refactor(db): switch records layer to Prisma

- Replace hand-written node:sqlite queries with a Prisma client using
  the better-sqlite3 driver adapter
- Version the schema with migrations: baseline table, timestamp
  normalisation, and WAL journal mode
- Store timestamps with an explicit UTC offset so they stop being parsed
  as local time
- Show created/updated times on the edit page, formatted with dayjs
- Move the root redirect into next.config to avoid a prerender error
- Run migrations from the container entrypoint before starting the server

BREAKING CHANGE: DNSMASQ_ADMIN_DB_PATH is replaced by DATABASE_URL, which
must be a Prisma connection URL (file:./data/dnsmasq-admin.db). Existing
database files are migrated in place and need no conversion.
This commit is contained in:
jamo.siu@gmail.com committed 2026-10-12 14:27:03 +08:00
1 parent 97ad09ad8a
commit 1e4f028685
25 files changed
+1796 -141

No files matched your search

@@ -0,0 +1,31 @@
-- Baseline: the `records` table as Prisma itself generates it from prisma/schema.prisma.
--
-- This SQL is kept byte-identical to the output of
-- `prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script`
-- on purpose. The alternative — adding `COLLATE NOCASE` on `domain` and a
-- `CHECK (type IN ('A','CNAME'))` by hand — makes Prisma see permanent drift and propose a
-- DROP TABLE + rebuild migration the next time anyone runs `migrate dev`, which would silently
-- drop those very constraints. A clean diff is worth more here than the extra constraints,
-- because both properties are enforced elsewhere:
--
-- - case-insensitive uniqueness: lib/validate.ts lowercases every domain before it reaches
-- the database, so `FOO.com` and `foo.com` can never both be inserted;
-- - case-insensitive ordering: lib/records.ts sorts with localeCompare after fetching,
-- since SQLite would otherwise order by binary collation ('Zoo' before 'apple');
-- - the type whitelist: again lib/validate.ts, plus the generated union in lib/db.ts.
--
-- Existing databases installed before this migration already ran the earlier hand-written
-- version and keep their column-level COLLATE NOCASE; nothing about them changes.
CREATE TABLE "records" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"domain" TEXT NOT NULL,
"type" TEXT NOT NULL,
"value" TEXT NOT NULL,
"enabled" BOOLEAN NOT NULL DEFAULT true,
"comment" TEXT NOT NULL DEFAULT '',
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "records_domain_key" ON "records"("domain");