Fix #33: adopt a Prisma migrations workflow#76
Merged
Conversation
Un-gitignore prisma/migrations and commit a squashed `init` baseline that exactly reproduces the current db-push schema, so the schema history lives in version control and prod can be brought forward with `prisma migrate deploy`. - .gitignore: drop `/prisma/migrations`; carve `!prisma/migrations/**/*.sql` out of the `*.sql` dump-block (#29) so migration SQL is tracked but raw dumps stay ignored. - prisma/migrations/20260710023845_init: baseline migration; verified its applied schema is byte-identical to `prisma db push` (only Prisma's own _prisma_migrations table differs). - dockerfile + docker-entrypoint.sh: install the pinned prisma CLI (+dotenv) into the final image and run `prisma migrate deploy` at container start before booting the server (idempotent no-op once up to date). - package.json: replace the broken `prisma:reset` with migration-aware scripts (prisma:migrate / prisma:deploy / prisma:reset). - CLAUDE.md: document the new workflow. The e2e harness still provisions its throwaway DB with `db push` (unchanged); full suite green (29 files / 111 tests). Requires a one-time human step against the LIVE prod DB (see PR body): `prisma migrate resolve --applied 20260710023845_init`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 10, 2026
* Fix #27: soft deletes for auditability Add deletedAt to Ride/User/Client/Volunteer (plus deletedEmail/deletedPhone on User to preserve released contact values). DELETE endpoints now archive rows instead of destroying them, releasing the unique email/phone so records can be re-added. Active read paths filter deletedAt: null; metrics endpoints deliberately do not, preserving historical totals. Soft-deleted users are blocked from logging in. Migration 20260710035425_add_soft_deletes is additive (nullable ADD COLUMN). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Guard PUT/estimate paths against soft-deleted records (#27 review) Address code-review follow-ups: PUT clients/volunteers and the ride estimate endpoint now treat an archived record as 404 (findFirst with deletedAt: null), so soft-deleted rows can't be edited or re-surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Revoke sessions on soft-delete; filter deletedAt on all volunteer lookups (#27 review) Address independent-review HIGH findings: - Session revocation: hard delete used to cascade to the session table (auth onDelete: Cascade), logging the user out. Soft-delete now deletes the user's session rows in the same transaction (admins/clients/volunteers), so an archived user's live cookie no longer retains API access — closing the gap in the decision-#1 login block. - Filter deletedAt: null on the volunteer lookups that resolve by userId from a session (signup, unsignup, bySession status/reminders/notifications) so a stale session can't act as an archived volunteer. - Guard the soft-delete update where-clauses (clients/volunteers) with deletedAt: null so a double-delete can't overwrite deletedEmail/deletedPhone. New regression test: "revokes sessions on soft-delete" — a previously valid volunteer cookie is rejected with 401 on GET /api/get/rides after the volunteer is archived, and no session rows remain. Fails pre-fix (expected 200 to be 401). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # .gitignore
Contributor
Author
🔀 Merge conflict resolvedMerged
Validated the merged result: Note: this branch now carries #33 (migrations) and #27 (soft deletes), since #79 was merged into this base branch. PRs #77 (#5) and #78 (#14) are still based on the earlier tip and will retarget to |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #33.
Adopts a real Prisma migrations workflow so the schema has reproducible history in version control and prod can be advanced with
prisma migrate deploy— unblocking #14, #27, #28, #5.This PR touches risk files (
prisma/migrations,dockerfile,package.json) and changes the deploy process. Before/right-after merging you must run once against the live prod DB (which already has this schema from the olddb pushprocess):This marks the baseline as already-applied without re-running it, so the entrypoint's
prisma migrate deploysees the DB as up-to-date and is a no-op. Skipping this step would makemigrate deploytry to CREATE tables that already exist and fail. After that one-time resolve, all future schema changes ship as new migrations applied automatically at container start.What changed
.gitignore— removed/prisma/migrations; added!prisma/migrations/**/*.sqlto carve migration SQL out of the*.sqldump-block from Production Database Dump with Real PII and Session Tokens in Public Repo #29 (so migrations are tracked, butprod.sql-style dumps stay ignored — verified both).prisma/migrations/20260710023845_init/— squashed baseline migration (all 10 tables + indexes) generated from the currentprisma/schema/.dockerfile— final stage now also copiesprisma.config.ts, installs the pinnedprismaCLI (+dotenv, which the config loads) into the app root, and copies the entrypoint.CMDis now the entrypoint.docker-entrypoint.sh(new) — runsprisma migrate deploy(vianpx --no-install, so no runtime network fetch), thenexec node .output/server/index.mjs.set -efails fast if a migration errors.package.json— replaced the staleprisma:reset(which regenerated aninitmigration) withprisma:migrate(migrate dev),prisma:deploy(migrate deploy), and a migration-awareprisma:reset(migrate reset --force). No dependency changes.CLAUDE.md— documented the new workflow and the.gitignorecarve-out.Verification done
db push: created one DB viaprisma db pushand one viaprisma migrate deploy, diffed.schema— the 105 application-schema lines match exactly; the only delta is Prisma's own_prisma_migrationsbookkeeping table (expected). This is what makes themigrate resolve --appliedstep safe on prod.migrate deployDB.migrate deployis idempotent — a second run reports "No pending migrations to apply", so container restarts are safe.prisma/+prisma.config.ts+ a freshly-installedprismaCLI runsmigrate deploysuccessfully (mirrors what the final image does).db pushand is unaffected by the committed migrations.Not validated here (please confirm in CI)
node:22-slimcouldn't be pulled). The Dockerfile changes are standard COPY/RUN/CMD steps and the migrate-deploy logic they invoke is validated above, but the actuallinux/arm64image build + a container-start smoke test should be confirmed by the CI build (and ideally a staging run) before this reaches prod. Because mergingmainbuilds+pushes the prod image, consider building the image from this branch first if you want belt-and-suspenders.Notes
migrate deployat container start (not CI) is deliberate: the prod DB is a runtime SQLite file (persistent volume), which CI's build environment can't reach.🤖 Generated with Claude Code