PRAGMA foreign_keys = ON; CREATE TABLE IF NOT EXISTS schema_migrations ( version INTEGER PRIMARY KEY, applied_at TEXT NOT NULL ); CREATE TABLE projects ( project_id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL ); CREATE TABLE actors ( actor_id TEXT PRIMARY KEY, auth_subject TEXT NOT NULL UNIQUE, display_name TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE TABLE project_memberships ( project_id TEXT NOT NULL REFERENCES projects(project_id), actor_id TEXT NOT NULL REFERENCES actors(actor_id), role TEXT NOT NULL CHECK (role IN ( 'SYSTEM','PO','PM','PA','ARCHITECT','LEAD_ENGINEER', 'IMPLEMENTER','REVIEWER','SECURITY_REVIEWER','OBSERVER' )), active INTEGER NOT NULL DEFAULT 1 CHECK (active IN (0, 1)), created_at TEXT NOT NULL, PRIMARY KEY (project_id, actor_id) ); CREATE TABLE work_packages ( project_id TEXT NOT NULL REFERENCES projects(project_id), work_package_id TEXT NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL, acceptance_criteria_json TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ( 'OPEN','CLAIMED','RESULT_SUBMITTED','IN_REVIEW','REVIEWED', 'ACCEPTED','REJECTED','CANCELLED' )), issued_by TEXT NOT NULL REFERENCES actors(actor_id), claimed_by TEXT REFERENCES actors(actor_id), result_submitted_by TEXT REFERENCES actors(actor_id), result_json TEXT, accepted_by TEXT REFERENCES actors(actor_id), created_at TEXT NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY (project_id, work_package_id) ); CREATE INDEX work_packages_project_status ON work_packages(project_id, status, updated_at); CREATE TABLE review_requests ( project_id TEXT NOT NULL REFERENCES projects(project_id), review_id TEXT NOT NULL, work_package_id TEXT NOT NULL, requested_by TEXT NOT NULL REFERENCES actors(actor_id), reviewer_id TEXT NOT NULL REFERENCES actors(actor_id), review_type TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ('OPEN','SUBMITTED')), verdict TEXT CHECK (verdict IN ('APPROVE','CHANGES_REQUESTED','REJECT')), findings_json TEXT, created_at TEXT NOT NULL, submitted_at TEXT, PRIMARY KEY (project_id, review_id), FOREIGN KEY (project_id, work_package_id) REFERENCES work_packages(project_id, work_package_id) ); CREATE INDEX review_requests_project_status ON review_requests(project_id, status, reviewer_id); CREATE TABLE decisions ( project_id TEXT NOT NULL REFERENCES projects(project_id), decision_id TEXT NOT NULL, kind TEXT NOT NULL CHECK (kind IN ('PRODUCT','ARCHITECTURE','OPERATIONAL','GATE')), title TEXT NOT NULL, decision TEXT NOT NULL, rationale TEXT NOT NULL, decided_by TEXT NOT NULL REFERENCES actors(actor_id), work_package_id TEXT, created_at TEXT NOT NULL, PRIMARY KEY (project_id, decision_id), FOREIGN KEY (project_id, work_package_id) REFERENCES work_packages(project_id, work_package_id) ); CREATE TABLE escalations ( project_id TEXT NOT NULL REFERENCES projects(project_id), escalation_id TEXT NOT NULL, raised_by TEXT NOT NULL REFERENCES actors(actor_id), severity TEXT NOT NULL CHECK (severity IN ('LOW','MEDIUM','HIGH','CRITICAL')), title TEXT NOT NULL, description TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ('OPEN','RESOLVED')), target_role TEXT, resolution TEXT, resolved_by TEXT REFERENCES actors(actor_id), created_at TEXT NOT NULL, resolved_at TEXT, PRIMARY KEY (project_id, escalation_id) ); CREATE TABLE event_log ( cursor INTEGER PRIMARY KEY AUTOINCREMENT, event_id TEXT NOT NULL UNIQUE, project_id TEXT NOT NULL REFERENCES projects(project_id), event_type TEXT NOT NULL, actor_id TEXT NOT NULL REFERENCES actors(actor_id), actor_role TEXT NOT NULL, aggregate_type TEXT NOT NULL, aggregate_id TEXT NOT NULL, correlation_id TEXT, causation_event_id TEXT, payload_json TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE INDEX event_log_project_cursor ON event_log(project_id, cursor); CREATE INDEX event_log_aggregate ON event_log(project_id, aggregate_type, aggregate_id, cursor); CREATE TRIGGER event_log_no_update BEFORE UPDATE ON event_log BEGIN SELECT RAISE(ABORT, 'event_log is append-only'); END; CREATE TRIGGER event_log_no_delete BEFORE DELETE ON event_log BEGIN SELECT RAISE(ABORT, 'event_log is append-only'); END; CREATE TABLE idempotency_records ( project_id TEXT NOT NULL, actor_id TEXT NOT NULL, idempotency_key TEXT NOT NULL, operation TEXT NOT NULL, request_hash TEXT NOT NULL, response_json TEXT NOT NULL, created_at TEXT NOT NULL, PRIMARY KEY (project_id, actor_id, idempotency_key) );