mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md
Lars 532e17c4cd
All checks were successful
Deploy Development / deploy (push) Successful in 1m5s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 24s
feat: add Jinkendo Foundation design principles documentation
- Introduced a new section for the Jinkendo Foundation, detailing design principles for the product family.
- Updated README files to include references to the new design principles documentation.
- Enhanced the overall documentation structure to improve navigation and accessibility of design resources.
- Ensured consistency across documentation related to the Jinkendo Foundation and its principles.
2026-07-22 11:11:07 +02:00

15 KiB
Raw Blame History

Migration & Deploy Designprinzipien (Extraktion)

Status: Analyse / Arbeitspapier
Stand: 2026-07-04
Geltungsbereich: DB-Migrationen, Container-Startup, CI/CD-Deploy — keine Anwendungsdomäne

Serie: Designprinzipien für Produktfamilie · Dokument 9 von n (Abschluss)
Vorgänger: NAVIGATION_IA_DESIGN_PRINCIPLES.md

Kernkomponenten:

Bereich Pfade
DB-Init & Migrationen backend/db_init.py, backend/startup.sh
Migrationen backend/migrations/XXX_*.sql
Basis-Schema (Greenfield) backend/schema.sql
Tracking Tabelle schema_migrations
Compose Prod/Dev docker-compose.yml, docker-compose.dev-env.yml
CI/CD .gitea/workflows/deploy-dev.yml, deploy-prod.yml, test.yml
Versionierung backend/version.py (APP_VERSION, DB_SCHEMA_VERSION, MODULE_VERSIONS)
Doku (operativ) MIGRATIONS.md
Architektur-Regeln .claude/rules/ARCHITECTURE.md §2, §7

Modul

Migration & Deploy

Automatische PostgreSQL-Schema-Evolution beim Container-Start plus Git-getriebene Deploy-Pipeline (develop → Dev, main → Prod) auf selbst-gehosteter Infrastruktur (Docker auf Raspberry Pi).


Fachliche Verantwortung

Das Modul übernimmt:

  1. Schema-Migrationen — Nummerierte SQL-Dateien, idempotent wo möglich, getrackt in schema_migrations.
  2. Startup-Orchestrierung — Postgres ready → Schema/Migrationen → optional SQLite-Import → Uvicorn.
  3. Umgebungstrennung — Dev (3099/8099) vs. Prod (3002/8002), getrennte DBs/Volumes.
  4. Deploy-Automatisierung — Push auf Branch → Runner → git reset --harddocker compose build --no-cache → Health-Check.
  5. Post-Deploy-Tests — Pytest/Lint/Frontend-Build gegen deployed Container auf dem Runner.
  6. Versions-Metadaten — App-/Modul-Version und dokumentierte DB_SCHEMA_VERSION.

Es übernimmt nicht:

  • Fachliche Datenberechnungen (→ Data Layer)
  • Automatisches Downgrade/Rollback von Schema
  • Blue-Green oder Multi-Region-Deploy

Deploy-Pipeline (Happy Path)

Entwickler: commit → push develop
  → Gitea Runner: deploy-dev.yml
      → cd /home/lars/docker/bodytrack-dev
      → git fetch + reset --hard origin/develop
      → docker compose -f docker-compose.dev-env.yml build --no-cache && up -d
      → backend startup.sh → db_init.py (Migrationen)
      → curl localhost:8099/api/auth/status
  → test.yml (push + nach Deploy): pytest im Container, py_compile, npm run build

Prod: PR develop → main → deploy-prod.yml (Port 8002, bodytrack/)

Administrierte vs. code-definierte Konfiguration

Konfiguration Speicherort Wer pflegt?
Migration-SQL backend/migrations/ Entwickler
Welche Migrationen angewendet schema_migrations (DB) Automatisch
Greenfield-Basis schema.sql Entwickler (selten)
Compose/Ports/Env docker-compose*.yml, .env auf Server Betrieb
Deploy-Workflow .gitea/workflows/*.yml Entwickler
App-Version / Changelog backend/version.py Entwickler (pro Release)
Prod-Geheimnisse Server-.env, nicht im Repo Betrieb

Designprinzipien

1. Migrationen beim Container-Start ( nicht manuell in Prod)

Prinzip startup.sh ruft db_init.py auf bevor Uvicorn startet; pending Migrationen werden automatisch angewendet.
Begründung Kein vergessenes Schema-Update; Deploy und DB-Stand bleiben gekoppelt.
Quelle startup.sh, db_init.py
Tragfähigkeit hoch
Einschränkung Fehlgeschlagene Migration blockiert API-Start (sys.exit(1)).

2. Nummeriertes Datei-Pattern als Gate

Prinzip Nur \d{3}_*.sql wird ausgeführt (z. B. 054_activity_session_metrics_eav.sql); alles andere wird ignoriert.
Begründung Sortierbare Reihenfolge; Ad-hoc-Skripte (check_features.sql, v9c_*.sql) verunreinigen nicht den Lauf.
Quelle run_migrations() Regex
Tragfähigkeit hoch
Einschränkung Legacy-Dateien ohne Nummer liegen noch im Ordner (historischer Ballast).

3. Tracking-Tabelle als Single Source of „applied“

Prinzip schema_migrations(filename) — jede erfolgreiche Datei genau einmal eingetragen; Pending = Dateien minus Applied.
Begründung Idempotenter Startup; wiederholter Container-Start wendet nichts doppelt an.
Quelle ensure_migration_table, apply_migration
Tragfähigkeit hoch
Einschränkung Kein checksum — geänderte Datei nach Apply wird nicht erneut ausgeführt.

4. Alphabetische Reihenfolge = Migrations-Reihenfolge

Prinzip sorted(glob) — dreistellige Präfixe (001, 054, 061) definieren die Apply-Order.
Begründung Einfach, git-freundlich, keine separate Migrations-Registry.
Quelle run_migrations()
Tragfähigkeit hoch
Einschränkung Nummern-Kollisionen oder nachträgliches Einfügen erfordern Disziplin (immer nächste freie Nummer).

5. Fail-Fast bei Migrationsfehler

Prinzip Schlägt eine Migration fehl → kein Commit in Tracking (bei Exception vor INSERT), Prozess exit 1, Container unhealthy.
Begründung API läuft nicht mit halb angewendetem Schema.
Quelle apply_migration, main in db_init.py
Tragfähigkeit hoch
Einschränkung Manueller Recovery-Prozess nötig (siehe MIGRATIONS.md Rollback).

6. Greenfield: schema.sql, Bestand: nur Migrationen

Prinzip Existiert profiles nicht → einmalig schema.sql laden; danach nur noch nummerierte Migrationen.
Begründung Frische Instanz schnell bootstrapped; langlebige DBs evolvieren incremental.
Quelle check_table_exists, load_schema
Tragfähigkeit hoch
Einschränkung schema.sql kann hinter Migrationen zurückfallen wenn nicht gepflegt.

7. Idempotente DDL bevorzugen

Prinzip ADD COLUMN IF NOT EXISTS, CREATE INDEX IF NOT EXISTS, defensive UPDATEs — Migration soll mehrfach ausführbar sein ohne Schaden.
Begründung Recovery nach partiellem Apply; manuelles Re-Run sicherer.
Quelle MIGRATIONS.md Best Practices
Tragfähigkeit hoch
Einschränkung Nicht alle Änderungen sind idempotent (DROP, irreversible Datenmigration).

8. Kein psql-Meta in Migrationsdateien

Prinzip Nur SQL — kein \echo, \i, \connect; Ausführung via psycopg2, nicht interaktiv.
Begründung Parser/Runner versteht nur SQL-Statements.
Quelle MIGRATIONS.md, apply_migration
Tragfähigkeit hoch
Einschränkung

9. Schema-Änderung = nummerierte Migration (nie ad-hoc in Prod)

Prinzip Neue Tabellen/Spalten nur via backend/migrations/XXX_*.sql; nicht direkt in laufender Prod-DB editieren.
Begründung Reproduzierbarkeit Dev→Prod; Review im Git-Diff.
Quelle ARCHITECTURE.md, CLAUDE.md
Tragfähigkeit hoch
Einschränkung Agent-Regel — technisch nicht erzwungen.

10. DB_SCHEMA_VERSION als dokumentierter Marker

Prinzip backend/version.pyDB_SCHEMA_VERSION bei Schema-Änderung manuell bumpen (Format z. B. YYYYMMDD + Suffix).
Begründung API /api/version und Changelog zeigen Schema-Stand unabhängig von App-Minor.
Quelle ARCHITECTURE.md §2.6
Tragfähigkeit mittelhoch
Einschränkung Nicht automatisch aus schema_migrations abgeleitet — Drift möglich.

11. Branch → Umgebung (develop / main)

Prinzip develop → Dev-Deploy automatisch; main → Prod-Deploy automatisch; Prod nur nach expliziter Freigabe/Merge.
Begründung Klare Promotion; Dev als Integrationsumgebung.
Quelle Workflows, CLAUDE.md Deployment
Tragfähigkeit hoch
Einschränkung Kein Staging-Branch zwischen Dev und Prod.

12. Deploy-Arbeitskopie = exakt Remote-Branch

Prinzip Runner: git fetch + git reset --hard origin/<branch> — keine pull-Merge-Konflikte, kein schmutziger package-lock auf dem Pi.
Begründung Reproduzierbarer Deploy-Baum; Fix aus GUI-IA-Abnahme 2026-04-05.
Quelle deploy-prod.yml, deploy-dev.yml
Tragfähigkeit hoch
Einschränkung Lokale Hotfixes auf dem Server werden beim Deploy überschrieben.

13. Immutabler Build pro Deploy (--no-cache)

Prinzip docker compose build --no-cache bei jedem Deploy — frisches Image aus Dockerfile + Repo-Stand.
Begründung Keine veralteten Layer; Migrationen und Code garantiert im Image.
Quelle Deploy-Workflows
Tragfähigkeit hoch
Einschränkung Langsamere Deploys; kein Registry-basiertes Image-Promotion.

14. Health-Check nach Deploy

Prinzip Nach up -d: kurz warten, dann curl -sf …/api/auth/status (8099 Dev / 8002 Prod).
Begründung Minimale Smoke-Verification dass API antwortet (inkl. DB-Init durchlaufen).
Quelle Deploy-Workflows
Tragfähigkeit mittelhoch
Einschränkung Prüft nicht fachliche Endpoints oder Migration-Inhalt.

15. Persistente Volumes für Daten und Fotos

Prinzip Postgres-Daten, /app/data, /app/photos in benannten/external Volumes — überleben Container-Rebuild.
Begründung Deploy = neues Image, nicht Datenverlust.
Quelle docker-compose*.yml
Tragfähigkeit hoch
Einschränkung Volume-Backup/Restore ist Betriebsaufgabe außerhalb Repo.

16. Postgres Healthcheck vor Backend-Start

Prinzip depends_on: condition: service_healthy — Backend startet erst wenn DB pg_isready.
Begründung wait_for_postgres in db_init ist zweite Absicherung; reduziert Race beim ersten Start.
Quelle Compose-Files
Tragfähigkeit hoch
Einschränkung

17. Tests gegen deployed Stack (Self-Hosted Runner)

Prinzip test.yml führt pytest im laufenden Backend-Container auf dem Pi aus, nicht in isolierter GitHub-Cloud.
Begründung Tests laufen gegen echte Dev/Prod-Compose-Umgebung des Projekts.
Quelle .gitea/workflows/test.yml
Tragfähigkeit mittel
Einschränkung Prod-Deploy triggert Tests auf Prod-Pfad — Risiko wenn Tests schreibend; -m 'not slow' begrenzt Laufzeit.

18. Feste Ports pro Umgebung

Prinzip Dev 3099/8099, Prod 3002/8002 — nicht ändern (Reverse Proxy/Fritz!Box hängen daran).
Begründung Externe URLs (dev.mitai.jinkendo.de, mitai.jinkendo.de) stabil.
Quelle CLAUDE.md, Compose
Tragfähigkeit hoch (betriebsspezifisch)
Einschränkung Andere Projekte brauchen eigene Port-Matrix.

19. Prod-Schutz: Deploy nur über Git

Prinzip Keine direkten Prod-Container-/DB-Schreibzugriffe für Automation; Prod-Änderung = Merge main → Workflow.
Begründung Audit-Trail, Review, keine Drift.
Quelle ARCHITECTURE.md §7.1, /deploy Command
Tragfähigkeit hoch
Einschränkung Menschlicher SSH-Zugriff bleibt möglich — Prozess, nicht Technik.

20. Versions-Bump als Release-Disziplin

Prinzip Jede lieferbare Änderung: APP_VERSION, betroffene MODULE_VERSIONS, CHANGELOG in version.py; bei Schema auch DB_SCHEMA_VERSION.
Begründung /api/version, Support, Korrelation Deploy ↔ Code.
Quelle ARCHITECTURE.md §2.5, deploy.md
Tragfähigkeit hoch
Einschränkung Frontend-version.js in Spec erwähnt, im Repo teils nicht vorhanden — Dual-Bump unvollständig.

Nicht übernehmen

  1. Unnummerierte Migrationsdateienv9c_*.sql, check_*.sql werden nicht auto-applied; nicht als Vorbild.

  2. Migration-Datei nach Apply ändern — Tracking verhindert Re-Run; neue Nummer statt Edit.

  3. Automatischer Downgrade — nicht implementiert; Rollback manuell + Tracking-Eintrag löschen.

  4. Direktes Schema in Prod — immer Git-Migration + Deploy.

  5. Breaking DROP ohne Koordination — App-Code und Migration in einem Release.

  6. psql-Metacommands in .sql — bricht Python-Runner.

  7. git pull auf Deploy-Server — Merge-Schmutz; reset --hard ist das Muster.

  8. Prod-Deploy ohne Dev-Validierung — develop-First ist implizite Policy.

  9. Schema-Drift ohne DB_SCHEMA_VERSION-Bump — dokumentarische Lücke.

  10. Cached Docker-Build als Default — Mitai wählt Reproduzierbarkeit über Geschwindigkeit.

  11. Migrationen außerhalb Container-Start vergessen — manuelles psql in Prod als Normalfall.

  12. Hardcoded Seed-Daten in Migration — produktive User/Secrets nicht in SQL.

  13. Port-Änderung „nebenbei“ — Infrastruktur-Kopplung.

  14. Tests nur lokal, nie auf Runner-Stack — Mitai testet bewusst post-deploy im Pi-Container (Trade-off verstehen).

  15. Transaktionssteuerung in SQL-Datei — Runner committet pro Datei; komplexe multi-step Rollbacks nicht eingebaut.


Modul-Inventar (Ist-Stand)

backend/
├── db_init.py           # wait, schema, run_migrations, sqlite import
├── startup.sh           # db_init → uvicorn
├── schema.sql           # Greenfield
├── migrations/          # 001061+ nummeriert (+ Legacy ohne Nummer)
└── version.py           # APP_VERSION, DB_SCHEMA_VERSION, MODULE_VERSIONS

docker-compose.yml           # Prod: 3002/8002
docker-compose.dev-env.yml   # Dev: 3099/8099

.gitea/workflows/
├── deploy-dev.yml       # push develop
├── deploy-prod.yml      # push main
└── test.yml             # pytest, lint, npm build on Pi

Server (Pi):
/home/lars/docker/bodytrack-dev/   # develop
/home/lars/docker/bodytrack/       # main

Migrationen (Stand): 60+ nummerierte Dateien (001061); höchste Nummer im Repo prüfen vor neuer Migration.


Verwandte Dokumentation


Serie Übersicht (abgeschlossen)

# Modul Status
1 Prompt Engine PROMPT_ENGINE_DESIGN_PRINCIPLES.md
2 Data Layer DATA_LAYER_DESIGN_PRINCIPLES.md
3 Feature & Entitlement FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md
4 Registry / Plugin (Meta) REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md
5 Auth & Session AUTH_SESSION_DESIGN_PRINCIPLES.md
6 Universal Import UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md
7 Dashboard Widgets DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md
8 Navigation / IA NAVIGATION_IA_DESIGN_PRINCIPLES.md
9 Migration & Deploy dieses Dokument