diff --git a/README.md b/README.md index 3dadcbd..e4c2dec 100644 --- a/README.md +++ b/README.md @@ -37,12 +37,10 @@ DATABASE_URL=file:./data/dimensionlab.sqlite SQLite files under `data/` are ignored. Drizzle schema lives in `src/lib/server/db/schema.ts`; tracked migrations live in `drizzle/`. Runtime -startup applies the checked-in dashboard migrations before reads or writes. If -the app is launched from outside the repo tree, set `DASHBOARD_MIGRATIONS_DIR` -to the tracked migrations directory. The current driver is `bun:sqlite`, which -keeps this repo installable in the Bun workflow. The store boundary is isolated -so a later Postgres driver can replace the SQLite connection without changing -the dashboard model or renderer. +startup applies the checked-in dashboard migrations before reads or writes. The +current driver is `bun:sqlite`, which keeps this repo installable in the Bun +workflow. The store boundary is isolated so a later Postgres driver can replace +the SQLite connection without changing the dashboard model or renderer. Stored dashboard documents pass through a version migration boundary before reads or writes; the MVP supports `dashboard.v1` and fails unsupported versions with an explicit migration error. diff --git a/src/lib/server/db/dashboard-store.test.ts b/src/lib/server/db/dashboard-store.test.ts index ecb80f3..71942f0 100644 --- a/src/lib/server/db/dashboard-store.test.ts +++ b/src/lib/server/db/dashboard-store.test.ts @@ -13,11 +13,9 @@ import { const stores: DashboardStore[] = []; const tempRoots: string[] = []; -const originalCwd = process.cwd(); afterEach(() => { vi.useRealTimers(); - process.chdir(originalCwd); stores.splice(0).forEach((store) => store.close()); tempRoots.splice(0).forEach((path) => rmSync(path, { force: true, recursive: true })); }); @@ -167,25 +165,6 @@ describe("dashboard persistence store", () => { seed.id, ]); }); - - test("applies migrations when launched outside the repository root", async () => { - const root = await mkdtemp(join(tmpdir(), "dimensionlab-dashboard-cwd-")); - tempRoots.push(root); - process.chdir(root); - vi.resetModules(); - const { createDashboardStore: createStore } = await import("./dashboard-store"); - const store = createStore({ - databaseUrl: `file:${join(root, "dashboard.sqlite")}`, - }); - stores.push(store); - - const seed = store.seedDashboardIfEmpty(genericDashboardFixture, { - actor: "test-seed", - }); - - expect(seed.document.metadata.title).toBe("Operations Console"); - expect(store.getActiveDashboard()?.currentRevisionId).toBe(seed.id); - }); }); async function createTestStore() { diff --git a/src/lib/server/db/migrations.ts b/src/lib/server/db/migrations.ts index 9e34ba0..917d777 100644 --- a/src/lib/server/db/migrations.ts +++ b/src/lib/server/db/migrations.ts @@ -1,52 +1,12 @@ -import { existsSync } from "node:fs"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; +import { resolve } from "node:path"; import { migrate } from "drizzle-orm/bun-sqlite/migrator"; import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite"; -const MIGRATION_JOURNAL_PATH = join("meta", "_journal.json"); +export const DASHBOARD_MIGRATIONS_FOLDER = resolve("drizzle"); export function applyDashboardMigrations( database: BunSQLiteDatabase>, - migrationsFolder = resolveDashboardMigrationsFolder(), + migrationsFolder = DASHBOARD_MIGRATIONS_FOLDER, ) { migrate(database, { migrationsFolder }); } - -export function resolveDashboardMigrationsFolder( - explicitFolder = process.env.DASHBOARD_MIGRATIONS_DIR, -): string { - if (explicitFolder) return assertMigrationFolder(resolve(explicitFolder)); - - const cwdFolder = findMigrationFolder(process.cwd()); - if (cwdFolder) return cwdFolder; - - const moduleFolder = findMigrationFolder(dirname(fileURLToPath(import.meta.url))); - if (moduleFolder) return moduleFolder; - - throw new Error( - "Unable to locate dashboard Drizzle migrations. Set DASHBOARD_MIGRATIONS_DIR.", - ); -} - -function findMigrationFolder(startPath: string): string | null { - let currentPath = resolve(startPath); - - while (true) { - const candidate = join(currentPath, "drizzle"); - if (hasMigrationJournal(candidate)) return candidate; - - const parentPath = dirname(currentPath); - if (parentPath === currentPath) return null; - currentPath = parentPath; - } -} - -function assertMigrationFolder(folder: string): string { - if (hasMigrationJournal(folder)) return folder; - throw new Error(`Dashboard migrations not found in ${folder}`); -} - -function hasMigrationJournal(folder: string): boolean { - return existsSync(join(folder, MIGRATION_JOURNAL_PATH)); -}