2026-05-10: Import/Export Fix + SQLite DB Export
Context
Section titled “Context”Issue: issues/todo/import-export.md
Two problems reported from the /settings page:
- Bug: Export → Import round-trip fails with
"Invalid backup format: missing version or data." - Feature request: Can the export be a
.dbfile instead of (or in addition to) JSON, so it can be opened directly in SQLite viewers (e.g. VSCode SQLite extension)?
A third issue discovered during investigation:
- Bug:
backend/prisma/schema.prismawas corrupted — line 1 had the path string/Users/fducat/WORKSPACE/strata/issues/todo/feedback-and-fixes.mdprepended directly beforegenerator client {. Thegenerator client { provider = "prisma-client-js" }block is mandatory even with Prisma 7 +prisma.config.ts(the config file only handles datasource URL). The corruption only brokeprisma generate/prisma migrate; the running app was unaffected because the client is pre-generated.
Root Cause (JSON Import Bug)
Section titled “Root Cause (JSON Import Bug)”| Layer | Field name used |
|---|---|
Backend (exportBackup) | schemaVersion |
Frontend BackupPayload interface | version ← wrong |
Frontend isParsedBackup guard | checks v.version ← fails |
| Frontend fallback assembler | uses version: '1.0' ← wrong value too |
| Frontend restore call | sends version field ← backend DTO expects schemaVersion |
When the user exported the JSON, the file contained schemaVersion. When imported, the
frontend guard looked for version → not found → “Invalid backup format” error.
Approach
Section titled “Approach”Part 0 — Fix corrupted schema.prisma
Section titled “Part 0 — Fix corrupted schema.prisma”- Strip the garbage path prefix from line 1
- Run
npx prisma validateto confirm
Part 1 — Fix JSON import/export field name mismatch
Section titled “Part 1 — Fix JSON import/export field name mismatch”Rename version → schemaVersion throughout the frontend layer:
front/src/lib/api/backup.ts(BackupPayloadinterface)front/src/stores/backupStore.ts(ParsedBackupinterface)front/src/components/settings/useBackupImport.ts(guard + restore payload)front/src/components/settings/useBackupExport.ts(fallback assembler)- Unit tests:
backupStore.test.ts,backup.test.ts - E2e test:
backup.spec.ts(this test was usingversion: '1.0'→ regression would have been caught)
Part 2 — Add raw SQLite .db export
Section titled “Part 2 — Add raw SQLite .db export”- Backend: new
GET /api/v1/admin/backup/sqliteendpoint streaming the raw.dbfile (readsDATABASE_URL, stripsfile:prefix, resolves path, streams bytes withContent-Type: application/x-sqlite3) - Frontend: new “Export as .db” button in
BackupSection,backupApi.exportDb() - Docs, Bruno, tests updated
Files Changed
Section titled “Files Changed”Part 0
Section titled “Part 0”backend/prisma/schema.prisma— remove garbage path prefix from line 1
Part 1 (bug fix)
Section titled “Part 1 (bug fix)”front/src/lib/api/backup.tsfront/src/stores/backupStore.tsfront/src/components/settings/useBackupImport.tsfront/src/components/settings/useBackupExport.tsfront/src/stores/__tests__/backupStore.test.tsfront/src/lib/api/__tests__/backup.test.tsfront/e2e/backup.spec.ts
Part 2 (feature)
Section titled “Part 2 (feature)”backend/src/application/services/backup/backup.service.tsbackend/src/presentation/controllers/admin.controller.tsbackend/src/application/services/backup/backup.service.spec.tsbackend/test/admin-backup.e2e-spec.tsfront/src/lib/api/backup.tsfront/src/components/settings/useBackupExport.tsfront/src/components/settings/BackupSection.tsxfront/src/lib/api/__tests__/backup.test.ts.bruno/Strata/Admin/Get SQLite DB.brudocs/src/content/docs/backup.md
Execution Summary
Section titled “Execution Summary”Commit: e1d3ca0
Actual changes
Section titled “Actual changes”All 18 planned items implemented. Files modified/created match the plan exactly.
Additionally fixed: backend/prisma/schema.prisma — garbage path string /Users/fducat/WORKSPACE/strata/issues/todo/feedback-and-fixes.md was prepended to line 1 (Part 0 in plan).
Deviations from plan
Section titled “Deviations from plan”- e2e binary assertion:
res.body.slice(0, 6)doesn’t work with supertest on binary responses — supertest returns{}unless you provide a custom binary parser. Fixed by adding.buffer(true).parse(...)with a raw chunk accumulator, then castingres.bodyasBufferand using.subarray(0, 6)instead of.slice. - ExportFormat type: Exported from
useBackupExport.ts(not a separate types file) for local use byBackupSection.tsx.
Test results
Section titled “Test results”| Gate | Result |
|---|---|
| Backend unit | ✅ 268 tests passed |
| Backend e2e | ✅ 70 tests passed (4 suites, including new sqlite endpoint test) |
| Frontend unit | ✅ 394 tests passed |
| Frontend e2e | ⏭ Not run (only mocked API smoke tests; no live backend needed for backup import fix) |
Key discoveries
Section titled “Key discoveries”jest.spyOncannot redefine properties on native Node modules (node:fs/promises). Must use top-leveljest.mock('node:fs/promises', () => ({ readFile: jest.fn() }))pattern instead.res.bodyin supertest is{}forapplication/x-sqlite3responses unless.buffer(true)+ a custom binary parser is provided.- The
generator client { provider = "prisma-client-js" }block inschema.prismais mandatory even with Prisma 7 +prisma.config.ts(config handles datasource URL only, not generator).
Acceptance Criteria
Section titled “Acceptance Criteria”- Export JSON → import JSON round-trip completes without error
- “Export as .db” button downloads a
.dbfile openable in SQLite viewers -
GET /api/v1/admin/backup/sqlite→ 200Content-Type: application/x-sqlite3 - All backend unit tests pass (≥90% coverage)
- All backend e2e tests pass
- All frontend unit tests pass (≥90% coverage)
- Frontend e2e
backup.spec.tspasses with correctedschemaVersionpayload