Files
settled-reach/db/schema.sql
T
jpmschweitzerandClaude Opus 4.6 e6a557e8e7 feat(meta): replace sprint workflow with kanban + milestones (D-221)
Sprint-based workflow (38 sprints) replaced by kanban + milestones.
Milestones are many-to-many with tickets and can block each other.

New: /whats-next skill (dependency-driven batch selection with Si
refinement review), /pr-process skill (renamed from pr-push, adds
review comment pickup), clerk agent + pre-push hook for D-record
consistency checks.

Deleted: sprint CLI, sprint-start/sprint-plan/sprint-status skills,
team-scoped file restrictions. Si rewritten as refinement manager.
All 19 agent briefings updated from stale PROJECT_STATE.md reference
to live ticket milestone queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-03 20:11:00 +02:00

114 lines
4.6 KiB
SQL

-- Settled Reach Project Ticketing Database Schema
-- Access via: python3 tooling/db/sqlite_connector.py <command>
-- DO NOT use sqlite3 CLI (crashes in Claude Code due to std::bad_alloc bug)
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys=ON;
CREATE TABLE IF NOT EXISTS tickets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT NOT NULL CHECK(type IN ('initiative', 'epic', 'story', 'task', 'bug')),
parent_id INTEGER REFERENCES tickets(id),
title TEXT NOT NULL,
description TEXT,
status TEXT NOT NULL DEFAULT 'backlog' CHECK(status IN ('backlog', 'ready', 'in_progress', 'review', 'done', 'cancelled')),
priority TEXT DEFAULT 'medium' CHECK(priority IN ('critical', 'high', 'medium', 'low')),
assigned_to TEXT,
team TEXT, -- comma-separated team names, e.g. 'server', 'client,server'
decision_ref TEXT, -- e.g. 'D-010' or 'Q-001'
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS milestones (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
status TEXT NOT NULL DEFAULT 'active'
CHECK(status IN ('active', 'completed', 'cancelled')),
cascade_phase INTEGER,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
completed_at TEXT
);
CREATE TABLE IF NOT EXISTS ticket_milestones (
ticket_id INTEGER NOT NULL REFERENCES tickets(id),
milestone_id INTEGER NOT NULL REFERENCES milestones(id),
PRIMARY KEY (ticket_id, milestone_id)
);
CREATE TABLE IF NOT EXISTS milestone_deps (
blocker_id INTEGER NOT NULL REFERENCES milestones(id),
blocked_id INTEGER NOT NULL REFERENCES milestones(id),
PRIMARY KEY (blocker_id, blocked_id)
);
CREATE TABLE IF NOT EXISTS ticket_deps (
blocker_id INTEGER NOT NULL REFERENCES tickets(id),
blocked_id INTEGER NOT NULL REFERENCES tickets(id),
PRIMARY KEY (blocker_id, blocked_id)
);
CREATE TABLE IF NOT EXISTS ticket_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticket_id INTEGER NOT NULL REFERENCES tickets(id),
field TEXT NOT NULL,
old_value TEXT,
new_value TEXT,
changed_by TEXT,
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS ticket_labels (
ticket_id INTEGER NOT NULL REFERENCES tickets(id),
label TEXT NOT NULL,
PRIMARY KEY (ticket_id, label)
);
CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status);
CREATE INDEX IF NOT EXISTS idx_tickets_type ON tickets(type);
CREATE INDEX IF NOT EXISTS idx_tickets_parent ON tickets(parent_id);
CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON tickets(assigned_to);
CREATE INDEX IF NOT EXISTS idx_tickets_decision ON tickets(decision_ref);
CREATE INDEX IF NOT EXISTS idx_tickets_team ON tickets(team);
CREATE INDEX IF NOT EXISTS idx_history_ticket ON ticket_history(ticket_id);
CREATE INDEX IF NOT EXISTS idx_ticket_milestones_ticket ON ticket_milestones(ticket_id);
CREATE INDEX IF NOT EXISTS idx_ticket_milestones_milestone ON ticket_milestones(milestone_id);
-- ---------------------------------------------------------------------------
-- Decision Sync Tables
-- Populated by: python3 tooling/db/decisions_sync.py
-- Source: decisions/*.md domain files
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS decisions (
id TEXT PRIMARY KEY,
type TEXT NOT NULL CHECK(type IN ('confirmed', 'question', 'rejected')),
domain TEXT NOT NULL,
title TEXT NOT NULL,
status TEXT DEFAULT 'active' CHECK(status IN ('active', 'superseded', 'resolved', 'open')),
round INTEGER,
date TEXT,
file_path TEXT NOT NULL,
synced_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS decision_refs (
source_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE,
target_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE,
ref_type TEXT NOT NULL CHECK(ref_type IN ('supersedes', 'references', 'resolves', 'depends_on')),
note TEXT,
PRIMARY KEY (source_id, target_id, ref_type)
);
CREATE INDEX IF NOT EXISTS idx_decisions_type ON decisions(type);
CREATE INDEX IF NOT EXISTS idx_decisions_domain ON decisions(domain);
CREATE INDEX IF NOT EXISTS idx_decisions_status ON decisions(status);
CREATE INDEX IF NOT EXISTS idx_decision_refs_source ON decision_refs(source_id);
CREATE INDEX IF NOT EXISTS idx_decision_refs_target ON decision_refs(target_id);
-- ---------------------------------------------------------------------------
-- Star Systems live in a separate database: server/data/systems.db
-- Schema: server/data/systems-schema.sql
-- ---------------------------------------------------------------------------