feat(FN-1690): add RoadmapStore with SQLite persistence

- Implement RoadmapStore with CRUD operations for roadmaps, milestones, and features
- Add roadmap schema migration v32 with roadmaps, roadmap_milestones, and roadmap_features tables
- Add covering indexes for deterministic ordering within roadmaps and milestones
- Wire RoadmapStore access via TaskStore.getRoadmapStore()
- Update architecture.md documentation with RoadmapStore persistence
- Add comprehensive tests for RoadmapStore CRUD and ordering
- Update db.test.ts with schema v32 assertions
- Add UpdateInput type imports to task-documents.test.ts
- Export RoadmapStore from core index.ts
This commit is contained in:
gsxdsm
2026-04-14 09:57:09 -07:00
parent 7857b9660b
commit d8982d5336
10 changed files with 1592 additions and 17 deletions

View File

@@ -59,7 +59,7 @@ export function fromJson<T>(json: string | null | undefined): T | undefined {
// ── Schema Definition ────────────────────────────────────────────────
const SCHEMA_VERSION = 31;
const SCHEMA_VERSION = 32;
function normalizeTaskComments(
steeringComments: SteeringComment[] | undefined,
@@ -1176,6 +1176,66 @@ export class Database {
this.db.exec(`CREATE INDEX IF NOT EXISTS idxFixLineageRunId ON mission_fix_feature_lineage(runId)`);
});
}
// Roadmap persistence tables (FN-1690)
// Standalone roadmap: Roadmap → RoadmapMilestone → RoadmapFeature
// with deterministic ordering indexes and FK cascade integrity
if (version < 32) {
this.applyMigration(32, () => {
// Roadmaps table
this.db.exec(`
CREATE TABLE IF NOT EXISTS roadmaps (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL
)
`);
// Roadmap milestones table
this.db.exec(`
CREATE TABLE IF NOT EXISTS roadmap_milestones (
id TEXT PRIMARY KEY,
roadmapId TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
orderIndex INTEGER NOT NULL,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
FOREIGN KEY (roadmapId) REFERENCES roadmaps(id) ON DELETE CASCADE
)
`);
// Roadmap features table
this.db.exec(`
CREATE TABLE IF NOT EXISTS roadmap_features (
id TEXT PRIMARY KEY,
milestoneId TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
orderIndex INTEGER NOT NULL,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
FOREIGN KEY (milestoneId) REFERENCES roadmap_milestones(id) ON DELETE CASCADE
)
`);
// Covering index for deterministic milestone ordering within a roadmap
// Covers: WHERE roadmapId = ? ORDER BY orderIndex ASC, createdAt ASC, id ASC
this.db.exec(`
CREATE INDEX IF NOT EXISTS idxRoadmapMilestonesRoadmapOrder
ON roadmap_milestones(roadmapId, orderIndex, createdAt, id)
`);
// Covering index for deterministic feature ordering within a milestone
// Covers: WHERE milestoneId = ? ORDER BY orderIndex ASC, createdAt ASC, id ASC
this.db.exec(`
CREATE INDEX IF NOT EXISTS idxRoadmapFeaturesMilestoneOrder
ON roadmap_features(milestoneId, orderIndex, createdAt, id)
`);
});
}
}
/**