diff --git a/backend/database.py b/backend/database.py index 01dfc17..ab82594 100644 --- a/backend/database.py +++ b/backend/database.py @@ -189,6 +189,13 @@ def init_db(): ); CREATE INDEX IF NOT EXISTS idx_route_walks_user ON route_walks(user_id); + CREATE TABLE IF NOT EXISTS route_dogs ( + route_id INTEGER NOT NULL REFERENCES routes(id) ON DELETE CASCADE, + dog_id INTEGER NOT NULL REFERENCES dogs(id) ON DELETE CASCADE, + PRIMARY KEY (route_id, dog_id) + ); + CREATE INDEX IF NOT EXISTS idx_route_dogs_dog ON route_dogs(dog_id); + CREATE TABLE IF NOT EXISTS exercise_progress ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, @@ -1974,6 +1981,38 @@ def _migrate(conn_factory): """) logger.info("Migration: futter_profil bereit.") + # Futter-Einträge & Reaktionen (Verträglichkeits-Tracking) + try: + conn.executescript(""" + CREATE TABLE IF NOT EXISTS futter_eintraege ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + dog_id INTEGER NOT NULL REFERENCES dogs(id) ON DELETE CASCADE, + datum TEXT NOT NULL, + uhrzeit TEXT NOT NULL, + futter_name TEXT NOT NULL, + futter_typ TEXT NOT NULL DEFAULT 'trockenfutter', + menge_g INTEGER, + notiz TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + CREATE INDEX IF NOT EXISTS idx_futter_eintraege_dog ON futter_eintraege(dog_id, datum DESC); + + CREATE TABLE IF NOT EXISTS futter_reaktionen ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + dog_id INTEGER NOT NULL REFERENCES dogs(id) ON DELETE CASCADE, + datum TEXT NOT NULL, + uhrzeit TEXT NOT NULL, + reaktion_typ TEXT NOT NULL, + intensitaet INTEGER NOT NULL DEFAULT 3, + notiz TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + CREATE INDEX IF NOT EXISTS idx_futter_reaktionen_dog ON futter_reaktionen(dog_id, datum DESC); + """) + logger.info("Migration: futter_eintraege + futter_reaktionen bereit.") + except Exception as e: + logger.warning(f"Migration futter_eintraege/reaktionen: {e}") + # Wiederkehrende Ausgaben (Daueraufträge) conn.executescript(""" CREATE TABLE IF NOT EXISTS recurring_expenses ( @@ -2104,6 +2143,85 @@ def _migrate(conn_factory): except Exception: pass # Spalte existiert bereits + # exercise_progress + training_plan_progress: dog_id ergänzen + existing_ep = [r[1] for r in conn.execute("PRAGMA table_info(exercise_progress)").fetchall()] + if 'dog_id' not in existing_ep: + try: + # Neue Tabelle mit dog_id erstellen + conn.execute(""" + CREATE TABLE exercise_progress_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + dog_id INTEGER REFERENCES dogs(id) ON DELETE CASCADE, + exercise_id TEXT NOT NULL, + status TEXT, + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + UNIQUE(dog_id, exercise_id) + ) + """) + # Bestehende Daten migrieren: dog_id = erster Hund des Users + conn.execute(""" + INSERT INTO exercise_progress_new (user_id, dog_id, exercise_id, status, updated_at) + SELECT ep.user_id, + (SELECT id FROM dogs WHERE user_id=ep.user_id ORDER BY id LIMIT 1), + ep.exercise_id, ep.status, ep.updated_at + FROM exercise_progress ep + """) + conn.execute("DROP TABLE exercise_progress") + conn.execute("ALTER TABLE exercise_progress_new RENAME TO exercise_progress") + conn.execute("CREATE INDEX IF NOT EXISTS idx_exercise_progress_user ON exercise_progress(user_id)") + conn.execute("CREATE INDEX IF NOT EXISTS idx_exercise_progress_dog ON exercise_progress(dog_id)") + logger.info("Migration: exercise_progress.dog_id hinzugefügt.") + except Exception as e: + logger.warning(f"Migration exercise_progress.dog_id fehlgeschlagen: {e}") + + existing_tp = [r[1] for r in conn.execute("PRAGMA table_info(training_plan_progress)").fetchall()] + if 'dog_id' not in existing_tp: + try: + conn.execute(""" + CREATE TABLE training_plan_progress_new ( + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + dog_id INTEGER REFERENCES dogs(id) ON DELETE CASCADE, + item_key TEXT NOT NULL, + checked INTEGER NOT NULL DEFAULT 1, + checked_at TEXT NOT NULL DEFAULT (datetime('now')), + PRIMARY KEY (dog_id, item_key) + ) + """) + conn.execute(""" + INSERT INTO training_plan_progress_new (user_id, dog_id, item_key, checked, checked_at) + SELECT tp.user_id, + (SELECT id FROM dogs WHERE user_id=tp.user_id ORDER BY id LIMIT 1), + tp.item_key, tp.checked, tp.checked_at + FROM training_plan_progress tp + """) + conn.execute("DROP TABLE training_plan_progress") + conn.execute("ALTER TABLE training_plan_progress_new RENAME TO training_plan_progress") + logger.info("Migration: training_plan_progress.dog_id hinzugefügt.") + except Exception as e: + logger.warning(f"Migration training_plan_progress.dog_id fehlgeschlagen: {e}") + + # verstorben_am: Hund als verstorben markierbar + try: + conn.execute("ALTER TABLE dogs ADD COLUMN verstorben_am TEXT") + logger.info("Migration: dogs.verstorben_am hinzugefügt.") + except Exception: + pass + + # route_dogs: bestehende Routen allen Hunden des Users zuweisen + try: + existing = conn.execute("SELECT COUNT(*) FROM route_dogs").fetchone()[0] + if existing == 0: + conn.execute(""" + INSERT OR IGNORE INTO route_dogs (route_id, dog_id) + SELECT r.id, d.id + FROM routes r + JOIN dogs d ON d.user_id = r.user_id + """) + logger.info("Migration: route_dogs mit bestehenden Routen befüllt.") + except Exception as e: + logger.warning(f"Migration route_dogs fehlgeschlagen: {e}") + def _seed_help_articles(conn): """Befüllt help_articles mit Starter-FAQs — nur wenn die Tabelle noch leer ist.""" diff --git a/backend/main.py b/backend/main.py index dc86828..00027f4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1414,7 +1414,7 @@ async def ausweis_page(dog_id: int, request: Request):