CREATE SEQUENCE IF NOT EXISTS users_id_seq; CREATE SEQUENCE IF NOT EXISTS sources_id_seq; CREATE SEQUENCE IF NOT EXISTS source_runs_id_seq; CREATE SEQUENCE IF NOT EXISTS entries_id_seq; CREATE SEQUENCE IF NOT EXISTS tags_id_seq; CREATE SEQUENCE IF NOT EXISTS comments_id_seq; CREATE SEQUENCE IF NOT EXISTS audit_logs_id_seq; CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY DEFAULT nextval('users_id_seq'), username VARCHAR UNIQUE NOT NULL, password_hash VARCHAR NOT NULL, role VARCHAR NOT NULL DEFAULT 'editor', status VARCHAR NOT NULL DEFAULT 'active', last_login_at TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS sources ( id INTEGER PRIMARY KEY DEFAULT nextval('sources_id_seq'), kind VARCHAR NOT NULL, name VARCHAR UNIQUE NOT NULL, enabled BOOLEAN NOT NULL DEFAULT TRUE, url VARCHAR, adapter VARCHAR, cron_expr VARCHAR DEFAULT '0 9 * * 1', api_key_hash VARCHAR, api_key VARCHAR, direct_publish BOOLEAN NOT NULL DEFAULT FALSE, last_run_at TIMESTAMPTZ, last_run_status VARCHAR ); CREATE TABLE IF NOT EXISTS source_runs ( id INTEGER PRIMARY KEY DEFAULT nextval('source_runs_id_seq'), source_id INTEGER NOT NULL REFERENCES sources(id), started_at TIMESTAMPTZ NOT NULL DEFAULT now(), finished_at TIMESTAMPTZ, status VARCHAR, found INTEGER DEFAULT 0, created INTEGER DEFAULT 0, skipped INTEGER DEFAULT 0, error TEXT ); CREATE TABLE IF NOT EXISTS tags ( id INTEGER PRIMARY KEY DEFAULT nextval('tags_id_seq'), name VARCHAR NOT NULL, parent_id INTEGER REFERENCES tags(id), sort INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS entries ( id INTEGER PRIMARY KEY DEFAULT nextval('entries_id_seq'), title VARCHAR NOT NULL, slug VARCHAR UNIQUE NOT NULL, type VARCHAR NOT NULL, summary VARCHAR DEFAULT '', description_md TEXT DEFAULT '', url VARCHAR DEFAULT '', license VARCHAR DEFAULT '', stars BIGINT DEFAULT 0, status VARCHAR NOT NULL DEFAULT 'pending', source_id INTEGER REFERENCES sources(id), verified_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS entry_tags ( entry_id INTEGER NOT NULL REFERENCES entries(id), tag_id INTEGER NOT NULL REFERENCES tags(id), PRIMARY KEY (entry_id, tag_id) ); CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY DEFAULT nextval('comments_id_seq'), entry_id INTEGER NOT NULL REFERENCES entries(id), user_id INTEGER REFERENCES users(id), author_name VARCHAR NOT NULL, body TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS audit_logs ( id INTEGER PRIMARY KEY DEFAULT nextval('audit_logs_id_seq'), actor VARCHAR NOT NULL, action VARCHAR NOT NULL, target VARCHAR DEFAULT '', detail TEXT DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now() );