zee-solution/docs/schema.md

7.2 KiB

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
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
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
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
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
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
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

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

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

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)

-- 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