CREATE TABLE IF NOT EXISTS students ( id SERIAL PRIMARY KEY, name VARCHAR(150) NOT NULL UNIQUE, created_at TIMESTAMPTZ DEFAULT now() ); ALTER TABLE students ADD COLUMN IF NOT EXISTS group_id INT REFERENCES groups(id); CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ); INSERT INTO settings (key, value) VALUES ('spam_interval_min', '30') ON CONFLICT (key) DO NOTHING; CREATE TABLE IF NOT EXISTS share_links ( id SERIAL PRIMARY KEY, token VARCHAR(40) UNIQUE NOT NULL, name VARCHAR(200) NOT NULL, group_id INT REFERENCES groups(id), student_name VARCHAR(150), date_from DATE, date_to DATE, created_at TIMESTAMPTZ DEFAULT now() ); DO $$ BEGIN INSERT INTO students (name) SELECT DISTINCT student_name FROM entries WHERE student_name IS NOT NULL AND student_name <> '' ON CONFLICT (name) DO NOTHING; END $$; CREATE TABLE IF NOT EXISTS project_files ( id SERIAL PRIMARY KEY, entry_id INT NOT NULL REFERENCES entries(id) ON DELETE CASCADE, token VARCHAR(64), path VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, created_at TIMESTAMPTZ DEFAULT now() ); UPDATE project_files SET token = md5(random()::text || clock_timestamp()::text) WHERE token IS NULL; ALTER TABLE project_files ALTER COLUMN token SET NOT NULL; CREATE UNIQUE INDEX IF NOT EXISTS project_files_token_key ON project_files(token);