# Fælles Vinindkøb — Projektplan ## Formål Erstatte manuel administration (regneark til betalingstracking, direkte databaseredigering for nye runder/deltagere/vine) med en rigtig admin-backend, samt automatisk betalings-mail til deltagere. Arkitekturen designes fra start til at kunne understøtte flere organisationer (fx vinbonden Horcher-familiens egne ruter i Frankrig/Belgien), selvom kun én organisation/rute er i drift i dag. ## Tech stack - Backend: FastAPI + SQLModel + PostgreSQL + Alembic (migrations) - Frontend: React (admin-UI) + eksisterende offentlige bestillingsside (fortsat intet login for deltagere) - Mail: SMTP-udbyder — afklares ## Datamodel - **WineCategory** — global, delt af ALLE organisationer/ruter (samme vinbonde, samme kategoristruktur: TRADITION, SELECTION, LES IMPERTINENTS, GRANDS CRUS, VENDANGES TARDIVES, CREMANT, MAGNUM, SANS ALCOOL osv.) - navn, sortering - **Organization** — administrativ gruppe (fx "Fælles Vinindkøb DK", "Horcher Frankrig") - navn - **User** — admin-login, tilhører en Organization - simpelt login v1 (password-hash + session/JWT), struktureret så passkey/WebAuthn kan tilføjes senere uden brud - **Route** — tilhører en Organization (fx "Tyskland" for jer; "Belgique" / "Paris" / "Massif Central" for Horcher-familien) - navn, mødested/kontaktperson/telefon (fritekst, forudfyldes fra forrige runde) - **Participant** — tilhører en Route - navn, mail, telefon, is_active - **PurchaseRound** — tilhører en Route - sæson (forår/efterår), år, status (kladde/åben/lukket) - eur_dkk_rate (valgfri — ikke alle organisationer skal omregne) - intro_text, pickup_info_text (forudfyldes fra forrige runde, kun dato/sæson skal typisk rettes) - **WineOffering** — tilhører PurchaseRound + (global) WineCategory - navn (inkl. størrelse, fx "75cl" — ikke separat felt v1) - vintage/årgang, pris (EUR) - is_organic (boolean — sat via checkbox, kilde: AB-mærket på producentens prisliste) - **Order** — deltager + runde - payment_status (ubetalt/betalt), paid_at - **OrderLine** — ordre + wine_offering + antal ## Mail-events 1. Runde åbnes → mail til alle aktive deltagere på ruten 2. Ordre afgivet → kvittering til deltager + notifikation til admin (findes allerede) 3. **Nyt:** Admin markerer ordre "betalt" → automatisk kvitteringsmail til deltager SMTP: Postal (selvhostet) ## Fase 1 — nuværende scope 1. Sæt FastAPI + SQLModel + PostgreSQL op med Alembic 2. Definér modellerne ovenfor (inkl. Organization/Route-hierarki, selvom kun én organisation/rute findes i dag) 3. Manuel dataindtastning: deltagere (og evt. en aktiv runde) fra MongoDB til PostgreSQL 4. Simpelt login til User 5. Admin CRUD: deltagere (inkl. aktiv/inaktiv — erstatter "tom bestilling"-tricket) 6. Admin CRUD: runder + vinliste, med "kopiér fra forrige runde" (alle felter, inkl. kategori, forudfyldt og frit redigerbare) 7. "Annoncér runde": skabelonmail til alle aktive deltagere på ruten 8. Flyt offentlig bestillingsformular til nyt API (fortsat uden login) 9. Admin-ordreoversigt pr. runde med "markér betalt" → trigger mail #3 10. Genskab afhentningsliste (HTML-udtræk til print) mod ny datamodel 11. Simpelt React admin-UI til pkt. 5, 6, 7, 9 12. Testkør en rigtig runde gennem hele flowet ## Fase 2 — senere - enablebanking.com: automatisk match af indbetalinger mod ubetalte ordrer → kalder samme "markér betalt"-logik - Passkey-login til admin - Rute-vælger på bestillingssiden (når flere ruter er aktive samtidig) - sold_only_by_case-flag + validering, hvis det bliver relevant