docs: Plan-Haekchen Ausbaustufe 6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 12:54:19 +02:00
parent 421899b922
commit 974ef5c208

View File

@@ -1,6 +1,6 @@
# Ausbaustufe 6 Implementation Plan — Szenario-Einträge-Tabelle (v0.7.0)
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking.
**Goal:** Pro Szenario eine immer sichtbare, editierbare Tabelle „Einträge" (Modifikatoren + szenario-eigene Einmalzahlungen gemeinsam) mit Inline-Bearbeiten und einem gemeinsamen Anlege-Formular; Release v0.7.0.
@@ -32,7 +32,7 @@
- Consumes: `ModifierIn`/`ModifierOut`, `ScenarioPlannedIn`/`ScenarioPlannedOut`, `_get_scenario` (alle vorhanden in `scenarios.py`).
- Produces: `PATCH /api/scenarios/{scenario_id}/modifiers/{mod_id}` (Body `ModifierIn`, Antwort `ModifierOut`, 404 „Modifikator nicht gefunden") und `PATCH /api/scenarios/{scenario_id}/planned/{item_id}` (Body `ScenarioPlannedIn`, Antwort `ScenarioPlannedOut`, 404 „Einmalzahlung nicht gefunden"). Task 2 (GUI) sendet auf genau diese URLs.
- [ ] **Step 1: Failing Tests** — in `tests/test_crud_api.py` ergänzen:
- [x] **Step 1: Failing Tests** — in `tests/test_crud_api.py` ergänzen:
```python
def test_modifier_patch(client, db):
@@ -85,7 +85,7 @@ def test_scenario_planned_patch(client, db):
Run: `.venv/bin/python -m pytest tests/test_crud_api.py -q` → neue Tests FAIL (405 Method Not Allowed)
- [ ] **Step 2: Endpunkte implementieren**`app/routers/scenarios.py`, direkt nach `delete_modifier` bzw. nach `delete_scenario_planned`:
- [x] **Step 2: Endpunkte implementieren**`app/routers/scenarios.py`, direkt nach `delete_modifier` bzw. nach `delete_scenario_planned`:
```python
@router.patch("/{scenario_id}/modifiers/{mod_id}", response_model=ModifierOut)
@@ -119,14 +119,14 @@ def patch_scenario_planned(scenario_id: int, item_id: int, data: ScenarioPlanned
return ScenarioPlannedOut.model_validate(item)
```
- [ ] **Step 3: Tests grün + Suite**
- [x] **Step 3: Tests grün + Suite**
Run: `.venv/bin/python -m pytest tests/test_crud_api.py -q && .venv/bin/python -m pytest -q`
Expected: alles PASS (178 + 2)
- [ ] **Step 4: Fable-Testagent-Abnahme** (Faktencheck: Validator-Wirkung beim PATCH [ende↔andere Arten], 404-Pfade, keine Nebenwirkungen auf Projektion). Erst nach VERIFIED weiter.
- [x] **Step 4: Fable-Testagent-Abnahme** (Faktencheck: Validator-Wirkung beim PATCH [ende↔andere Arten], 404-Pfade, keine Nebenwirkungen auf Projektion). Erst nach VERIFIED weiter.
- [ ] **Step 5: Commit**
- [x] **Step 5: Commit**
```bash
cd /home/wlfb/bin && git add finance/app/routers/scenarios.py finance/tests/test_crud_api.py
@@ -147,7 +147,7 @@ git commit -m "feat: PATCH-Endpunkte fuer Szenario-Modifikatoren und -Einmalzahl
- Consumes: PATCH-Endpunkte aus Task 1; `toggleEdit`, `onModTargetTypeChange`, Filter `|eur`/`|de_label`, Kontext `row.modifiers`/`row.planned_items`/`modifier_kinds`/`recurring_names`/`category_names` (alle vorhanden).
- Produces: Element-IDs `mod-row-{id}`/`mod-edit-{id}` und `spi-row-{id}`/`spi-edit-{id}`; JS `onEntryArtChange(select)` (ersetzt `onModKindChange` vollständig — auch in den Art-Selects); Anlege-Formular mit `data-modifiers-url`/`data-planned-url` und Eintragsart-Option `value="einmal"`.
- [ ] **Step 1: Failing GUI-Test** — in `tests/test_gui.py` ergänzen (Imports `Scenario, ScenarioModifier, ScenarioPlannedItem` existieren dort seit A5):
- [x] **Step 1: Failing GUI-Test** — in `tests/test_gui.py` ergänzen (Imports `Scenario, ScenarioModifier, ScenarioPlannedItem` existieren dort seit A5):
```python
def test_szenario_eintraege_tabelle(client, db):
@@ -182,7 +182,7 @@ def test_szenario_eintraege_tabelle(client, db):
Run: → FAIL
- [ ] **Step 2: `_scenario_rows` sortieren**`app/routers/gui.py`, Modifikator-Query um `.order_by(ScenarioModifier.id)` ergänzen:
- [x] **Step 2: `_scenario_rows` sortieren**`app/routers/gui.py`, Modifikator-Query um `.order_by(ScenarioModifier.id)` ergänzen:
```python
modifiers = session.execute(
@@ -191,7 +191,7 @@ Run: → FAIL
).scalars().all()
```
- [ ] **Step 3: Einträge-Tabelle** — in `planning.html` die BEIDEN `<details>`-Blöcke „Modifikatoren" und „Einmalzahlungen in diesem Szenario" komplett ersetzen durch:
- [x] **Step 3: Einträge-Tabelle** — in `planning.html` die BEIDEN `<details>`-Blöcke „Modifikatoren" und „Einmalzahlungen in diesem Szenario" komplett ersetzen durch:
```html
<h3>Einträge</h3>
@@ -289,7 +289,7 @@ Run: → FAIL
</table>
```
- [ ] **Step 4: Anlege-Formular „Neuer Eintrag"** — direkt nach der Tabelle (Default-Art ist die erste Option `percent` → Wert aktiv, Datumsfelder/Einmal-Felder disabled):
- [x] **Step 4: Anlege-Formular „Neuer Eintrag"** — direkt nach der Tabelle (Default-Art ist die erste Option `percent` → Wert aktiv, Datumsfelder/Einmal-Felder disabled):
```html
<form hx-ext="json-form" hx-post="/api/scenarios/{{ sc.id }}/modifiers" hx-swap="none"
@@ -334,7 +334,7 @@ Run: → FAIL
WICHTIG: Der Ziel-Typ-Select muss VOR den beiden Ziel-Spans stehen wie im bisherigen Formular? Nein — Reihenfolge im bisherigen Formular war Ziel-Typ, dann Spans. Diese Reihenfolge beibehalten (Ziel-Typ zuerst, dann die Spans), damit das Formular lesbar bleibt — den obigen Block entsprechend anordnen: Eintragsart, Ziel-Typ, beide Spans, Wert, Endet am, Name, Betrag, Fällig am, Button.
- [ ] **Step 5: JS** — im `<script>`-Block von `planning.html` die Funktion `onModKindChange` ERSETZEN durch:
- [x] **Step 5: JS** — im `<script>`-Block von `planning.html` die Funktion `onModKindChange` ERSETZEN durch:
```javascript
function onEntryArtChange(select) {
@@ -373,7 +373,7 @@ WICHTIG: Der Ziel-Typ-Select muss VOR den beiden Ziel-Spans stehen wie im bisher
`onModTargetTypeChange` und `toggleEdit` bleiben unverändert.
- [ ] **Step 6: Bestehenden Test anpassen**`tests/test_gui.py::test_szenario_gui_ende_und_einmalzahlungen` (aus A5 Task 7): die Assertions `"Einmalzahlungen in diesem Szenario" in r` und `f'hx-post="/api/scenarios/{sc.id}/planned"' in r` ersetzen durch:
- [x] **Step 6: Bestehenden Test anpassen**`tests/test_gui.py::test_szenario_gui_ende_und_einmalzahlungen` (aus A5 Task 7): die Assertions `"Einmalzahlungen in diesem Szenario" in r` und `f'hx-post="/api/scenarios/{sc.id}/planned"' in r` ersetzen durch:
```python
assert "Einträge" in r
@@ -382,7 +382,7 @@ WICHTIG: Der Ziel-Typ-Select muss VOR den beiden Ziel-Spans stehen wie im bisher
Die übrigen Assertions (`value="ende"`, `name="end_date"`, `31.08.2026`, `Zufluss-GUI`, `5.000,00`, `30.07.2026`) bleiben gültig. Danach: `grep -n "Einmalzahlungen in diesem Szenario" tests/` → 0 Treffer.
- [ ] **Step 7: Hilfe anpassen**`app/templates/hilfe.html`, im Szenarien-Absatz (aus A5) den Satzteil zu Modifikatoren/Einmalzahlungen ersetzen durch (generisch, keine echten Daten):
- [x] **Step 7: Hilfe anpassen**`app/templates/hilfe.html`, im Szenarien-Absatz (aus A5) den Satzteil zu Modifikatoren/Einmalzahlungen ersetzen durch (generisch, keine echten Daten):
```html
Varianten wie „Best Case“ pflegst du in der Tabelle „Einträge“ des
@@ -394,14 +394,14 @@ Die übrigen Assertions (`value="ende"`, `name="end_date"`, `31.08.2026`, `Zuflu
änderbar.
```
- [ ] **Step 8: Tests + Suite grün**
- [x] **Step 8: Tests + Suite grün**
Run: `.venv/bin/python -m pytest tests/test_gui.py -q && .venv/bin/python -m pytest -q`
Expected: alles PASS
- [ ] **Step 9: Fable-Testagent-Abnahme** — Live-Anteil (TestClient-Approximation): gemischte Tabelle rendert beide Typen in korrekter Reihenfolge; Edit-Roundtrips für Modifikator (percent→ende inkl. Datumspflicht) und Einmalzahlung mit deutscher Betragseingabe; Umschaltmatrix-Handtrace für alle 5 Eintragsarten (inkl. disabled-Zustand von `kind`-Fremdfeld beim jeweils anderen Endpunkt); keine doppelten IDs. Erst nach VERIFIED weiter.
- [x] **Step 9: Fable-Testagent-Abnahme** — Live-Anteil (TestClient-Approximation): gemischte Tabelle rendert beide Typen in korrekter Reihenfolge; Edit-Roundtrips für Modifikator (percent→ende inkl. Datumspflicht) und Einmalzahlung mit deutscher Betragseingabe; Umschaltmatrix-Handtrace für alle 5 Eintragsarten (inkl. disabled-Zustand von `kind`-Fremdfeld beim jeweils anderen Endpunkt); keine doppelten IDs. Erst nach VERIFIED weiter.
- [ ] **Step 10: Commit**
- [x] **Step 10: Commit**
```bash
cd /home/wlfb/bin && git add finance/app/templates/ finance/app/routers/gui.py finance/tests/test_gui.py
@@ -419,22 +419,22 @@ git commit -m "feat: Szenario-Eintraege als eine editierbare Tabelle"
**Interfaces:**
- Consumes: Tasks 1-2 committet, Suite grün, bestehendes Live-Szenario „Best Case" (id 4) mit 3 Einträgen.
- [ ] **Step 1: Suite final**`cd /home/wlfb/bin/finance && .venv/bin/python -m pytest -q` → alle grün.
- [x] **Step 1: Suite final**`cd /home/wlfb/bin/finance && .venv/bin/python -m pytest -q` → alle grün.
- [ ] **Step 2: Version + Commit**
- [x] **Step 2: Version + Commit**
```bash
echo "0.7.0" > /home/wlfb/bin/finance/VERSION
cd /home/wlfb/bin && git add finance/VERSION && git commit -m "chore: Version 0.7.0"
```
- [ ] **Step 3: Redeploy**`cd /home/wlfb/bin && ./create_pod_finance.sh` (keine Migration nötig; Entrypoint-`alembic upgrade head` ist idempotent). Expected: Service aktiv, Readiness 200.
- [x] **Step 3: Redeploy**`cd /home/wlfb/bin && ./create_pod_finance.sh` (keine Migration nötig; Entrypoint-`alembic upgrade head` ist idempotent). Expected: Service aktiv, Readiness 200.
- [ ] **Step 4: Live-Smoke**`/api/version` == 0.7.0 (Bearer-Key aus `~/.local/share/finance_pod/.env`); GUI-Login; `/planung` zeigt im „Best Case"-Kasten die Einträge-Tabelle mit 3 Zeilen (2× Ende, 1× Einmalzahlung) OHNE aufklappen zu müssen; kein „Modifikatoren"-Summary mehr.
- [x] **Step 4: Live-Smoke**`/api/version` == 0.7.0 (Bearer-Key aus `~/.local/share/finance_pod/.env`); GUI-Login; `/planung` zeigt im „Best Case"-Kasten die Einträge-Tabelle mit 3 Zeilen (2× Ende, 1× Einmalzahlung) OHNE aufklappen zu müssen; kein „Modifikatoren"-Summary mehr.
- [ ] **Step 5: Fable-Testagent-Abnahme (Release-Gate)** — Live: zusätzlich zu Step 4 ein kompletter Roundtrip in einem WEGWERF-Szenario „SMOKE-A6" (anlegen → Eintrag percent anlegen → per PATCH auf ende mit Datum ändern → Einmalzahlung anlegen → Betrag per PATCH ändern → Szenario löschen [räumt alles ab]); Bestandsdaten unverändert (confirmed-Tx-Count, „Best Case"-Einträge unangetastet). Erst nach VERIFIED weiter.
- [x] **Step 5: Fable-Testagent-Abnahme (Release-Gate)** — Live: zusätzlich zu Step 4 ein kompletter Roundtrip in einem WEGWERF-Szenario „SMOKE-A6" (anlegen → Eintrag percent anlegen → per PATCH auf ende mit Datum ändern → Einmalzahlung anlegen → Betrag per PATCH ändern → Szenario löschen [räumt alles ab]); Bestandsdaten unverändert (confirmed-Tx-Count, „Best Case"-Einträge unangetastet). Erst nach VERIFIED weiter.
- [ ] **Step 6: Ledger + Plan-Häkchen + Push**
- [x] **Step 6: Ledger + Plan-Häkchen + Push**
```bash
cd /home/wlfb/bin && git add docs/superpowers/plans/2026-07-20-ausbaustufe-6.md && git commit -m "docs: Ledger/Plan Ausbaustufe 6" && git push