db: Prisma-Migrations-System statt db push (datenerhaltend)

`db push --accept-data-loss` konnte bei Schema-Änderungen still Daten verlieren
(Renames, Type-Changes, NOT NULL ohne Default). Umstellung auf versionierte
Migrations:

- 0_init aus aktuellem Schema generiert (alte gedriftete Migrations entfernt)
- entrypoint: Auto-Baseline für bestehende DBs ohne `_prisma_migrations`,
  dann `migrate deploy` (idempotent, kein Daten-Loss)
- npm run schema:sync: legt automatisch eine Migration mit Zeitstempel an
  (`prisma migrate dev --name auto_<ts>`)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 17:02:35 +02:00
parent 6f293211a4
commit 27a0fdbc45
29 changed files with 1067 additions and 885 deletions
+60 -6
View File
@@ -1,6 +1,10 @@
#!/bin/sh
# Beim Container-Start: Schema in DB pushen (idempotent) + (optional) seed.
# RUN_SEED=true beim ersten Start setzen, danach wieder auf false.
# Container-Start:
# 1) Auf DB warten
# 2) Auto-Baseline für bestehende DBs (db-push-Ära ohne _prisma_migrations)
# 3) `prisma migrate deploy` (idempotent, datenerhaltend)
# 4) Auto-Seed bei leerer User-Tabelle (oder RUN_SEED=true)
# Neue Schema-Änderung anlegen (lokal, im Dev): npm run schema:sync
set -e
# DATABASE_URL aus DB_*-Komponenten bauen, falls nicht explizit gesetzt.
@@ -21,10 +25,16 @@ if [ -z "$DATABASE_URL" ] && [ -n "$DB_USER" ] && [ -n "$DB_PASSWORD" ] && [ -n
fi
echo "[entrypoint] Warte auf Datenbank…"
# Prisma versucht selbst Connect; einfacher Retry-Loop um Race-Bedingungen
# beim parallelen Container-Start abzufangen.
# Erst auf DB-Verfügbarkeit warten via einfachem Connect-Check.
# Wir nutzen Prisma's interne Engine, kein extra mysql-client nötig.
TRIES=30
until npx prisma db push --skip-generate --accept-data-loss 2>/dev/null; do
until node -e "
const { PrismaClient } = require('@prisma/client');
const p = new PrismaClient();
p.\$queryRaw\`SELECT 1\`
.then(() => p.\$disconnect().then(() => process.exit(0)))
.catch(() => process.exit(1));
" 2>/dev/null; do
TRIES=$((TRIES - 1))
if [ "$TRIES" -le 0 ]; then
echo "[entrypoint] DB nicht erreichbar Abbruch"
@@ -33,7 +43,51 @@ until npx prisma db push --skip-generate --accept-data-loss 2>/dev/null; do
echo "[entrypoint] DB noch nicht bereit retry in 2s ($TRIES Versuche übrig)"
sleep 2
done
echo "[entrypoint] DB-Schema synced"
echo "[entrypoint] DB erreichbar"
# Auto-Baseline: Wenn die DB Anwendungs-Tabellen enthält (z.B. User), aber noch
# keine _prisma_migrations-Tabelle, dann ist es eine "alte" DB, die früher mit
# `prisma db push` synced wurde. Wir markieren 0_init als bereits angewendet,
# damit `migrate deploy` nicht versucht, alle Tabellen nochmal anzulegen.
NEEDS_BASELINE=$(node -e "
const { PrismaClient } = require('@prisma/client');
const p = new PrismaClient();
(async () => {
try {
const dbName = process.env.DB_NAME;
const tables = await p.\$queryRawUnsafe(
\`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?\`,
dbName
);
const names = tables.map(t => t.TABLE_NAME);
const hasMigrations = names.includes('_prisma_migrations');
const hasUserTable = names.includes('User');
// Existing DB (User da) ohne Migrations-Tracking => Baseline nötig
if (hasUserTable && !hasMigrations) process.stdout.write('yes');
else process.stdout.write('no');
} catch (e) {
process.stdout.write('no');
} finally {
await p.\$disconnect();
}
})();
" 2>/dev/null)
if [ "$NEEDS_BASELINE" = "yes" ]; then
echo "[entrypoint] Bestehende DB ohne Migrations-Tracking erkannt markiere 0_init als angewendet (Baseline)"
npx prisma migrate resolve --applied 0_init || echo "[entrypoint] Baseline fehlgeschlagen fahre trotzdem fort"
fi
# Migrations anwenden (idempotent: bereits angewendete werden übersprungen).
# Im Gegensatz zu `db push` löscht `migrate deploy` keine Daten — Schema-
# Änderungen werden über versionierte Migrations-Files unter prisma/migrations/
# eingespielt. Neue Migration anlegen mit: npm run schema:sync (lokal, dev).
echo "[entrypoint] Wende Migrations an…"
if ! npx prisma migrate deploy; then
echo "[entrypoint] migrate deploy fehlgeschlagen Abbruch"
exit 1
fi
echo "[entrypoint] DB-Schema aktuell"
# Auto-Seed: wenn die User-Tabelle leer ist (= Erstinstallation), automatisch seeden.
# RUN_SEED=true erzwingt Seed auch bei nicht-leerer DB (z.B. nach Reset).