feat: rebuild CSP practice workflow, UX and automation

这个提交包含在:
Codex CLI
2026-02-13 15:49:05 +08:00
父节点 d33deed4c5
当前提交 e2ab522b78
修改 105 个文件,包含 15669 行新增428 行删除

查看文件

@@ -24,7 +24,11 @@ CREATE TABLE IF NOT EXISTS problems (
title TEXT NOT NULL,
statement_md TEXT NOT NULL,
difficulty INTEGER NOT NULL DEFAULT 1,
source TEXT NOT NULL DEFAULT "",
source TEXT NOT NULL DEFAULT '',
statement_url TEXT NOT NULL DEFAULT '',
llm_profile_json TEXT NOT NULL DEFAULT '{}',
sample_input TEXT NOT NULL DEFAULT '',
sample_output TEXT NOT NULL DEFAULT '',
created_at INTEGER NOT NULL
);
@@ -39,22 +43,26 @@ CREATE TABLE IF NOT EXISTS submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
problem_id INTEGER NOT NULL,
contest_id INTEGER,
language TEXT NOT NULL,
code TEXT NOT NULL,
status TEXT NOT NULL,
score INTEGER NOT NULL DEFAULT 0,
time_ms INTEGER NOT NULL DEFAULT 0,
memory_kb INTEGER NOT NULL DEFAULT 0,
compile_log TEXT NOT NULL DEFAULT '',
runtime_log TEXT NOT NULL DEFAULT '',
created_at INTEGER NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE,
FOREIGN KEY(contest_id) REFERENCES contests(id) ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS wrong_book (
user_id INTEGER NOT NULL,
problem_id INTEGER NOT NULL,
last_submission_id INTEGER,
note TEXT NOT NULL DEFAULT "",
note TEXT NOT NULL DEFAULT '',
updated_at INTEGER NOT NULL,
PRIMARY KEY(user_id, problem_id),
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
@@ -62,5 +70,133 @@ CREATE TABLE IF NOT EXISTS wrong_book (
FOREIGN KEY(last_submission_id) REFERENCES submissions(id) ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS contests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
starts_at INTEGER NOT NULL,
ends_at INTEGER NOT NULL,
rule_json TEXT NOT NULL DEFAULT '{}'
);
CREATE TABLE IF NOT EXISTS contest_problems (
contest_id INTEGER NOT NULL,
problem_id INTEGER NOT NULL,
idx INTEGER NOT NULL,
PRIMARY KEY(contest_id, problem_id),
FOREIGN KEY(contest_id) REFERENCES contests(id) ON DELETE CASCADE,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS contest_registrations (
contest_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
registered_at INTEGER NOT NULL,
PRIMARY KEY(contest_id, user_id),
FOREIGN KEY(contest_id) REFERENCES contests(id) ON DELETE CASCADE,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS kb_articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
content_md TEXT NOT NULL,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS kb_article_links (
article_id INTEGER NOT NULL,
problem_id INTEGER NOT NULL,
PRIMARY KEY(article_id, problem_id),
FOREIGN KEY(article_id) REFERENCES kb_articles(id) ON DELETE CASCADE,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS import_jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
status TEXT NOT NULL,
trigger TEXT NOT NULL DEFAULT 'manual',
total_count INTEGER NOT NULL DEFAULT 0,
processed_count INTEGER NOT NULL DEFAULT 0,
success_count INTEGER NOT NULL DEFAULT 0,
failed_count INTEGER NOT NULL DEFAULT 0,
options_json TEXT NOT NULL DEFAULT '{}',
last_error TEXT NOT NULL DEFAULT '',
started_at INTEGER NOT NULL,
finished_at INTEGER,
updated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS import_job_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
job_id INTEGER NOT NULL,
source_path TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'queued',
title TEXT NOT NULL DEFAULT '',
difficulty INTEGER NOT NULL DEFAULT 0,
problem_id INTEGER,
error_text TEXT NOT NULL DEFAULT '',
started_at INTEGER,
finished_at INTEGER,
updated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
FOREIGN KEY(job_id) REFERENCES import_jobs(id) ON DELETE CASCADE,
UNIQUE(job_id, source_path)
);
CREATE TABLE IF NOT EXISTS problem_drafts (
user_id INTEGER NOT NULL,
problem_id INTEGER NOT NULL,
language TEXT NOT NULL DEFAULT 'cpp',
code TEXT NOT NULL DEFAULT '',
stdin TEXT NOT NULL DEFAULT '',
updated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
PRIMARY KEY(user_id, problem_id),
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS problem_solution_jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
problem_id INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'queued',
progress INTEGER NOT NULL DEFAULT 0,
message TEXT NOT NULL DEFAULT '',
created_by INTEGER NOT NULL DEFAULT 0,
max_solutions INTEGER NOT NULL DEFAULT 3,
created_at INTEGER NOT NULL,
started_at INTEGER,
finished_at INTEGER,
updated_at INTEGER NOT NULL,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS problem_solutions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
problem_id INTEGER NOT NULL,
variant INTEGER NOT NULL DEFAULT 1,
title TEXT NOT NULL DEFAULT '',
idea_md TEXT NOT NULL DEFAULT '',
explanation_md TEXT NOT NULL DEFAULT '',
code_cpp TEXT NOT NULL DEFAULT '',
complexity TEXT NOT NULL DEFAULT '',
tags_json TEXT NOT NULL DEFAULT '[]',
source TEXT NOT NULL DEFAULT 'llm',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
FOREIGN KEY(problem_id) REFERENCES problems(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_submissions_user_created_at ON submissions(user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_submissions_problem_created_at ON submissions(problem_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_submissions_contest_user_created_at ON submissions(contest_id, user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_problem_tags_tag ON problem_tags(tag);
CREATE INDEX IF NOT EXISTS idx_kb_article_links_problem_id ON kb_article_links(problem_id);
CREATE INDEX IF NOT EXISTS idx_import_jobs_created_at ON import_jobs(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_import_jobs_status ON import_jobs(status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_import_job_items_job_status ON import_job_items(job_id, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_problem_drafts_updated ON problem_drafts(updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_problem_solution_jobs_problem ON problem_solution_jobs(problem_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_problem_solutions_problem ON problem_solutions(problem_id, variant, id);