LearnSpace: full-stack educational whiteboard platform
Node.js/Express backend + vanilla JS frontend. Features: real-time collaborative whiteboard (SSE), multi-page support, LaTeX formulas, shapes/connectors, coordinate systems, number lines, compass, zoom/pan, Catmull-Rom pencil smoothing, ruler/protractor with rotation & resize controls, minimap navigation overlay, auto-measurements, multi-page thumbnails sidebar, PNG export, page templates. Student/teacher workflows: classes, assignments, library, dashboard. Mobile responsive. SQLite (better-sqlite3). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
-- =============================================
|
||||
-- LearnSpace — Initial schema
|
||||
-- =============================================
|
||||
|
||||
-- Расширения
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- ── Пользователи ──────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'student'
|
||||
CHECK (role IN ('student', 'teacher', 'admin')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_login TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- ── Предметы ──────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS subjects (
|
||||
id SERIAL PRIMARY KEY,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
icon VARCHAR(10)
|
||||
);
|
||||
|
||||
INSERT INTO subjects (slug, name, icon) VALUES
|
||||
('bio', 'Биология', 'dna'),
|
||||
('chem', 'Химия', 'atom'),
|
||||
('math', 'Математика', 'compass'),
|
||||
('phys', 'Физика', 'zap')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ── Темы ──────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS topics (
|
||||
id SERIAL PRIMARY KEY,
|
||||
subject_id INT NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
order_index INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- ── Банк вопросов ─────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS questions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
subject_id INT NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
|
||||
topic_id INT REFERENCES topics(id) ON DELETE SET NULL,
|
||||
text TEXT NOT NULL,
|
||||
difficulty SMALLINT NOT NULL DEFAULT 1 CHECK (difficulty BETWEEN 1 AND 3),
|
||||
year SMALLINT,
|
||||
explanation TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ── Варианты ответов ──────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS options (
|
||||
id SERIAL PRIMARY KEY,
|
||||
question_id INT NOT NULL REFERENCES questions(id) ON DELETE CASCADE,
|
||||
text TEXT NOT NULL,
|
||||
is_correct BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
order_index SMALLINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- ── Сессии тестирования ───────────────────────
|
||||
CREATE TABLE IF NOT EXISTS test_sessions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
subject_id INT REFERENCES subjects(id) ON DELETE SET NULL,
|
||||
mode VARCHAR(20) NOT NULL DEFAULT 'exam'
|
||||
CHECK (mode IN ('exam', 'practice', 'topic', 'random')),
|
||||
total INT NOT NULL,
|
||||
score INT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'in_progress'
|
||||
CHECK (status IN ('in_progress', 'completed', 'abandoned')),
|
||||
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
finished_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- ── Вопросы сессии ────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS session_questions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id INT NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE,
|
||||
question_id INT NOT NULL REFERENCES questions(id),
|
||||
order_index INT NOT NULL
|
||||
);
|
||||
|
||||
-- ── Ответы пользователя ───────────────────────
|
||||
CREATE TABLE IF NOT EXISTS user_answers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id INT NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE,
|
||||
question_id INT NOT NULL REFERENCES questions(id),
|
||||
chosen_option_id INT REFERENCES options(id),
|
||||
is_correct BOOLEAN,
|
||||
time_spent_sec SMALLINT,
|
||||
answered_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ── Индексы ───────────────────────────────────
|
||||
CREATE INDEX IF NOT EXISTS idx_questions_subject ON questions(subject_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_questions_topic ON questions(topic_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_user ON test_sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_answers_session ON user_answers(session_id);
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Уникальный индекс для upsert ответов
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_answers_session_question
|
||||
ON user_answers (session_id, question_id);
|
||||
Reference in New Issue
Block a user