244 lines
7.2 KiB
Markdown
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* |