Feature: Trauer-Feature, Futter-Verträglichkeit, Multi-Hund-Fixes, Wetter-Ort (Sprint 47)
- dog-profile.js: Verstorben-Button, Gedenkseite, KI-Abschiedstext - database.py: futter_eintraege/reaktionen, route_dogs, exercise_progress.dog_id - routes/ernaehrung.py: Futter-Verträglichkeit mit 20 Reaktionstypen + Analyse - routes/routen.py: route_dogs Many-to-Many, Routen editierbar - routes/training.py: exercise_progress per dog_id - routes/ki.py: /ki/abschied Trauer-KI - weather.py: Nominatim Ortsname parallel geladen - ui.js: dogChip/bindDogChip, visualViewport-Modal - api.js: gedenken, gedenkseite, futter-Methoden, route_dogs - worlds.js: Ortsname im Wetter-Chip - uebungen.js: _progressLoaded-Flag, dog-spezifischer Fortschritt - trainingsplaene.js: dog_id Unterstützung - diary.js/health.js: P-Badge Cleanup - map.js: Wetter-Ort-Anzeige entfernt - wetter.js: Ort in Wetter-Detail
This commit is contained in:
parent
1ce802c8dc
commit
bda61a0e40
16 changed files with 713 additions and 181 deletions
|
|
@ -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."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue