Update CLAUDE.md for task 8a, add standing update-after-each-task note

Order/OrderLine now have a real write path (the public order API), so
their "model exists, no API yet" notes are replaced with what's
actually there. Participant's entry documents the ad-hoc-create/
always-update-on-order behavior. Mail-events #2 marked implemented
with the same detail level as #1. Fase 1 task 8 split into 8a (done)/
8b (pending, own stack decision) matching the 7a/7b/7c precedent.

Added a short process note at the top, per explicit user request:
this file should be updated after each (sub)task, not just on request.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Carsten Gram 2026-09-28 22:11:55 +02:00
parent 706c6d5828
commit 5db65fb268

View file

@ -1,5 +1,10 @@
# Fælles Vinindkøb — Projektplan # Fælles Vinindkøb — Projektplan
> **Proces:** Når en opgave (eller delopgave, fx 7a/8a) er
> gennemført, skal denne fil opdateres til at afspejle det faktisk
> byggede — datamodel, endpoints, og status i Fase 1-listen. Filen er
> den løbende sandhed om projektet, ikke kun den oprindelige plan.
## Formål ## Formål
Erstatte manuel administration (regneark til betalingstracking, direkte Erstatte manuel administration (regneark til betalingstracking, direkte
databaseredigering for nye runder/deltagere/vine) med en rigtig databaseredigering for nye runder/deltagere/vine) med en rigtig
@ -54,6 +59,11 @@ vinbonden Horcher-familiens egne ruter i Frankrig/Belgien), selvom kun
- Soft-delete via `is_active` er den normale vej (bevarer historik - Soft-delete via `is_active` er den normale vej (bevarer historik
for deltagere der forlader og kommer tilbage); en rigtig `DELETE` for deltagere der forlader og kommer tilbage); en rigtig `DELETE`
findes også, kun til GDPR-sletningsanmodninger findes også, kun til GDPR-sletningsanmodninger
- Oprettes/opdateres også ad-hoc via den offentlige bestillings-API
(opgave 8a) — matcher emailen en eksisterende deltager på ruten,
**overskrives** `name`/`phone`/`is_active` fra formularen ved hver
bestilling (ingen login = bestillingsformularen er selve vejen man
holder sine oplysninger opdateret); ny email = ny deltager-række
- **PurchaseRound** — tilhører en Route - **PurchaseRound** — tilhører en Route
- `name` (frit, fx "Forår 2026" — intet sæson/år-felt, da det ikke - `name` (frit, fx "Forår 2026" — intet sæson/år-felt, da det ikke
@ -74,10 +84,11 @@ vinbonden Horcher-familiens egne ruter i Frankrig/Belgien), selvom kun
- **Order** — deltager + runde - **Order** — deltager + runde
- `payment_status` (`unpaid`/`paid`), `paid_at`, `created_at` - `payment_status` (`unpaid`/`paid`), `paid_at`, `created_at`
- *Model findes, men ingen CRUD/API endnu — kommer med opgave 8/9* - Oprettes via den offentlige bestillings-API (opgave 8a, ingen
login); admin-ordreoversigt + "markér betalt" er stadig opgave 9
- **OrderLine** — ordre + wine_offering + antal - **OrderLine** — ordre + wine_offering + antal
- *Model findes, men ingen CRUD/API endnu — kommer med opgave 8/9* - Samme som Order — skrives af opgave 8a's bestillings-endpoint
- **MailTemplate** — tilhører Route, én pr. `(route, event_type)` - **MailTemplate** — tilhører Route, én pr. `(route, event_type)`
- `event_type`: `round_announced` / `order_confirmed` / - `event_type`: `round_announced` / `order_confirmed` /
@ -102,21 +113,26 @@ vinbonden Horcher-familiens egne ruter i Frankrig/Belgien), selvom kun
`POST /purchase-rounds/{id}/announce`, logges i `MailLog`, `POST /purchase-rounds/{id}/announce`, logges i `MailLog`,
statusopdateres løbende via Postal-webhook (`POST /webhooks/postal`, statusopdateres løbende via Postal-webhook (`POST /webhooks/postal`,
RSA-SHA256-signatur verificeret mod DKIM-nøglen fra DNS). RSA-SHA256-signatur verificeret mod DKIM-nøglen fra DNS).
2. Ordre afgivet → kvittering til deltager + notifikation til admin 2. Ordre afgivet → kvittering til deltager. **Implementeret** (opgave
(findes allerede i den gamle offentlige bestillingsside — flyttes i 8a): `POST /public/routes/{route_id}/orders` (ingen login) genbruger
opgave 8) 7b's render/send/log-mønster for én deltager. Manglende skabelon
blokerer bevidst **ikke** bestillingen (kun `/announce`'s admin-flow
fejler hårdt på det) — en konfigurationsfejl må aldrig stoppe en
rigtig kundes ordre. Kvitteringen genskaber bevidst det gamle
systems fulde vinkatalog-layout (efterligner den fysiske
bestillingsseddel ved vinbonden). *Notifikation til admin ved ny
ordre findes ikke endnu.*
3. **Nyt:** Admin markerer ordre "betalt" → automatisk kvitteringsmail 3. **Nyt:** Admin markerer ordre "betalt" → automatisk kvitteringsmail
til deltager (opgave 9) til deltager (opgave 9 — bygger videre på samme mønster)
Event #2 og #3 er modelleret i `MailEventType` Event #3 er modelleret i `MailEventType` (`payment_confirmed`) og kan
(`order_confirmed`/`payment_confirmed`) og kan allerede have skabeloner allerede have en skabelon oprettet via 7a's CRUD, men selve
oprettet via 7a's CRUD, men selve udløsningen (fra ordre-flowet i udløsningen (fra "markér betalt"-handlingen i opgave 9) er ikke bygget
opgave 8/9) er ikke bygget endnu — 7b's afsendelses-/logmønster endnu.
(rendering, `send_mail`, `MailLog`) er genbrugbart når det sker.
## Fase 1 — nuværende scope ## Fase 1 — nuværende scope
**Færdige opgaver (1-7):** **Færdige opgaver (1-7, 8a):**
1. ✅ FastAPI + SQLModel + PostgreSQL + Alembic scaffolding 1. ✅ FastAPI + SQLModel + PostgreSQL + Alembic scaffolding
2. ✅ Datamodellerne (Organization/Route-hierarki) 2. ✅ Datamodellerne (Organization/Route-hierarki)
3. ✅ Deltager-migrering fra MongoDB (308 deltagere importeret, 3. ✅ Deltager-migrering fra MongoDB (308 deltagere importeret,
@ -132,9 +148,15 @@ opgave 8/9) er ikke bygget endnu — 7b's afsendelses-/logmønster
- **7b**: Afsendelse via Postal + `MailLog` - **7b**: Afsendelse via Postal + `MailLog`
(`POST /purchase-rounds/{id}/announce`, `GET /mail-logs`) (`POST /purchase-rounds/{id}/announce`, `GET /mail-logs`)
- **7c**: Postal-webhook til leveringsstatus (`POST /webhooks/postal`) - **7c**: Postal-webhook til leveringsstatus (`POST /webhooks/postal`)
8. "Flyt offentlig bestillingsformular til nyt API" — delt i to:
- **8a**: ✅ Backend-API (`GET /public/routes/{id}/current-round`,
`POST /public/routes/{id}/orders`), ad-hoc deltageroprettelse,
kvitteringsmail
- **8b**: Selve den nye offentlige frontend — brugeren har ikke
adgang til den gamle frontends kode (hårdt koblet til det gamle
API), så en ny bygges. Egen stack-beslutning, ikke taget endnu.
**Resterende opgaver:** **Resterende opgaver:**
8. Flyt offentlig bestillingsformular til nyt API (fortsat uden login)
9. Admin-ordreoversigt pr. runde med "markér betalt" → trigger mail #3 9. Admin-ordreoversigt pr. runde med "markér betalt" → trigger mail #3
10. Genskab afhentningsliste (HTML-udtræk til print) mod ny datamodel 10. Genskab afhentningsliste (HTML-udtræk til print) mod ny datamodel
11. Simpelt React admin-UI til pkt. 5, 6, 7, 9 11. Simpelt React admin-UI til pkt. 5, 6, 7, 9