-- edu.senex.de Training Platform - Database Schema -- Run: docker exec -i postgres psql -U postgres -d edu < schema.sql -- Users CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, display_name VARCHAR(100) NOT NULL, is_admin BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT NOW() ); -- Flashcard Decks CREATE TABLE IF NOT EXISTS decks ( id SERIAL PRIMARY KEY, slug VARCHAR(100) UNIQUE NOT NULL, name VARCHAR(200) NOT NULL, description TEXT DEFAULT '', card_count INT DEFAULT 0, sort_order INT DEFAULT 0, source_file VARCHAR(200), updated_at TIMESTAMP DEFAULT NOW() ); -- Flashcards CREATE TABLE IF NOT EXISTS cards ( id SERIAL PRIMARY KEY, deck_id INT NOT NULL REFERENCES decks(id) ON DELETE CASCADE, question TEXT NOT NULL, answer TEXT NOT NULL, level VARCHAR(20) DEFAULT 'basis', sort_order INT DEFAULT 0, source_file VARCHAR(200), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_cards_deck ON cards(deck_id); -- SM-2 Spaced Repetition Progress CREATE TABLE IF NOT EXISTS card_progress ( id SERIAL PRIMARY KEY, user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, card_id INT NOT NULL REFERENCES cards(id) ON DELETE CASCADE, ease_factor REAL DEFAULT 2.5, interval_days INT DEFAULT 0, repetitions INT DEFAULT 0, next_review DATE DEFAULT CURRENT_DATE, last_rating VARCHAR(10), last_reviewed_at TIMESTAMP, UNIQUE(user_id, card_id) ); CREATE INDEX IF NOT EXISTS idx_card_progress_due ON card_progress(user_id, next_review); -- Tutorials CREATE TABLE IF NOT EXISTS tutorials ( id SERIAL PRIMARY KEY, slug VARCHAR(100) UNIQUE NOT NULL, title VARCHAR(200) NOT NULL, description TEXT DEFAULT '', content_md TEXT NOT NULL, duration_min INT, sort_order INT DEFAULT 0, source_file VARCHAR(200), updated_at TIMESTAMP DEFAULT NOW() ); -- Tutorial Progress CREATE TABLE IF NOT EXISTS tutorial_progress ( id SERIAL PRIMARY KEY, user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, tutorial_id INT NOT NULL REFERENCES tutorials(id) ON DELETE CASCADE, completed BOOLEAN DEFAULT false, completed_at TIMESTAMP, UNIQUE(user_id, tutorial_id) ); -- Cheat Sheets CREATE TABLE IF NOT EXISTS cheatsheets ( id SERIAL PRIMARY KEY, slug VARCHAR(100) UNIQUE NOT NULL, title VARCHAR(200) NOT NULL, category VARCHAR(100) DEFAULT '', content_md TEXT NOT NULL, source_file VARCHAR(200), updated_at TIMESTAMP DEFAULT NOW() ); -- Quiz Results CREATE TABLE IF NOT EXISTS quiz_results ( id SERIAL PRIMARY KEY, user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, deck_slug VARCHAR(100), quiz_type VARCHAR(50) DEFAULT 'multiple_choice', score_percent INT, total_questions INT, correct_answers INT, created_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_quiz_results_user ON quiz_results(user_id, created_at DESC);