Repository navigation
Database System
AutoBot Solutions edited this page Apr 29, 2026
·
1 revision
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_URL: PostgreSQL connection string - Format:
postgresql://user:password@host:port/database - Example:
postgresql://forumuser:password@localhost:5432/forumdb
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = FalseCREATE 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);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);CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
description TEXT,
color VARCHAR(7) DEFAULT '#00f5ff'
);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);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);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;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);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);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);CREATE TABLE badges (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
description TEXT,
icon VARCHAR(32) DEFAULT '★',
color VARCHAR(7) DEFAULT '#ff00ff'
);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)
);- User → Posts
- User → Comments
- User → Notifications
- User → Sent Messages
- User → Received Messages
- User → Bookmarks
- Repository → Posts
- Category → Posts
- Post → Comments
- User ↔ Badges (via user_badges)
- None currently
- Database schema versioning
- Automatic migration generation
- Upgrade/downgrade support
- Migration history tracking
# Generate migration
flask db migrate -m "description"
# Apply migrations
flask db upgrade
# Rollback migration
flask db downgrade
# View migration history
flask db history- Creates all tables
- Creates indexes
- Creates constraints
- Sets up relationships
# Creates admin user
# Creates default categories
# Initializes database
# Run after first migrationpython init_db.pyGet User by Username
user = User.query.filter_by(username='username').first()Get Posts with Category
posts = Post.query.filter_by(category_id=category_id).all()Get Unread Notifications
notifications = Notification.query.filter_by(user_id=user.id, is_read=False).all()Search Posts
posts = Post.query.filter(
(Post.title.ilike(f'%{query}%')) |
(Post.content.ilike(f'%{query}%'))
).all()- Username index
- Email index
- User foreign key indexes
- Created_at indexes for sorting
- Category index
- Unique constraints for votes and bookmarks
- Lazy loading for relationships
- Eager loading when needed
- Query filtering
- Pagination (future)
- Query result caching (future)
- SQLAlchemy connection pooling
- Configurable pool size
- Automatic connection management
- Connection reuse
- PostgreSQL pg_dump
- Scheduled backups
- Off-site storage
- Point-in-time recovery
# Full backup
pg_dump -U username -d forumdb > backup.sql
# Restore
psql -U username -d forumdb < backup.sql- Database user with limited privileges
- No direct web access to database
- Connection string in environment variables
- SSL/TLS for database connections
- Passwords hashed before storage
- No plain text passwords
- Sensitive data in environment variables
- Regular security audits
- Vacuum and analyze tables
- Reindex indexes
- Update statistics
- Monitor disk space
- Check for bloat
# Vacuum and analyze
VACUUM ANALYZE;
# Reindex
REINDEX DATABASE forumdb;
# Update statistics
ANALYZE;- Connection pool usage
- Query performance
- Table sizes
- Index usage
- Disk space
- Slow queries
- PostgreSQL logs
- Query performance logs
- Connection pool logs
- External monitoring (future)
- 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
- Foreign key constraints
- Check constraints
- Unique constraints
- Not null constraints
- Data validation at database level
- Connection pooling optimization
- Query result caching (Redis)
- Database connection monitoring
- Automatic failover
- Load balancing