feat(import): add ImportJob model for Apple Health export ingest

Additive Prisma model mirroring a `pg-boss` `apple-health-import`
job's lifecycle. The polling endpoint reads `progress` and `result`
live from this row rather than the one-shot terminal `output` column
on `pg_boss.job` (pg-boss v12 only populates `output` on completion).

Carries `pgBossJobId` for the worker's reverse lookup, an upload
sha-256 for content-hash idempotency on re-upload, and per-phase
status (`queued | unpacking | parsing | upserting | done | failed`).
This commit is contained in:
Marc-André Bombeck committed 2026-05-16 20:24:31 +02:00
1 parent 2a3fb0e913
commit 3d309bb91b
2 files changed
+105

No files matched your search

@@ -0,0 +1,45 @@
-- v1.4.34 — Apple Health export.zip import jobs
--
-- Additive-only — one new table mirroring the lifecycle of a pg-boss
-- `apple-health-import` job. The polling endpoint reads from this
-- table so the operator sees live per-phase progress rather than the
-- one-shot terminal `output` column on `pg_boss.job` (v12 contract).
--
-- `pg_boss_job_id` is nullable so the `INSERT` can land before the
-- kick-off route gets the boss id back from `boss.send`. The unique
-- index covers the populated rows; NULL values are distinct under
-- the default Postgres semantics so two pre-send rows never collide.
--
-- Locks per `.planning/research/v1434-r-1-xml-import.md` §5.2.
CREATE TABLE IF NOT EXISTS "import_jobs" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"triggered_by_admin_id" TEXT,
"pg_boss_job_id" TEXT,
"status" TEXT NOT NULL DEFAULT 'queued',
"failure_reason" TEXT,
"upload_bytes" INTEGER NOT NULL,
"upload_sha256" TEXT,
"exported_at" TIMESTAMP(3),
"started_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"completed_at" TIMESTAMP(3),
"progress" JSONB NOT NULL DEFAULT '{}'::jsonb,
"result" JSONB,
CONSTRAINT "import_jobs_pkey" PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX IF NOT EXISTS "import_jobs_pg_boss_job_id_key"
ON "import_jobs" ("pg_boss_job_id");
CREATE INDEX IF NOT EXISTS "import_jobs_user_id_started_at_idx"
ON "import_jobs" ("user_id", "started_at");
CREATE INDEX IF NOT EXISTS "import_jobs_status_idx"
ON "import_jobs" ("status");
ALTER TABLE "import_jobs"
ADD CONSTRAINT "import_jobs_user_id_fkey"
FOREIGN KEY ("user_id") REFERENCES "users"("id")
ON DELETE CASCADE ON UPDATE CASCADE;