Backend Sprint 2+3: Health-Modul, Multi-Dog Tagebuch, Pillow, Migrations

- database.py: diary_dogs + walk_participant_dogs Tabellen, idempotente
  Migration für Health-Felder (charge_nr, kosten, diagnose, …), Backfill
- routes/health.py: vollständiges Health-Modul (war Stub), CRUD für
  Impfung/Entwurmung/Tierarzt/Medikament/Gewicht/Allergie/Dokument
- routes/diary.py: Multi-Dog n:m via diary_dogs (dog_ids in allen Endpoints)
- routes/dogs.py: Foto-Upload konvertiert HEIC/PNG/WebP → JPEG via Pillow
- routes/poison.py: Resolve mit Grundauswahl + Soft-Delete (geloest_von/at/grund)
- ki.py: health_summary() für KI-Gesundheitsbericht
- main.py: /favicon.ico Route
- requirements.txt: Pillow 11.2.1 + pillow-heif 0.22.0
This commit is contained in:
rene 2026-04-13 19:29:51 +02:00
parent 96e7a97b52
commit 6f48ec581d
8 changed files with 570 additions and 52 deletions

View file

@ -88,6 +88,14 @@ def init_db():
);
CREATE INDEX IF NOT EXISTS idx_diary_dog ON diary(dog_id, datum DESC);
-- TAGEBUCH HUNDE (n:m ein Eintrag kann mehrere Hunde betreffen)
CREATE TABLE IF NOT EXISTS diary_dogs (
diary_id INTEGER NOT NULL REFERENCES diary(id) ON DELETE CASCADE,
dog_id INTEGER NOT NULL REFERENCES dogs(id) ON DELETE CASCADE,
PRIMARY KEY (diary_id, dog_id)
);
CREATE INDEX IF NOT EXISTS idx_diary_dogs_dog ON diary_dogs(dog_id);
-- GESUNDHEIT
CREATE TABLE IF NOT EXISTS health (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -186,6 +194,15 @@ def init_db():
PRIMARY KEY (walk_id, user_id)
);
-- GASSI-TREFFEN HUNDE (n:m Teilnehmer kann mehrere Hunde mitbringen)
CREATE TABLE IF NOT EXISTS walk_participant_dogs (
walk_id INTEGER NOT NULL REFERENCES walks(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
dog_id INTEGER NOT NULL REFERENCES dogs(id) ON DELETE CASCADE,
PRIMARY KEY (walk_id, user_id, dog_id)
);
CREATE INDEX IF NOT EXISTS idx_wpd_dog ON walk_participant_dogs(dog_id);
-- FORUM
CREATE TABLE IF NOT EXISTS forum_threads (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -234,4 +251,48 @@ def init_db():
""")
# Migrations: neue Spalten zu bestehenden Tabellen hinzufügen (idempotent)
_migrate(conn_factory=db)
logger.info("Datenbank initialisiert.")
def _migrate(conn_factory):
"""Fügt fehlende Spalten hinzu und führt Datenmigration durch (idempotent)."""
migrations = [
# Giftköder: Auflösungs-Details für spätere KI-Analyse
("poison", "geloest_von", "INTEGER"),
("poison", "geloest_at", "TEXT"),
("poison", "geloest_grund", "TEXT"),
# Gesundheit: erweiterte Felder je nach Eintragstyp
("health", "charge_nr", "TEXT"),
("health", "tierarzt_name", "TEXT"),
("health", "kosten", "REAL"),
("health", "diagnose", "TEXT"),
("health", "dosierung", "TEXT"),
("health", "haeufigkeit", "TEXT"),
("health", "aktiv", "INTEGER NOT NULL DEFAULT 1"),
("health", "bis_datum", "TEXT"),
("health", "schweregrad", "TEXT"),
("health", "reaktion", "TEXT"),
("health", "datei_url", "TEXT"),
("health", "datei_typ", "TEXT"),
]
with conn_factory() as conn:
for table, column, col_type in migrations:
existing = [
row[1] for row in
conn.execute(f"PRAGMA table_info({table})").fetchall()
]
if column not in existing:
conn.execute(
f"ALTER TABLE {table} ADD COLUMN {column} {col_type}"
)
logger.info(f"Migration: {table}.{column} hinzugefügt.")
# Datenmigration: diary_dogs für bestehende Einträge befüllen
conn.execute("""
INSERT OR IGNORE INTO diary_dogs (diary_id, dog_id)
SELECT id, dog_id FROM diary
""")
logger.info("Migration: diary_dogs Backfill abgeschlossen.")