--- stepsCompleted: - step-01-validate-prerequisites - step-02-design-epics - step-03-create-stories - step-04-final-validation inputDocuments: - _bmad-output/planning-artifacts/prd.md - _bmad-output/planning-artifacts/architecture.md - _bmad-output/planning-artifacts/ux-design.md bmadSkill: 'PM Agent (John) — /bmad-agent-bmm-pm → [CE] Create Epics and Stories' bmadWorkflow: '_bmad/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md' --- # CouncilOS — Epic & Story Breakdown **Autor:** John (📋 BMAD PM Agent) **Datum:** 2026-03-12 **Version:** 1.0.0 --- ## Anforderungs-Inventar ### Funktionale Anforderungen | ID | Anforderung | |----|-------------| | FR-01.1 | Agent-Nodes per Drag & Drop auf den Canvas | | FR-01.2 | Node-Einstellungs-Panel (Name, System-Prompt, Modell, Tools) | | FR-01.3 | Lineare Edges zwischen Nodes | | FR-01.4 | Bedingte Edges mit Routing-Label | | FR-01.5 | Council unter Namen speichern | | FR-01.6 | Gespeicherten Council laden und bearbeiten | | FR-01.7 | Blueprint-JSON-Export | | FR-02.1 | Prompt-Eingabe als Council-Input | | FR-02.2 | PDF-Upload als Council-Input | | FR-02.3 | Auto-Pilot / God Mode Toggle | | FR-02.4 | Auto-Pilot läuft autonom | | FR-02.5 | God Mode pausiert vor jedem Agent | | FR-02.6 | Finales Dokument anzeigen | | FR-02.7 | Run-Verlauf einsehen | | FR-03.1 | Aktiver Node pulsiert im Canvas | | FR-03.2 | WebSocket-Events mit node_name + status | | FR-03.3 | `done`-Event nach Run-Abschluss | | FR-04.1 | God Mode Approval-Popup | | FR-04.2 | Approve → nächster Node | | FR-04.3 | Reject → Run abbrechen | | FR-04.4 | Modify → Draft bearbeiten vor Fortsetzung | | FR-05.1 | LLM-Modell pro Agent konfigurierbar | | FR-05.2 | Web-Suche optional aktivierbar | | FR-05.3 | PDF-Reader optional aktivierbar | | FR-06.1 | Blueprint-CRUD REST-API | | FR-06.2 | Blueprints in PostgreSQL JSONB | | FR-06.3 | `version`-Feld im Blueprint | ### Nicht-Funktionale Anforderungen | ID | Anforderung | |----|-------------| | NFR-01.1 | WebSocket < 500 ms | | NFR-01.2 | Blueprint-CRUD < 200 ms P95 | | NFR-01.3 | ≥ 10 parallele Runs | | NFR-02.1 | API-Keys nur in Umgebungsvariablen | | NFR-03.1 | Test-Coverage ≥ 80 % agents/, ≥ 90 % state.py | | NFR-03.2 | Alembic für Migrationen | | NFR-03.3 | Dynamischer Graph ab Phase 3 | ### FR-Abdeckungskarte | Epic | Abgedeckte FRs | |------|----------------| | Epic 1 | NFR-01–03, Infrastruktur | | Epic 2 | FR-02.1–02.4, FR-02.6, FR-03.1–03.3 (Phase 1 Backend) | | Epic 3 | FR-01.1–01.7, FR-06.1–06.3 (Phase 2 Frontend) | | Epic 4 | FR-02.1–02.7, FR-03.1–03.3 (Phase 3 Integration) | | Epic 5 | FR-02.2, FR-04.1–04.4, FR-05.2–05.3 (Phase 4 Tools & God Mode) | --- ## Epic-Liste 1. **Epic 1:** Projekt-Setup & Infrastruktur 2. **Epic 2:** LangGraph Engine Backend (Phase 1) 3. **Epic 3:** Visueller Baukasten Frontend (Phase 2) 4. **Epic 4:** Frontend-Backend-Integration (Phase 3) 5. **Epic 5:** Tools & God Mode (Phase 4) --- ## Epic 1: Projekt-Setup & Infrastruktur **Ziel:** Vollständig konfiguriertes, lauffähiges Entwicklungsumfeld mit Docker Compose, PostgreSQL, FastAPI-Skeleton und Next.js-Skeleton. ### Story 1.1: Docker-Compose-Umgebung aufsetzen Als **Entwickler** möchte ich **eine vollständige lokale Docker-Compose-Umgebung**, damit ich **ohne lokale Python/Node-Installation entwickeln kann**. **Akzeptanzkriterien:** **Gegeben** ein frisch geclontes Repository **Wenn** ich `docker compose up -d` ausführe **Dann** starten drei Services: `db` (PostgreSQL 16), `api` (FastAPI Port 8000), `frontend` (Next.js Port 3000) **Und** `GET /api/health` gibt `{"status": "ok"}` zurück **Und** das Frontend ist unter `http://localhost:3000` erreichbar **Gegeben** der `db`-Service läuft **Wenn** ich `pg_isready` im Container ausführe **Dann** antwortet PostgreSQL mit `accepting connections` ### Story 1.2: Backend-Python-Umgebung & Requirements Als **Backend-Entwickler** möchte ich **eine vollständige `requirements.txt` mit allen Abhängigkeiten**, damit ich **reproduzierbar installieren kann**. **Akzeptanzkriterien:** **Gegeben** ein Python 3.11+ Environment **Wenn** ich `pip install -r requirements.txt` ausführe **Dann** sind FastAPI, LangGraph, langchain-anthropic, langchain-openai, SQLAlchemy, alembic, chromadb, tavily-python, pypdf, pytest und alle Transitivabhängigkeiten installiert **Gegeben** die Abhängigkeiten sind installiert **Wenn** ich `pytest backend/tests/` ausführe **Dann** laufen alle Tests durch (auch wenn noch keine Testfälle existieren: 0 passed, 0 failed) ### Story 1.3: Datenbank-Migrationen mit Alembic Als **Backend-Entwickler** möchte ich **Alembic-Migrationen für `blueprints` und `council_runs`**, damit ich **das Schema versioniert verwalten kann**. **Akzeptanzkriterien:** **Gegeben** eine laufende PostgreSQL-Instanz **Wenn** ich `alembic upgrade head` ausführe **Dann** werden die Tabellen `blueprints` und `council_runs` erstellt **Und** `alembic current` zeigt die aktuelle Revision **Gegeben** die Tabellen existieren **Wenn** ich ein Blueprint via REST-API erstelle **Dann** wird es in `blueprints` mit UUID, JSONB-Daten und Timestamps gespeichert --- ## Epic 2: LangGraph Engine Backend (Phase 1) **Ziel:** Funktionierender, hartcodierter LangGraph-Graph (Master→Critic→Writer) mit CouncilState, Routing-Logik und FastAPI-Endpunkten. Verifikation via Terminal/Postman. ### Story 2.1: CouncilState TypedDict implementieren Als **Backend-Entwickler** möchte ich **den `CouncilState` TypedDict mit allen Feldern und Reducern**, damit er **das einzige State-Objekt für alle Agents ist**. **Akzeptanzkriterien:** **Gegeben** `state.py` ist implementiert **Wenn** ich `feedback_history` mit `operator.add` als Reducer definiere **Dann** werden neue Feedback-Einträge angehängt — niemals überschrieben **Wenn** ich `messages` mit `operator.add` als Reducer definiere **Dann** akkumuliert der LLM-Nachrichtenverlauf korrekt über mehrere Nodes **Wenn** `APPROVAL_THRESHOLD = 8.0` und `MAX_ITERATIONS = 5` definiert sind **Dann** sind diese Konstanten importierbar und in Tests verwendbar ### Story 2.2: Master-Agent-Node implementieren Als **Backend-Entwickler** möchte ich **den `master_agent_node`**, damit er **auf Basis von `input_topic` und `feedback_history` einen Draft erstellt**. **Akzeptanzkriterien:** **Gegeben** ein `CouncilState` ohne `feedback_history` **Wenn** `master_agent_node(state)` aufgerufen wird (LLM gemockt) **Dann** enthält der Rückgabe-Dict `current_draft` mit einem nicht-leeren String **Und** `messages` enthält genau 3 Elemente (SystemMessage, HumanMessage, AIMessage) **Und** `iteration_count` ist um 1 erhöht **Gegeben** ein State mit `feedback_history = ["Too short"]` **Wenn** `master_agent_node(state)` aufgerufen wird **Dann** enthält der User-Prompt den Text „feedback" oder die Feedback-Einträge ### Story 2.3: Critic-Agent-Node implementieren Als **Backend-Entwickler** möchte ich **den `critic_agent_node` mit Score-Parsing und Routing**, damit er **Drafts bewertet und `route_decision` setzt**. **Akzeptanzkriterien:** **Gegeben** ein Score < 8 in der LLM-Antwort **Wenn** `critic_agent_node(state)` aufgerufen wird **Dann** ist `route_decision = "rework"` **Und** `feedback_history` enthält einen neuen Eintrag **Gegeben** ein Score ≥ 8 **Dann** ist `route_decision = "approve"` **Und** `feedback_history` bleibt unverändert **Gegeben** `iteration_count >= MAX_ITERATIONS` **Dann** ist `route_decision = "approve"` ohne LLM-Aufruf (Safety Valve) **Gegeben** eine nicht-parsbare LLM-Antwort **Dann** fällt `route_decision` auf `"rework"` zurück — kein Crash ### Story 2.4: Writer-Agent-Node implementieren Als **Backend-Entwickler** möchte ich **den `writer_agent_node`**, damit er **den finalen Draft für die Ausgabe formatiert**. **Akzeptanzkriterien:** **Gegeben** ein `CouncilState` mit `current_draft` **Wenn** `writer_agent_node(state)` aufgerufen wird (LLM gemockt) **Dann** enthält der Rückgabe-Dict `current_draft` (finaler Output) **Und** `active_node = "writer_agent"` ### Story 2.5: LangGraph-Graph bauen und ausführen Als **Backend-Entwickler** möchte ich **einen kompilierten LangGraph-Graphen** (`build_council_graph`), damit er **Master→Critic→(conditional)→Writer ausführt**. **Akzeptanzkriterien:** **Gegeben** `build_council_graph()` wird aufgerufen **Dann** ist der zurückgegebene Graph kompiliert und `invoke`-fähig **Gegeben** ein hartcodierter Test-Input (LLMs gemockt, Score 9 bei 2. Iteration) **Wenn** `graph.invoke(initial_state)` aufgerufen wird **Dann** durchläuft der Graph: master→critic→(rework)→master→critic→(approve)→writer→END **Und** der finale State hat `route_decision = "approve"` und `iteration_count = 2` ### Story 2.6: FastAPI-Run-Endpunkte implementieren Als **API-Nutzer** möchte ich **`POST /api/councils/run` und `GET /api/councils/run/{run_id}`**, damit ich **einen Council-Run starten und sein Ergebnis abrufen kann**. **Akzeptanzkriterien:** **Gegeben** `POST /api/councils/run` mit `{"input_topic": "Test"}` **Wenn** der Endpunkt aufgerufen wird **Dann** gibt er `202 Accepted` mit `run_id` zurück **Und** der Run läuft asynchron im Hintergrund **Gegeben** ein abgeschlossener Run **Wenn** `GET /api/councils/run/{run_id}` aufgerufen wird **Dann** gibt er `status: "completed"` und `final_draft` zurück **Gegeben** eine unbekannte `run_id` **Dann** gibt er `404 Not Found` zurück --- ## Epic 3: Visueller Baukasten Frontend (Phase 2) **Ziel:** React Flow Canvas mit Custom Nodes/Edges, Node-Einstellungs-Panel, Blueprint-Parser und PostgreSQL-Speicherung. ### Story 3.1: React-Flow-Canvas mit Custom Agent Node Als **Nutzer** möchte ich **Agent-Nodes per Drag & Drop auf den Canvas ziehen**, damit ich **meinen KI-Rat visuell zusammenstellen kann**. **Akzeptanzkriterien:** **Gegeben** der Rat-Architekt-Tab ist geöffnet **Wenn** ich einen Node aus der Seitenleiste auf den Canvas ziehe **Dann** erscheint ein Custom-Agent-Node mit Default-Name, Default-Modell und Tool-Badges **Gegeben** ein Node ist auf dem Canvas **Wenn** ich ihn anklicke **Dann** öffnet sich das rechte Einstellungs-Panel **Gegeben** das Einstellungs-Panel ist offen **Wenn** ich den Namen ändere **Dann** aktualisiert sich der Canvas-Node sofort (Live-Bindung) ### Story 3.2: Lineare und bedingte Edges Als **Nutzer** möchte ich **Pfeile zwischen Nodes ziehen und als linear/bedingt markieren**, damit ich **den Workflow meines Councils definieren kann**. **Akzeptanzkriterien:** **Gegeben** zwei Nodes auf dem Canvas **Wenn** ich vom Ausgangs-Handle des ersten zum Eingangs-Handle des zweiten ziehe **Dann** erscheint ein linearer Pfeil (grau, durchgehend) **Gegeben** ich klicke eine Edge an **Wenn** ich sie als „bedingt" mit Label „rework" markiere **Dann** wird sie gestrichelt rot mit Label dargestellt **Gegeben** ich markiere eine Edge als „approve" **Dann** wird sie grün dargestellt ### Story 3.3: Blueprint-Parser (React Flow → JSON) Als **System** möchte ich **eine `parseGraphToBlueprint()`-Funktion**, damit sie **den Canvas-State in ein valides Blueprint-JSON konvertiert**. **Akzeptanzkriterien:** **Gegeben** ein Canvas mit zwei Nodes und einer linearen Edge **Wenn** `parseGraphToBlueprint(nodes, edges, name)` aufgerufen wird **Dann** enthält das JSON `version`, `name`, `nodes[]`, `edges[]` **Gegeben** eine bedingte Edge mit Condition-Label **Dann** ist `type: "conditional"` und `condition: "