Fix Task 1 schema in the Prisma plan for exact DDL fidelity

Task 1's reviewer found the original schema.prisma didn't reproduce
db/schema.sql's DDL (DATETIME(3) vs DATETIME, auto-generated index
names, no explicit precision on defaults). Verified the real DDL via
SHOW CREATE TABLE and empirically confirmed @db.DateTime(0) plus
explicit map: names close the gap. Two remaining differences (table
collation, no DB-level ON UPDATE for updatedAt) are Prisma/MySQL
provider limitations with no schema-level fix; documented as
accepted, per user decision, since the baseline never executes this
SQL against the real database and all writes go through Prisma.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 01:04:23 +02:00
co-authored by Claude Sonnet 5
parent d86245a2b1
commit 3f1280be33
@@ -10,7 +10,7 @@
## Global Constraints ## Global Constraints
- `prisma/schema.prisma` must reproduce `db/schema.sql` column-for-column, so the initial migration is a no-op against databases that already have the table (spec: "Schema"). - `prisma/schema.prisma` must reproduce `db/schema.sql` column-for-column, so the initial migration is a no-op against databases that already have the table (spec: "Schema"). Two documented, accepted exceptions where Prisma's MySQL provider has no schema-level equivalent (verified empirically against the real DB's `SHOW CREATE TABLE conversion_jobs`, and confirmed acceptable by the user on 2026-07-31): (1) table collation — the live MariaDB server defaults to `utf8mb4_uca1400_ai_ci` (a MariaDB-specific collation), but Prisma always emits `utf8mb4_unicode_ci` in generated DDL with no schema attribute to override it; (2) `updatedAt`'s `ON UPDATE CURRENT_TIMESTAMP` — Prisma's `@updatedAt` is implemented client-side only for the `mysql` provider and never emits a DB-level `ON UPDATE` clause. Neither has practical impact here: the baseline (Task 3) marks the initial migration applied without ever executing its SQL against the real database, and every write to `conversion_jobs` after this migration goes through Prisma Client, which sets `updatedAt` itself. All other columns (types, defaults, index/constraint names) must match exactly — see Task 1's schema, which uses `@db.DateTime(0)` and explicit `map:` names for this reason.
- `DATABASE_URL` is never written into `.env` or `.env.local` — it is always computed on demand from the existing `DB_HOST`/`DB_USER`/`DB_PASSWORD`/`DB_NAME` variables (spec: "Running Prisma CLI locally"). `.env` holds production credentials and must never be loaded for local work (CLAUDE.md). - `DATABASE_URL` is never written into `.env` or `.env.local` — it is always computed on demand from the existing `DB_HOST`/`DB_USER`/`DB_PASSWORD`/`DB_NAME` variables (spec: "Running Prisma CLI locally"). `.env` holds production credentials and must never be loaded for local work (CLAUDE.md).
- The connection string includes `?connection_limit=10`, preserving the current pool's `connectionLimit: 10` (spec: "Running Prisma CLI locally"). - The connection string includes `?connection_limit=10`, preserving the current pool's `connectionLimit: 10` (spec: "Running Prisma CLI locally").
- `getJobByUuid`, `findPendingJobs`, and `findExpiredJobs` must never expose `errorLog` — only `getJobErrorLog` does (spec: "Data access layer"). - `getJobByUuid`, `findPendingJobs`, and `findExpiredJobs` must never expose `errorLog` — only `getJobErrorLog` does (spec: "Data access layer").
@@ -60,7 +60,7 @@ enum JobStatus {
model ConversionJob { model ConversionJob {
id Int @id @default(autoincrement()) @db.UnsignedInt id Int @id @default(autoincrement()) @db.UnsignedInt
uuid String @unique @db.Char(36) uuid String @unique(map: "uniq_uuid") @db.Char(36)
status JobStatus @default(pending) status JobStatus @default(pending)
family String @db.VarChar(32) family String @db.VarChar(32)
sourceFormat String @map("source_format") @db.VarChar(16) sourceFormat String @map("source_format") @db.VarChar(16)
@@ -69,24 +69,26 @@ model ConversionJob {
inputPath String @map("input_path") @db.VarChar(255) inputPath String @map("input_path") @db.VarChar(255)
outputPath String? @map("output_path") @db.VarChar(255) outputPath String? @map("output_path") @db.VarChar(255)
inputMimeType String @map("input_mime_type") @db.VarChar(128) inputMimeType String @map("input_mime_type") @db.VarChar(128)
outputMimeType String? @map("output_mime_type") @db.VarChar(128) outputMimeType String? @map("output_mime_type") @db.VarChar(128)
inputSizeBytes Int @map("input_size_bytes") @db.UnsignedInt inputSizeBytes Int @map("input_size_bytes") @db.UnsignedInt
outputSizeBytes Int? @map("output_size_bytes") @db.UnsignedInt outputSizeBytes Int? @map("output_size_bytes") @db.UnsignedInt
quality Int? @db.UnsignedSmallInt quality Int? @db.UnsignedSmallInt
conversionDurationSeconds Decimal? @map("conversion_duration_seconds") @db.Decimal(10, 3) conversionDurationSeconds Decimal? @map("conversion_duration_seconds") @db.Decimal(10, 3)
errorMessage String? @map("error_message") @db.VarChar(255) errorMessage String? @map("error_message") @db.VarChar(255)
errorLog String? @map("error_log") @db.Text errorLog String? @map("error_log") @db.Text
createdAt DateTime @default(now()) @map("created_at") createdAt DateTime @default(now()) @map("created_at") @db.DateTime(0)
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.DateTime(0)
expiresAt DateTime @map("expires_at") expiresAt DateTime @map("expires_at") @db.DateTime(0)
cleanedAt DateTime? @map("cleaned_at") cleanedAt DateTime? @map("cleaned_at") @db.DateTime(0)
@@index([status]) @@index([status], map: "idx_status")
@@index([expiresAt]) @@index([expiresAt], map: "idx_expires_at")
@@map("conversion_jobs") @@map("conversion_jobs")
} }
``` ```
`@db.DateTime(0)` matches the real table's `datetime` columns (no fractional seconds) — without it Prisma defaults to `DATETIME(3)`/`CURRENT_TIMESTAMP(3)`, which would both mismatch the existing column type and risk an "Invalid default value" error on a fresh `prisma migrate deploy` (MySQL/MariaDB require the `CURRENT_TIMESTAMP(n)` default's precision to match the column's own precision). The `map: "..."` arguments make Prisma reuse the existing constraint/index names (`uniq_uuid`, `idx_status`, `idx_expires_at`) instead of auto-generating new ones. Verified empirically via `prisma migrate diff --from-empty --to-schema-datamodel` in a scratch directory on 2026-07-31.
- [ ] **Step 3: Add the postinstall script** - [ ] **Step 3: Add the postinstall script**
Edit `package.json`: Edit `package.json`: