27a0fdbc45
`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>
114 lines
4.6 KiB
Bash
Executable File
114 lines
4.6 KiB
Bash
Executable File
#!/bin/sh
|
||
# 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.
|
||
# Wichtig: encodeURIComponent für DB_USER + DB_PASSWORD, damit Sonderzeichen
|
||
# wie $, !, #, @, :, / etc. nicht die URL-Authority-Syntax brechen.
|
||
# Wir nutzen node-eval (ist eh installiert), kein extra-Tool wie jq nötig.
|
||
if [ -z "$DATABASE_URL" ] && [ -n "$DB_USER" ] && [ -n "$DB_PASSWORD" ] && [ -n "$DB_NAME" ]; then
|
||
DATABASE_URL=$(node -e "
|
||
const u = encodeURIComponent(process.env.DB_USER);
|
||
const p = encodeURIComponent(process.env.DB_PASSWORD);
|
||
const h = process.env.DB_HOST || 'db';
|
||
const port = process.env.DB_PORT || '3306';
|
||
const n = process.env.DB_NAME;
|
||
process.stdout.write(\`mysql://\${u}:\${p}@\${h}:\${port}/\${n}\`);
|
||
")
|
||
export DATABASE_URL
|
||
echo "[entrypoint] DATABASE_URL aus DB_*-Komponenten gebaut (host=${DB_HOST:-db})"
|
||
fi
|
||
|
||
echo "[entrypoint] Warte auf Datenbank…"
|
||
# 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 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"
|
||
exit 1
|
||
fi
|
||
echo "[entrypoint] DB noch nicht bereit – retry in 2s ($TRIES Versuche übrig)"
|
||
sleep 2
|
||
done
|
||
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).
|
||
USER_COUNT=$(node -e "
|
||
const { PrismaClient } = require('@prisma/client');
|
||
const p = new PrismaClient();
|
||
p.user.count()
|
||
.then((n) => { process.stdout.write(String(n)); process.exit(0); })
|
||
.catch(() => { process.stdout.write('-1'); process.exit(0); });
|
||
" 2>/dev/null)
|
||
|
||
if [ "${RUN_SEED:-false}" = "true" ]; then
|
||
echo "[entrypoint] RUN_SEED=true – seede DB (Force)"
|
||
npx prisma db seed || echo "[entrypoint] Seed fehlgeschlagen oder schon gelaufen – ignoriert"
|
||
elif [ "$USER_COUNT" = "0" ]; then
|
||
echo "[entrypoint] DB ist leer (User-Count=0) – Auto-Seed wird ausgeführt"
|
||
npx prisma db seed || echo "[entrypoint] Auto-Seed fehlgeschlagen – ignoriert"
|
||
else
|
||
echo "[entrypoint] DB enthält $USER_COUNT User – kein Seed nötig"
|
||
fi
|
||
|
||
echo "[entrypoint] Starte Backend…"
|
||
exec "$@"
|