CREATE TABLE achievements ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT UNIQUE NOT NULL, title TEXT NOT NULL, icon TEXT NOT NULL DEFAULT '🏆', category TEXT NOT NULL DEFAULT 'general', description TEXT ); CREATE TABLE admin_audit_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, admin_id INTEGER NOT NULL REFERENCES users(id), action TEXT NOT NULL, target TEXT, detail TEXT, ip TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE announcements ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE, author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, text TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE app_settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL DEFAULT '' ); CREATE TABLE "assignment_sessions" ( id INTEGER PRIMARY KEY AUTOINCREMENT, assignment_id INTEGER NOT NULL REFERENCES assignments(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, session_id INTEGER REFERENCES test_sessions(id) ON DELETE SET NULL, attempt_num INTEGER NOT NULL DEFAULT 1, first_seen_at TEXT ); CREATE TABLE assignment_templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, label TEXT NOT NULL, subject_slug TEXT NOT NULL, mode TEXT NOT NULL DEFAULT 'exam', count INTEGER NOT NULL DEFAULT 25, topic_id INTEGER REFERENCES topics(id) ON DELETE SET NULL, test_id INTEGER REFERENCES tests(id) ON DELETE SET NULL, file_id INTEGER REFERENCES files(id) ON DELETE SET NULL, is_homework INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE "assignments" ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER REFERENCES classes(id) ON DELETE CASCADE, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, title TEXT NOT NULL, subject_slug TEXT NOT NULL, mode TEXT NOT NULL DEFAULT 'exam', count INTEGER NOT NULL DEFAULT 25, topic_id INTEGER REFERENCES topics(id) ON DELETE SET NULL, deadline TEXT, created_by INTEGER NOT NULL REFERENCES users(id), test_id INTEGER REFERENCES tests(id) ON DELETE SET NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) , file_id INTEGER REFERENCES files(id) ON DELETE SET NULL, is_homework INTEGER NOT NULL DEFAULT 0, max_attempts INTEGER NOT NULL DEFAULT 0); CREATE TABLE avatar_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, filename TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', reviewer_id INTEGER REFERENCES users(id), reject_msg TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), reviewed_at TEXT ); CREATE TABLE bio_challenges ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT 'build', target_formula TEXT NOT NULL DEFAULT '', hint TEXT DEFAULT NULL, xp_reward INTEGER NOT NULL DEFAULT 50, difficulty INTEGER NOT NULL DEFAULT 1, topic_tag TEXT DEFAULT NULL, order_n INTEGER NOT NULL DEFAULT 0 , data_json TEXT DEFAULT NULL); CREATE TABLE bio_elements ( symbol TEXT PRIMARY KEY, name_ru TEXT NOT NULL, valency_max INTEGER NOT NULL DEFAULT 1, valency_opts TEXT NOT NULL DEFAULT '[1]', color TEXT NOT NULL DEFAULT '#888888', radius INTEGER NOT NULL DEFAULT 20, mass REAL NOT NULL DEFAULT 1.0 ); CREATE TABLE bio_molecules ( id INTEGER PRIMARY KEY AUTOINCREMENT, formula TEXT NOT NULL, name_ru TEXT NOT NULL, name_lat TEXT NOT NULL DEFAULT '', category TEXT NOT NULL DEFAULT 'inorganic', difficulty INTEGER NOT NULL DEFAULT 1, description TEXT NOT NULL DEFAULT '', atoms_json TEXT NOT NULL DEFAULT '[]', bonds_json TEXT NOT NULL DEFAULT '[]', is_library INTEGER NOT NULL DEFAULT 1, topic_tags TEXT NOT NULL DEFAULT '[]', created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE bio_reactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, equation TEXT NOT NULL, name_ru TEXT NOT NULL, type TEXT NOT NULL DEFAULT 'synthesis', description TEXT NOT NULL DEFAULT '', reactant_ids TEXT NOT NULL DEFAULT '[]', product_ids TEXT NOT NULL DEFAULT '[]', conditions TEXT DEFAULT NULL, energy_kj REAL DEFAULT NULL, topic_tags TEXT NOT NULL DEFAULT '[]' ); CREATE TABLE bio_user_challenges ( user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, challenge_id INTEGER NOT NULL REFERENCES bio_challenges(id) ON DELETE CASCADE, completed_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (user_id, challenge_id) ); CREATE TABLE bio_user_molecules ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, molecule_id INTEGER REFERENCES bio_molecules(id), name TEXT DEFAULT NULL, formula TEXT NOT NULL, atoms_json TEXT NOT NULL, bonds_json TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE bookmarks ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, entity_type TEXT NOT NULL CHECK (entity_type IN ('lesson','course','file','question')), entity_id INTEGER NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (user_id, entity_type, entity_id) ); CREATE TABLE challenges ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, week TEXT NOT NULL, title TEXT NOT NULL, description TEXT, type TEXT NOT NULL DEFAULT 'tests', target INTEGER NOT NULL DEFAULT 3, progress INTEGER NOT NULL DEFAULT 0, xp_reward INTEGER NOT NULL DEFAULT 100, subject_slug TEXT, topic_id INTEGER, completed INTEGER NOT NULL DEFAULT 0, claimed INTEGER NOT NULL DEFAULT 0, UNIQUE(user_id, week, title) ); CREATE TABLE class_courses ( class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE, course_id INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE, deadline TEXT, assigned_by INTEGER REFERENCES users(id) ON DELETE SET NULL, assigned_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (class_id, course_id) ); CREATE TABLE class_members ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, joined_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (class_id, user_id) ); CREATE TABLE classes ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, teacher_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, invite_code TEXT UNIQUE NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) , features TEXT, cover_emoji TEXT NOT NULL DEFAULT ''); CREATE TABLE classroom_attendance ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), joined_at TEXT NOT NULL DEFAULT (datetime('now')), left_at TEXT, UNIQUE(session_id, user_id) ); CREATE TABLE classroom_chat ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), message TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) , pinned INTEGER NOT NULL DEFAULT 0, attachment_url TEXT, attachment_type TEXT); CREATE TABLE classroom_chat_reactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id INTEGER NOT NULL REFERENCES classroom_chat(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), reaction TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(chat_id, user_id, reaction) ); CREATE TABLE classroom_draw_permissions ( session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), PRIMARY KEY (session_id, user_id) ); CREATE TABLE classroom_hands ( session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), PRIMARY KEY (session_id, user_id) ); CREATE TABLE classroom_invites ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), UNIQUE(session_id, user_id) ); CREATE TABLE classroom_notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), content TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(session_id, user_id) ); CREATE TABLE classroom_pages ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, page_num INTEGER NOT NULL DEFAULT 1, bg_color TEXT NOT NULL DEFAULT '#ffffff', template TEXT NOT NULL DEFAULT 'blank', name TEXT, UNIQUE(session_id, page_num) ); CREATE TABLE classroom_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER REFERENCES classes(id) ON DELETE CASCADE, teacher_id INTEGER NOT NULL REFERENCES users(id), title TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'active', current_page INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT (datetime('now')), ended_at TEXT , board_theme TEXT NOT NULL DEFAULT 'chalkboard'); CREATE TABLE classroom_strokes ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE, page_num INTEGER NOT NULL DEFAULT 1, user_id INTEGER NOT NULL REFERENCES users(id), tool TEXT NOT NULL DEFAULT 'pencil', data TEXT NOT NULL, seq INTEGER NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE classroom_templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, teacher_id INTEGER NOT NULL REFERENCES users(id), title TEXT NOT NULL, description TEXT DEFAULT '', pages_data TEXT NOT NULL DEFAULT '[]', created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE course_sections ( id INTEGER PRIMARY KEY AUTOINCREMENT, course_id INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE, title TEXT NOT NULL, order_index INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE course_templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, category TEXT NOT NULL DEFAULT 'general', subject_slug TEXT, structure TEXT NOT NULL DEFAULT '{}', is_public INTEGER NOT NULL DEFAULT 0, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE courses ( id INTEGER PRIMARY KEY AUTOINCREMENT, subject_slug TEXT NOT NULL, title TEXT NOT NULL, description TEXT, cover_emoji TEXT NOT NULL DEFAULT '📚', order_index INTEGER NOT NULL DEFAULT 0, is_published INTEGER NOT NULL DEFAULT 0, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE daily_goals ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, date TEXT NOT NULL, tests_target INTEGER NOT NULL DEFAULT 3, tests_done INTEGER NOT NULL DEFAULT 0, xp_target INTEGER NOT NULL DEFAULT 200, xp_earned INTEGER NOT NULL DEFAULT 0, UNIQUE (user_id, date) ); CREATE TABLE error_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, level TEXT NOT NULL DEFAULT 'error', message TEXT NOT NULL, stack TEXT, route TEXT, method TEXT, user_id INTEGER, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE file_access ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('class', 'user')), target_id INTEGER NOT NULL, UNIQUE (file_id, type, target_id) ); CREATE TABLE files ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, original_name TEXT NOT NULL, stored_name TEXT NOT NULL UNIQUE, mimetype TEXT, size INTEGER, subject_slug TEXT, is_public INTEGER NOT NULL DEFAULT 1, uploaded_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) , folder_id INTEGER); CREATE TABLE flashcard_cards ( id INTEGER PRIMARY KEY AUTOINCREMENT, deck_id INTEGER NOT NULL REFERENCES flashcard_decks(id) ON DELETE CASCADE, front TEXT NOT NULL DEFAULT '', back TEXT NOT NULL DEFAULT '', order_idx INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE flashcard_decks ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', color TEXT NOT NULL DEFAULT '#9B5DE5', created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE flashcard_reviews ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, card_id INTEGER NOT NULL REFERENCES flashcard_cards(id) ON DELETE CASCADE, ease_factor REAL NOT NULL DEFAULT 2.5, interval_days INTEGER NOT NULL DEFAULT 1, repetitions INTEGER NOT NULL DEFAULT 0, due_at TEXT NOT NULL DEFAULT (datetime('now')), last_reviewed TEXT, UNIQUE(user_id, card_id) ); CREATE TABLE folder_access ( id INTEGER PRIMARY KEY AUTOINCREMENT, folder_id INTEGER NOT NULL REFERENCES folders(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('class', 'user')), target_id INTEGER NOT NULL, UNIQUE (folder_id, type, target_id) ); CREATE TABLE folders ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE geometry_submissions ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL REFERENCES geometry_tasks(id) ON DELETE CASCADE, student_id INTEGER NOT NULL REFERENCES users(id), state_json TEXT NOT NULL DEFAULT '{}', score REAL DEFAULT NULL, feedback TEXT DEFAULT '', submitted_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(task_id, student_id) ); CREATE TABLE geometry_tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, teacher_id INTEGER NOT NULL REFERENCES users(id), class_id INTEGER REFERENCES classes(id) ON DELETE SET NULL, title TEXT NOT NULL DEFAULT 'Без названия', description TEXT DEFAULT '', state_json TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE "lesson_blocks" ( id INTEGER PRIMARY KEY AUTOINCREMENT, lesson_id INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE, type TEXT NOT NULL DEFAULT 'text' CHECK (type IN ('heading','text','formula','image','quiz','sim', 'table','code','divider','callout','video','flashcard', 'matching','fill-blank','ordering', 'accordion','timeline','diagram','geogebra','audio','columns','alert')), order_index INTEGER NOT NULL DEFAULT 0, data TEXT NOT NULL DEFAULT '{}' ); CREATE TABLE lesson_comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, lesson_id INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, parent_id INTEGER REFERENCES lesson_comments(id) ON DELETE CASCADE, text TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE lesson_notes ( user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, lesson_id INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE, text TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (user_id, lesson_id) ); CREATE TABLE lesson_progress ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, lesson_id INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE, completed INTEGER NOT NULL DEFAULT 0, updated_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (user_id, lesson_id) ); CREATE TABLE lesson_templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, category TEXT NOT NULL DEFAULT 'general', subject_slug TEXT, blocks TEXT NOT NULL DEFAULT '[]', is_public INTEGER NOT NULL DEFAULT 0, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE lessons ( id INTEGER PRIMARY KEY AUTOINCREMENT, course_id INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE, title TEXT NOT NULL, order_index INTEGER NOT NULL DEFAULT 0, is_published INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) , section_id INTEGER REFERENCES course_sections(id) ON DELETE SET NULL, read_time INTEGER NOT NULL DEFAULT 0); CREATE TABLE "live_answers" ( id INTEGER PRIMARY KEY AUTOINCREMENT, live_session_id INTEGER NOT NULL REFERENCES live_sessions(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), question_id INTEGER REFERENCES questions(id) ON DELETE SET NULL, option_id INTEGER REFERENCES options(id), answer_text TEXT, is_correct INTEGER, answered_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(live_session_id, user_id, question_id) ); CREATE TABLE live_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE, teacher_id INTEGER NOT NULL REFERENCES users(id), question_id INTEGER REFERENCES questions(id), status TEXT NOT NULL DEFAULT 'waiting', show_results INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')), ended_at TEXT ); CREATE TABLE notifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, type TEXT NOT NULL DEFAULT 'info', message TEXT NOT NULL, link TEXT, is_read INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE options ( id INTEGER PRIMARY KEY AUTOINCREMENT, question_id INTEGER NOT NULL REFERENCES questions(id) ON DELETE CASCADE, text TEXT NOT NULL, is_correct INTEGER NOT NULL DEFAULT 0, order_index INTEGER NOT NULL DEFAULT 0 , match_pair TEXT); CREATE TABLE parent_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, token TEXT UNIQUE NOT NULL, label TEXT NOT NULL DEFAULT '', is_active INTEGER NOT NULL DEFAULT 1, last_used TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), expires_at TEXT ); CREATE TABLE parent_notifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, parent_link_id INTEGER NOT NULL REFERENCES parent_links(id) ON DELETE CASCADE, type TEXT NOT NULL DEFAULT 'info', message TEXT NOT NULL, is_read INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE questions ( id INTEGER PRIMARY KEY AUTOINCREMENT, subject_id INTEGER NOT NULL REFERENCES subjects(id) ON DELETE CASCADE, topic_id INTEGER REFERENCES topics(id) ON DELETE SET NULL, text TEXT NOT NULL, difficulty INTEGER NOT NULL DEFAULT 1 CHECK (difficulty BETWEEN 1 AND 3), year INTEGER, explanation TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')) , type TEXT NOT NULL DEFAULT 'single', correct_text TEXT, image TEXT, source_type TEXT NOT NULL DEFAULT 'базовый'); CREATE TABLE rb_food_web ( predator_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, prey_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, strength REAL NOT NULL DEFAULT 0.5, PRIMARY KEY (predator_id, prey_id) ); CREATE TABLE rb_groups ( id INTEGER PRIMARY KEY AUTOINCREMENT, name_ru TEXT NOT NULL, name_lat TEXT NOT NULL DEFAULT '', icon TEXT NOT NULL DEFAULT '🌿', color TEXT NOT NULL DEFAULT '#16a34a' ); CREATE TABLE rb_habitats ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, type TEXT NOT NULL DEFAULT 'forest', description TEXT NOT NULL DEFAULT '', sound_file TEXT NOT NULL DEFAULT '' ); CREATE TABLE rb_population_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, species_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, year INTEGER NOT NULL, count_estimate INTEGER NOT NULL DEFAULT 0, source TEXT NOT NULL DEFAULT '' ); CREATE TABLE rb_quests ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', species_ids TEXT NOT NULL DEFAULT '[]', xp_reward INTEGER NOT NULL DEFAULT 150, badge_slug TEXT NOT NULL DEFAULT '' ); CREATE TABLE rb_sightings ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, species_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, region_code TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', photo_url TEXT NOT NULL DEFAULT '', confirmed_by_teacher INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE rb_species ( id INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER NOT NULL REFERENCES rb_groups(id), habitat_id INTEGER REFERENCES rb_habitats(id), name_ru TEXT NOT NULL, name_be TEXT NOT NULL DEFAULT '', name_lat TEXT NOT NULL DEFAULT '', category TEXT NOT NULL DEFAULT 'VU' CHECK (category IN ('CR','EN','VU','NT','LC')), by_category TEXT NOT NULL DEFAULT 'III', description TEXT NOT NULL DEFAULT '', interesting_fact TEXT NOT NULL DEFAULT '', threats TEXT NOT NULL DEFAULT '[]', conservation TEXT NOT NULL DEFAULT '', where_to_see TEXT NOT NULL DEFAULT '', photo_url TEXT NOT NULL DEFAULT '', model_type TEXT NOT NULL DEFAULT 'silhouette' CHECK (model_type IN ('procedural','silhouette','none')), population_trend TEXT NOT NULL DEFAULT '[]', biomass_kg REAL NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) , season_active TEXT NOT NULL DEFAULT '', name_be_short TEXT NOT NULL DEFAULT ''); CREATE TABLE rb_species_regions ( species_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, region_code TEXT NOT NULL CHECK (region_code IN ('brest','vitebsk','gomel','grodno','minsk','mogilev')), PRIMARY KEY (species_id, region_code) ); CREATE TABLE rb_user_collection ( user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, species_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE, unlock_method TEXT NOT NULL DEFAULT 'explore', notes TEXT NOT NULL DEFAULT '', unlocked_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (user_id, species_id) ); CREATE TABLE rb_user_quests ( user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, quest_id INTEGER NOT NULL REFERENCES rb_quests(id) ON DELETE CASCADE, status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','completed')), progress TEXT NOT NULL DEFAULT '{}', completed_at TEXT, PRIMARY KEY (user_id, quest_id) ); CREATE TABLE "role_permissions" ( id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT NOT NULL CHECK (role IN ('teacher', 'student', 'free_student')), permission TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 0, UNIQUE (role, permission) ); CREATE TABLE session_questions ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE, question_id INTEGER NOT NULL REFERENCES questions(id), order_index INTEGER NOT NULL ); CREATE TABLE shop_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, type TEXT NOT NULL DEFAULT 'frame' CHECK (type IN ('frame','theme','title','effect')), category TEXT NOT NULL DEFAULT 'cosmetic', price INTEGER NOT NULL DEFAULT 100, data TEXT NOT NULL DEFAULT '{}', icon TEXT NOT NULL DEFAULT 'star', is_active INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE subjects ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT UNIQUE NOT NULL, name TEXT NOT NULL, icon TEXT , default_mode TEXT NOT NULL DEFAULT 'exam', default_count INTEGER NOT NULL DEFAULT 25, default_test_id INTEGER REFERENCES tests(id) ON DELETE SET NULL); CREATE TABLE submission_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, submission_id INTEGER NOT NULL, class_id INTEGER, assignment_id INTEGER, student_id INTEGER NOT NULL, student_name TEXT, original_name TEXT, status TEXT, grade INTEGER, teacher_note TEXT, submitted_at TEXT, action TEXT NOT NULL DEFAULT 'deleted', deleted_by INTEGER NOT NULL, deleted_by_role TEXT, deleted_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE "submissions" ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE, assignment_id INTEGER REFERENCES assignments(id) ON DELETE SET NULL, student_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, original_name TEXT NOT NULL, stored_name TEXT NOT NULL UNIQUE, mimetype TEXT, size INTEGER, message TEXT, status TEXT NOT NULL DEFAULT 'new' CHECK (status IN ('new','reviewed','revision','resubmitted','accepted')), teacher_note TEXT, grade INTEGER, reviewed_at TEXT, submitted_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE test_questions ( test_id INTEGER NOT NULL REFERENCES tests(id) ON DELETE CASCADE, question_id INTEGER NOT NULL REFERENCES questions(id) ON DELETE CASCADE, order_index INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (test_id, question_id) ); CREATE TABLE test_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, subject_id INTEGER REFERENCES subjects(id) ON DELETE SET NULL, mode TEXT NOT NULL DEFAULT 'exam' CHECK (mode IN ('exam', 'practice', 'topic', 'random')), total INTEGER NOT NULL, score INTEGER, status TEXT NOT NULL DEFAULT 'in_progress' CHECK (status IN ('in_progress', 'completed', 'abandoned')), started_at TEXT NOT NULL DEFAULT (datetime('now')), finished_at TEXT ); CREATE TABLE tests ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, subject_slug TEXT NOT NULL, description TEXT, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) , show_answers INTEGER NOT NULL DEFAULT 1, time_limit INTEGER); CREATE TABLE topics ( id INTEGER PRIMARY KEY AUTOINCREMENT, subject_id INTEGER NOT NULL REFERENCES subjects(id) ON DELETE CASCADE, name TEXT NOT NULL, order_index INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE user_achievements ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, achievement_id INTEGER NOT NULL REFERENCES achievements(id) ON DELETE CASCADE, unlocked_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (user_id, achievement_id) ); CREATE TABLE user_answers ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE, question_id INTEGER NOT NULL REFERENCES questions(id), chosen_option_id INTEGER REFERENCES options(id), is_correct INTEGER, time_spent_sec INTEGER, answered_at TEXT NOT NULL DEFAULT (datetime('now')), answer_text TEXT, UNIQUE (session_id, question_id) ); CREATE TABLE user_permissions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, permission TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 0, UNIQUE (user_id, permission) ); CREATE TABLE user_preferences ( user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, data TEXT NOT NULL DEFAULT '{}', updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE user_purchases ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, item_id INTEGER NOT NULL REFERENCES shop_items(id) ON DELETE CASCADE, purchased_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(user_id, item_id) ); CREATE TABLE "users" ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, name TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'student' CHECK (role IN ('student','teacher','admin','free_student')), created_at TEXT NOT NULL DEFAULT (datetime('now')), last_login TEXT, xp INTEGER NOT NULL DEFAULT 0, level INTEGER NOT NULL DEFAULT 1, streak_current INTEGER NOT NULL DEFAULT 0, streak_best INTEGER NOT NULL DEFAULT 0, streak_date TEXT, goal_tier TEXT DEFAULT 'medium', avatar_frame TEXT DEFAULT 'default', coins INTEGER NOT NULL DEFAULT 0, active_title TEXT DEFAULT NULL, active_theme TEXT DEFAULT NULL, active_effect TEXT DEFAULT NULL, token_version INTEGER NOT NULL DEFAULT 0, lab_experiments INTEGER NOT NULL DEFAULT 0, lab_reactions INTEGER NOT NULL DEFAULT 0, is_banned INTEGER NOT NULL DEFAULT 0 , pet_name TEXT, pet_color TEXT DEFAULT 'purple', pet_last_petted TEXT, pet_petting_streak INT DEFAULT 0, pet_last_star TEXT, pet_bg TEXT DEFAULT 'default', pet_bg_owned TEXT DEFAULT '[]', pet_last_fed TEXT, avatar_url TEXT DEFAULT NULL); CREATE TABLE xp_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, amount INTEGER NOT NULL, reason TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE INDEX idx_announcements_class ON announcements(class_id); CREATE INDEX idx_answers_session ON user_answers(session_id); CREATE INDEX idx_answers_sq ON user_answers(session_id, question_id); CREATE INDEX idx_assign_sess_assign ON assignment_sessions(assignment_id); CREATE INDEX idx_assign_sess_user ON assignment_sessions(user_id); CREATE INDEX idx_assignments_class ON assignments(class_id); CREATE INDEX idx_assignments_deadline ON assignments(deadline); CREATE INDEX idx_assignments_user ON assignments(user_id); CREATE INDEX idx_audit_log_admin ON admin_audit_log(admin_id); CREATE INDEX idx_audit_log_date ON admin_audit_log(created_at DESC); CREATE INDEX idx_avatar_req_status ON avatar_requests(status); CREATE INDEX idx_avatar_req_user ON avatar_requests(user_id); CREATE INDEX idx_bio_mol_cat ON bio_molecules(category); CREATE INDEX idx_bio_mol_formula ON bio_molecules(formula); CREATE INDEX idx_bio_user_chal ON bio_user_challenges(user_id); CREATE INDEX idx_bio_user_mol ON bio_user_molecules(user_id); CREATE INDEX idx_blocks_lesson ON lesson_blocks(lesson_id); CREATE INDEX idx_bookmarks_user ON bookmarks(user_id); CREATE INDEX idx_cc_class ON class_courses(class_id); CREATE INDEX idx_cc_course ON class_courses(course_id); CREATE INDEX idx_challenges_user_week ON challenges(user_id, week); CREATE INDEX idx_class_members_class ON class_members(class_id); CREATE INDEX idx_class_members_user ON class_members(user_id); CREATE INDEX idx_courses_creator ON courses(created_by); CREATE INDEX idx_courses_subject ON courses(subject_slug); CREATE INDEX idx_cr_chat ON classroom_chat(session_id); CREATE INDEX idx_cr_reactions ON classroom_chat_reactions(chat_id); CREATE INDEX idx_cr_sessions_class ON classroom_sessions(class_id, status); CREATE INDEX idx_cr_strokes ON classroom_strokes(session_id, page_num, seq); CREATE INDEX idx_ctpl_creator ON course_templates(created_by); CREATE INDEX idx_ctpl_public ON course_templates(is_public); CREATE INDEX idx_daily_goals_user ON daily_goals(user_id, date); CREATE INDEX idx_error_log_date ON error_log(created_at DESC); CREATE INDEX idx_file_access_file ON file_access(file_id); CREATE INDEX idx_files_subject ON files(subject_slug); CREATE INDEX idx_files_uploader ON files(uploaded_by); CREATE INDEX idx_folder_access_folder ON folder_access(folder_id); CREATE INDEX idx_geo_subs_student ON geometry_submissions(student_id); CREATE INDEX idx_geo_subs_task ON geometry_submissions(task_id); CREATE INDEX idx_geo_tasks_teacher ON geometry_tasks(teacher_id); CREATE INDEX idx_lcomments_lesson ON lesson_comments(lesson_id); CREATE INDEX idx_lcomments_parent ON lesson_comments(parent_id); CREATE INDEX idx_lcomments_user ON lesson_comments(user_id); CREATE INDEX idx_lessons_course ON lessons(course_id); CREATE INDEX idx_live_answers_question ON live_answers(live_session_id, question_id); CREATE INDEX idx_live_answers_session ON live_answers(live_session_id); CREATE INDEX idx_live_sessions_class ON live_sessions(class_id, status); CREATE INDEX idx_lprogress_lesson ON lesson_progress(lesson_id); CREATE INDEX idx_lprogress_user ON lesson_progress(user_id); CREATE INDEX idx_ltpl_creator ON lesson_templates(created_by); CREATE INDEX idx_ltpl_public ON lesson_templates(is_public); CREATE INDEX idx_notes_lesson ON lesson_notes(lesson_id); CREATE INDEX idx_notes_user ON lesson_notes(user_id); CREATE INDEX idx_notifications_user ON notifications(user_id, is_read); CREATE INDEX idx_parent_links_student ON parent_links(student_id); CREATE INDEX idx_parent_links_token ON parent_links(token); CREATE INDEX idx_parent_notif_link ON parent_notifications(parent_link_id, is_read); CREATE INDEX idx_parent_notif_link_date ON parent_notifications(parent_link_id, created_at DESC); CREATE INDEX idx_purchases_user ON user_purchases(user_id); CREATE INDEX idx_questions_source ON questions(source_type); CREATE INDEX idx_questions_subject ON questions(subject_id); CREATE INDEX idx_questions_topic ON questions(topic_id); CREATE INDEX idx_rb_collection_user ON rb_user_collection(user_id); CREATE INDEX idx_rb_popdata_species ON rb_population_data(species_id); CREATE INDEX idx_rb_sightings_user ON rb_sightings(user_id); CREATE INDEX idx_rb_species_category ON rb_species(category); CREATE INDEX idx_rb_species_group ON rb_species(group_id); CREATE INDEX idx_sections_course ON course_sections(course_id); CREATE INDEX idx_sessions_user ON test_sessions(user_id); CREATE INDEX idx_sessions_user_status ON test_sessions(user_id, status); CREATE INDEX idx_sessions_user_status_date ON test_sessions(user_id, status, started_at DESC); CREATE INDEX idx_sq_session ON session_questions(session_id); CREATE INDEX idx_submissions_assignment ON submissions(assignment_id); CREATE INDEX idx_submissions_class ON submissions(class_id); CREATE INDEX idx_submissions_student ON submissions(student_id); CREATE INDEX idx_test_sessions_status ON test_sessions(status); CREATE INDEX idx_test_sessions_user_status ON test_sessions(user_id, status); CREATE UNIQUE INDEX idx_topics_uniq ON topics(subject_id, name); CREATE INDEX idx_tpl_creator ON assignment_templates(created_by); CREATE INDEX idx_user_achievements_user ON user_achievements(user_id); CREATE INDEX idx_user_permissions_user ON user_permissions(user_id); CREATE INDEX idx_xp_log_date ON xp_log(created_at); CREATE INDEX idx_xp_log_user ON xp_log(user_id); CREATE INDEX idx_xp_log_user_created ON xp_log(user_id, created_at);