-- Phase 2/3 initial schema. -- -- Users = people who sign in via Entra ID. -- Workers = entities that get work assigned (may or may not also be users). -- Never conflate the two. CREATE TABLE users ( id INTEGER PRIMARY KEY, entra_oid TEXT NOT NULL UNIQUE, email TEXT NOT NULL, display_name TEXT NOT NULL, is_admin INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, last_login_at TEXT ); CREATE TABLE workers ( id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE, is_active INTEGER NOT NULL DEFAULT 1, default_rtb REAL NOT NULL DEFAULT 0.0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE sprints ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, start_date TEXT NOT NULL, end_date TEXT NOT NULL, reserve_fraction REAL NOT NULL DEFAULT 0.2, is_archived INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE sprint_weeks ( id INTEGER PRIMARY KEY, sprint_id INTEGER NOT NULL REFERENCES sprints(id) ON DELETE CASCADE, sort_order INTEGER NOT NULL, iso_week INTEGER NOT NULL, start_date TEXT NOT NULL, max_working_days REAL NOT NULL, UNIQUE (sprint_id, sort_order) ); CREATE TABLE sprint_workers ( id INTEGER PRIMARY KEY, sprint_id INTEGER NOT NULL REFERENCES sprints(id) ON DELETE CASCADE, worker_id INTEGER NOT NULL REFERENCES workers(id) ON DELETE RESTRICT, rtb REAL NOT NULL DEFAULT 0.0, sort_order INTEGER NOT NULL, UNIQUE (sprint_id, worker_id) ); CREATE TABLE sprint_worker_days ( id INTEGER PRIMARY KEY, sprint_worker_id INTEGER NOT NULL REFERENCES sprint_workers(id) ON DELETE CASCADE, sprint_week_id INTEGER NOT NULL REFERENCES sprint_weeks(id) ON DELETE CASCADE, days REAL NOT NULL DEFAULT 0, UNIQUE (sprint_worker_id, sprint_week_id) ); CREATE TABLE tasks ( id INTEGER PRIMARY KEY, sprint_id INTEGER NOT NULL REFERENCES sprints(id) ON DELETE CASCADE, title TEXT NOT NULL, owner_worker_id INTEGER REFERENCES workers(id) ON DELETE SET NULL, priority INTEGER NOT NULL CHECK (priority IN (1, 2)), sort_order INTEGER NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE task_assignments ( id INTEGER PRIMARY KEY, task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, sprint_worker_id INTEGER NOT NULL REFERENCES sprint_workers(id) ON DELETE CASCADE, days REAL NOT NULL DEFAULT 0, UNIQUE (task_id, sprint_worker_id) ); CREATE TABLE audit_log ( id INTEGER PRIMARY KEY, occurred_at TEXT NOT NULL, user_id INTEGER, user_email TEXT, action TEXT NOT NULL, entity_type TEXT NOT NULL, entity_id INTEGER, before_json TEXT, after_json TEXT, ip_address TEXT, user_agent TEXT ); CREATE INDEX idx_audit_occurred_at ON audit_log(occurred_at DESC); CREATE INDEX idx_audit_entity ON audit_log(entity_type, entity_id); CREATE INDEX idx_tasks_sprint ON tasks(sprint_id, sort_order); CREATE INDEX idx_sw_sprint ON sprint_workers(sprint_id, sort_order);