project-bifrost-platform/scripts/seed-roadmap.js
Jonathan Hvid 9ae8422527 feat(db): roadmap_items gains 'considering' + 'in_beta' rename, --on-ink tokens
Migration 0006 (the spec said 0005 but that number was already taken by
polls_on_dispatches from the previous session): rebuilds the
roadmap_items CHECK to ('shipping','in_beta','exploring','considering')
and renames any existing 'beta' rows to 'in_beta' in-place. FKs from
roadmap_attributions are preserved across the DROP/RENAME by toggling
PRAGMA foreign_keys off around the rebuild — attribution count unchanged
after migrate (verified 4 rows survive on the demo DB).

Tokens (src/styles/tokens.css): adds --on-ink, --on-ink-body,
--on-ink-muted, --ink-divider. The bleached #fffcf7 cream replaces the
warm #e8e0d0 --ink-text wherever it sits on indigo. Legacy --ink-text /
--ink-muted stay in tokens.css for now — if any later commit references
them they remain defined; the migration of existing call sites is
covered here.

Migrated to the new tokens in this pass:
  - src/components/MembershipCard.astro (members/:slug card)
  - src/pages/events.astro (hero invitation card)
  Both render with cleaner whites on indigo as a side effect.

Code updates for the new status enum:
  - db.ts: RoadmapStatus = shipping | in_beta | exploring | considering
  - admin/RoadmapTab.astro: Status select gains Considering + In beta;
    grouped section iteration covers all four
  - admin/index.astro: validation list updated
  - scripts/seed-roadmap.js: 'In progress' markdown bucket → 'in_beta'
  - pulse.astro: roadmapStatusDot + roadmapStatusBlurb temporarily widened
    (full rewrite of that section lands in step 7)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:46:39 +02:00

84 lines
2.7 KiB
JavaScript

#!/usr/bin/env node
// Parse content/roadmap.md → roadmap_items rows. Idempotent: only seeds if
// the table is empty. Once admin starts managing roadmap via /admin, the
// markdown is no longer the source of truth — but it stays in the repo as
// the initial-seed reference.
import Database from 'better-sqlite3';
import { readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const dbPath = process.env.BIFROST_DB_PATH ?? join(__dirname, '..', 'bifrost.db');
const mdPath = join(__dirname, '..', 'content', 'roadmap.md');
const db = new Database(dbPath);
db.pragma('foreign_keys = ON');
const existing = db.prepare('SELECT COUNT(*) AS n FROM roadmap_items').get().n;
if (existing > 0) {
console.log(` roadmap_items already populated (${existing} rows) — skipping seed.`);
db.close();
process.exit(0);
}
const md = readFileSync(mdPath, 'utf8');
// Section → status mapping.
// Markdown sections "In progress" / "Next" / "Later" map to the council-portal
// schema's three statuses. In-progress items are actively being built and
// tested with pilots → beta. Next/Later are roadmap intent, not started → exploring.
const SECTION_STATUS = {
'In progress': { status: 'in_beta', target: null },
'Next': { status: 'exploring', target: 'Next quarter' },
'Later': { status: 'exploring', target: 'Later this year' },
};
const items = [];
let currentSection = null;
let sectionDisplayOrder = 0;
for (const rawLine of md.split('\n')) {
const line = rawLine.trim();
const h2 = line.match(/^##\s+(.+)$/);
if (h2) {
currentSection = h2[1].trim();
sectionDisplayOrder = 0;
continue;
}
if (!currentSection || !SECTION_STATUS[currentSection]) continue;
// Format: **Title** — description text. Optional `pilot-only` flag at end.
const m = line.match(/^\*\*([^*]+)\*\*\s*[—-]\s*(.+)$/);
if (!m) continue;
sectionDisplayOrder += 10;
const title = m[1].trim();
let description = m[2].trim();
// strip trailing ` `pilot-only` ` flag; admin can re-add via UI if wanted
description = description.replace(/`pilot-only`\s*$/, '').trim();
items.push({
title,
description,
status: SECTION_STATUS[currentSection].status,
target: SECTION_STATUS[currentSection].target,
display_order: sectionDisplayOrder,
});
}
const insert = db.prepare(`
INSERT INTO roadmap_items (title, description, status, target, display_order)
VALUES (?,?,?,?,?)
`);
const tx = db.transaction(() => {
for (const it of items) {
insert.run(it.title, it.description, it.status, it.target, it.display_order);
}
});
tx();
console.log(` seeded ${items.length} roadmap items from content/roadmap.md`);
db.close();