zee-solution/docs/schema.md

244 lines
7.2 KiB
Markdown

# ZEE Quiz Application - Database Schema
app_ver: 1.0.0
doc_ver: A1
## Database Schema
### 1. Primary Database (PostgreSQL 14)
* **DB Type:** Relational
* **Technology:** PostgreSQL 14
* **Purpose:** Primary data store for all application data
* **Connection String:** `postgresql://user:password@host:5432/zee_quiz`
#### Tables
##### 1.1. users
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'user',
is_active BOOLEAN DEFAULT true,
last_login_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role ON users(role);
```
##### 1.2. profiles
```sql
CREATE TABLE profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
date_of_birth DATE NOT NULL,
gender VARCHAR(20) NOT NULL,
preferred_gender VARCHAR(20) NOT NULL,
phone_number VARCHAR(20),
facebook_link VARCHAR(255),
location VARCHAR(100),
team VARCHAR(50),
hobbies TEXT[],
things_not_tried TEXT,
hopes_for_partner TEXT,
dealbreakers TEXT,
message_to_partner TEXT,
zodiac_sign VARCHAR(20),
access_code VARCHAR(20) UNIQUE,
personal_link VARCHAR(255),
is_lucky_winner BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_profiles_user_id ON profiles(user_id);
CREATE INDEX idx_profiles_access_code ON profiles(access_code);
```
##### 1.3. photos
```sql
CREATE TABLE photos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
profile_id UUID REFERENCES profiles(id) ON DELETE CASCADE,
url VARCHAR(512) NOT NULL,
is_primary BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_photos_profile_id ON photos(profile_id);
```
##### 1.4. quizzes
```sql
CREATE TABLE quizzes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
description TEXT,
start_time TIMESTAMP WITH TIME ZONE NOT NULL,
end_time TIMESTAMP WITH TIME ZONE NOT NULL,
time_limit_seconds INT DEFAULT 300, -- 5 minutes
is_active BOOLEAN DEFAULT true,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_quizzes_active ON quizzes(is_active, start_time, end_time);
```
##### 1.5. questions
```sql
CREATE TABLE questions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
quiz_id UUID REFERENCES quizzes(id) ON DELETE CASCADE,
question_text TEXT NOT NULL,
question_type VARCHAR(50) NOT NULL, -- multiple_choice, true_false, short_answer
options JSONB,
correct_answer TEXT,
points INT DEFAULT 1,
display_order INT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_questions_quiz_id ON questions(quiz_id);
```
##### 1.6. user_answers
```sql
CREATE TABLE user_answers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
quiz_id UUID REFERENCES quizzes(id) ON DELETE CASCADE,
question_id UUID REFERENCES questions(id) ON DELETE CASCADE,
answer_text TEXT,
is_correct BOOLEAN,
points_earned INT DEFAULT 0,
time_taken_seconds INT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_user_answers_user_quiz ON user_answers(user_id, quiz_id);
CREATE INDEX idx_user_answers_question ON user_answers(question_id);
```
### 2. Cache (Redis 7)
* **DB Type:** Key-Value
* **Technology:** Redis 7
* **Purpose:** Caching, rate limiting, and session storage
* **Connection String:** `redis://:password@host:6379/0`
#### Key Patterns
- `user:sessions:{session_id}` - User session data
- `quiz:leaderboard:{quiz_id}` - Sorted set for quiz leaderboard
- `rate_limit:{ip_address}` - Rate limiting counters
- `user:profile:{user_id}` - Cached user profile data
- `quiz:active` - Set of active quiz IDs
### 3. File Storage (AWS S3)
* **DB Type:** Object Storage
* **Technology:** AWS S3
* **Purpose:** Storing user-uploaded files (profile photos, quiz images)
* **Bucket Name:** `zee-quiz-{environment}`
#### Directory Structure
```
zquiz/
├── profiles/
│ └── {user_id}/
│ ├── {photo_id}.jpg
│ └── {photo_id}_thumbnail.jpg
└── quizzes/
└── {quiz_id}/
└── {question_id}.{ext}
```
## Data Structures
### 1. User Session
```go
type UserSession struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Email string `json:"email"`
Role string `json:"role"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
LastActivity time.Time `json:"last_activity"`
ExpiresAt time.Time `json:"expires_at"`
}
```
### 2. Quiz Question
```go
type Question struct {
ID string `json:"id"`
QuizID string `json:"quiz_id"`
QuestionText string `json:"question_text"`
QuestionType string `json:"question_type"` // multiple_choice, true_false, short_answer
Options []string `json:"options,omitempty"`
CorrectAnswer string `json:"correct_answer,omitempty"`
Points int `json:"points"`
DisplayOrder int `json:"display_order"`
MediaURL string `json:"media_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
```
### 3. Quiz Result
```go
type QuizResult struct {
UserID string `json:"user_id"`
QuizID string `json:"quiz_id"`
TotalQuestions int `json:"total_questions"`
CorrectAnswers int `json:"correct_answers"`
TotalPoints int `json:"total_points"`
Score float64 `json:"score"` // Percentage
TimeCompleted time.Time `json:"time_completed"`
Rank int `json:"rank,omitempty"`
}
```
## Database Migrations
### Initial Migration (0001_initial.up.sql)
```sql
-- This file is auto-generated and managed by the golang-migrate tool
-- It contains all the initial table creation statements
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Create users table
-- (Include all table creation SQL from above)
```
## Performance Considerations
### Indexing Strategy
- All foreign keys are indexed
- Frequently queried columns have appropriate indexes
- Composite indexes for common query patterns
### Partitioning
- User answers table is partitioned by `quiz_id` for large-scale deployments
- Old quiz data can be archived to cold storage
### Caching Strategy
- User sessions and active quiz data are cached in Redis
- Leaderboards are maintained in Redis sorted sets
- Profile data is cached with TTL
---
*Document Version: A1*
*Last Updated: 2025-06-06*