diff --git a/backend/db.py b/backend/db.py index 1542c26..78e1a1f 100644 --- a/backend/db.py +++ b/backend/db.py @@ -106,6 +106,7 @@ CREATE TABLE IF NOT EXISTS leitner( CREATE TABLE IF NOT EXISTS befunde( id INTEGER PRIMARY KEY, run_id INTEGER NOT NULL, ebene TEXT NOT NULL, art TEXT NOT NULL, item TEXT DEFAULT '', detail TEXT DEFAULT '', status TEXT NOT NULL DEFAULT 'offen'); +CREATE INDEX IF NOT EXISTS idx_befunde_run ON befunde(run_id, ebene); CREATE TABLE IF NOT EXISTS lernstand( topic TEXT NOT NULL, baustein_id INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'aktiv', xp INTEGER NOT NULL DEFAULT 0, diff --git a/backend/main.py b/backend/main.py index 04767a5..b6b524c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -125,6 +125,18 @@ async def lauf_stop(topic: str): return {"ok": True} +def _befunde_aktuell(topic: str) -> list[dict]: + """Offene Befunde des jeweils jüngsten Laufs je Ebene — in zwei billigen Pässen.""" + neueste = db.query( + "SELECT b.ebene, MAX(b.run_id) AS run_id FROM befunde b" + " JOIN runs r ON r.id=b.run_id WHERE r.topic=? GROUP BY b.ebene", (topic,)) + out: list[dict] = [] + for ne in neueste: + out += db.query("SELECT * FROM befunde WHERE run_id=? AND ebene=?" + " AND status='offen' ORDER BY id", (ne["run_id"], ne["ebene"])) + return out + + @app.get("/api/topics/{topic}/state") def state(topic: str): t = db.one("SELECT * FROM topics WHERE name=?", (topic,)) @@ -153,16 +165,11 @@ def state(topic: str): "bausteine": db.query( "SELECT b.*, s.stage FROM bausteine b LEFT JOIN sections s ON s.baustein_id=b.id" " WHERE b.topic=? ORDER BY b.ord", (topic,)), - # Je Ebene nur der JÜNGSTE Messstand: offene Befunde älterer Läufe sind - # veraltete Momentaufnahmen (aak: 1244 Anker-Leichen bei 0 echten) — der - # letzte Lauf, der die Ebene gemessen hat, ist die Wahrheit. - "befunde": db.query( - "SELECT b.* FROM befunde b JOIN runs r ON r.id=b.run_id" - " WHERE r.topic=? AND b.status='offen'" - " AND b.run_id = (SELECT MAX(b2.run_id) FROM befunde b2" - " JOIN runs r2 ON r2.id=b2.run_id" - " WHERE r2.topic=? AND b2.ebene=b.ebene)" - " ORDER BY b.id", (topic, topic)), + # Je Ebene nur der JÜNGSTE Messstand (veraltete Läufe sind Momentaufnahmen). + # ENTKORRELIERT: erst MAX(run_id) je Ebene, dann gezielte Lookups — der + # korrelierte Subquery brauchte 874 ms und staute hinter db._lock den + # ganzen Server (state wird bei jedem Poll/WS-Push gerufen). + "befunde": _befunde_aktuell(topic), "agenten": agents.aktive_agenten(), }