Home / Wiki / Database System

Database System

Database System

Overview

The database system uses PostgreSQL as the primary database with SQLAlchemy ORM for database operations. It includes migrations via Flask-Migrate and supports all forum data including users, posts, comments, votes, and more.

Database Configuration

Environment Variables

  • DATABASE_URL: PostgreSQL connection string
  • Format: postgresql://user:password@host:port/database
  • Example: postgresql://forumuser:password@localhost:5432/forumdb
  • SQLAlchemy Configuration

    python
    app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    

    Database Schema

    Core Tables

    Users Table

    sql
    CREATE TABLE users (
        id SERIAL PRIMARY KEY,
        username VARCHAR(64) UNIQUE NOT NULL,
        email VARCHAR(120) UNIQUE NOT NULL,
        password_hash VARCHAR(256) NOT NULL,
        is_admin BOOLEAN DEFAULT FALSE,
        is_verified BOOLEAN DEFAULT FALSE,
        verification_token VARCHAR(256),
        reset_token VARCHAR(256),
        reset_token_expiration TIMESTAMP,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_email ON users(email);

    Repositories Table

    sql
    CREATE TABLE repositories (
        id SERIAL PRIMARY KEY,
        name VARCHAR(128) NOT NULL,
        description TEXT,
        github_url VARCHAR(256) UNIQUE NOT NULL,
        stars INTEGER DEFAULT 0,
        language VARCHAR(64),
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX idx_repositories_github_url ON repositories(github_url);

    Categories Table

    sql
    CREATE TABLE categories (
        id SERIAL PRIMARY KEY,
        name VARCHAR(64) UNIQUE NOT NULL,
        description TEXT,
        color VARCHAR(7) DEFAULT '#00f5ff'
    );
    

    Posts Table

    sql
    CREATE TABLE posts (
        id SERIAL PRIMARY KEY,
        title VARCHAR(256) NOT NULL,
        content TEXT NOT NULL,
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        repository_id INTEGER REFERENCES repositories(id) ON DELETE SET NULL,
        category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
        attachment VARCHAR(256),
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        upvotes INTEGER DEFAULT 0,
        downvotes INTEGER DEFAULT 0
    );

    CREATE INDEX idx_posts_user_id ON posts(user_id); CREATE INDEX idx_posts_created_at ON posts(created_at DESC); CREATE INDEX idx_posts_category_id ON posts(category_id);

    Comments Table

    sql
    CREATE TABLE comments (
        id SERIAL PRIMARY KEY,
        content TEXT NOT NULL,
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        upvotes INTEGER DEFAULT 0,
        downvotes INTEGER DEFAULT 0
    );

    CREATE INDEX idx_comments_post_id ON comments(post_id); CREATE INDEX idx_comments_created_at ON comments(created_at DESC);

    Votes Table

    sql
    CREATE TABLE votes (
        id SERIAL PRIMARY KEY,
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
        comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE,
        value INTEGER NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        CHECK (value IN (1, -1))
    );

    CREATE UNIQUE INDEX idx_votes_user_post ON votes(user_id, post_id) WHERE post_id IS NOT NULL; CREATE UNIQUE INDEX idx_votes_user_comment ON votes(user_id, comment_id) WHERE comment_id IS NOT NULL;

    Notifications Table

    sql
    CREATE TABLE notifications (
        id SERIAL PRIMARY KEY,
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        content TEXT NOT NULL,
        link VARCHAR(256),
        is_read BOOLEAN DEFAULT FALSE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX idx_notifications_user_id ON notifications(user_id); CREATE INDEX idx_notifications_is_read ON notifications(is_read);

    Messages Table

    sql
    CREATE TABLE messages (
        id SERIAL PRIMARY KEY,
        sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        receiver_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        content TEXT NOT NULL,
        is_read BOOLEAN DEFAULT FALSE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX idx_messages_sender_id ON messages(sender_id); CREATE INDEX idx_messages_receiver_id ON messages(receiver_id); CREATE INDEX idx_messages_is_read ON messages(is_read);

    Bookmarks Table

    sql
    CREATE TABLE bookmarks (
        id SERIAL PRIMARY KEY,
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        UNIQUE (user_id, post_id)
    );

    CREATE INDEX idx_bookmarks_user_id ON bookmarks(user_id);

    Badges Table

    sql
    CREATE TABLE badges (
        id SERIAL PRIMARY KEY,
        name VARCHAR(64) UNIQUE NOT NULL,
        description TEXT,
        icon VARCHAR(32) DEFAULT '★',
        color VARCHAR(7) DEFAULT '#ff00ff'
    );
    

    User_Badges Association Table

    sql
    CREATE TABLE user_badges (
        user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        badge_id INTEGER NOT NULL REFERENCES badges(id) ON DELETE CASCADE,
        PRIMARY KEY (user_id, badge_id)
    );
    

    Relationships

    One-to-Many Relationships

  • User → Posts
  • User → Comments
  • User → Notifications
  • User → Sent Messages
  • User → Received Messages
  • User → Bookmarks
  • Repository → Posts
  • Category → Posts
  • Post → Comments
  • Many-to-Many Relationships

  • User ↔ Badges (via user_badges)
  • One-to-One Relationships

  • None currently
  • Migrations

    Flask-Migrate

  • Database schema versioning
  • Automatic migration generation
  • Upgrade/downgrade support
  • Migration history tracking
  • Migration Commands

    bash
    

    Generate migration

    flask db migrate -m "description"

    Apply migrations

    flask db upgrade

    Rollback migration

    flask db downgrade

    View migration history

    flask db history

    Initial Migration

  • Creates all tables
  • Creates indexes
  • Creates constraints
  • Sets up relationships
  • Database Initialization

    init_db.py Script

    python
    

    Creates admin user

    Creates default categories

    Initializes database

    Run after first migration

    Running Initialization

    bash
    python init_db.py
    

    Database Operations

    Query Examples

    Get User by Username

    python
    user = User.query.filter_by(username='username').first()
    

    Get Posts with Category

    python
    posts = Post.query.filter_by(category_id=category_id).all()
    

    Get Unread Notifications

    python
    notifications = Notification.query.filter_by(user_id=user.id, is_read=False).all()
    

    Search Posts

    python
    posts = Post.query.filter(
        (Post.title.ilike(f'%{query}%')) | 
        (Post.content.ilike(f'%{query}%'))
    ).all()
    

    Performance Optimization

    Indexes

  • Username index
  • Email index
  • User foreign key indexes
  • Created_at indexes for sorting
  • Category index
  • Unique constraints for votes and bookmarks
  • Query Optimization

  • Lazy loading for relationships
  • Eager loading when needed
  • Query filtering
  • Pagination (future)
  • Query result caching (future)
  • Connection Pooling

  • SQLAlchemy connection pooling
  • Configurable pool size
  • Automatic connection management
  • Connection reuse
  • Database Backup

    Backup Strategies

  • PostgreSQL pg_dump
  • Scheduled backups
  • Off-site storage
  • Point-in-time recovery
  • Backup Commands

    bash
    

    Full backup

    pg_dump -U username -d forumdb > backup.sql

    Restore

    psql -U username -d forumdb < backup.sql

    Database Security

    Access Control

  • Database user with limited privileges
  • No direct web access to database
  • Connection string in environment variables
  • SSL/TLS for database connections
  • Data Protection

  • Passwords hashed before storage
  • No plain text passwords
  • Sensitive data in environment variables
  • Regular security audits
  • Database Maintenance

    Regular Tasks

  • Vacuum and analyze tables
  • Reindex indexes
  • Update statistics
  • Monitor disk space
  • Check for bloat
  • Maintenance Commands

    bash
    

    Vacuum and analyze

    VACUUM ANALYZE;

    Reindex

    REINDEX DATABASE forumdb;

    Update statistics

    ANALYZE;

    Database Monitoring

    Metrics to Monitor

  • Connection pool usage
  • Query performance
  • Table sizes
  • Index usage
  • Disk space
  • Slow queries
  • Monitoring Tools

  • PostgreSQL logs
  • Query performance logs
  • Connection pool logs
  • External monitoring (future)
  • Future Enhancements

    Database Features

  • Read replicas for scaling
  • Partitioning for large tables
  • Full-text search (PostgreSQL)
  • JSONB fields for flexible data
  • Materialized views for common queries
  • Database triggers for automation
  • Stored procedures for complex operations
  • Data Integrity

  • Foreign key constraints
  • Check constraints
  • Unique constraints
  • Not null constraints
  • Data validation at database level
  • Performance

  • Connection pooling optimization
  • Query result caching (Redis)
  • Database connection monitoring
  • Automatic failover
  • Load balancing