CP_EHRENAMT/TASKS-backup.md
2026-06-25 18:58:44 +02:00

13 KiB
Raw Permalink Blame History

TASKS.md — Build-Checkliste CheckPoint Ehrenamt App

Eine Aufgabe pro Session. Nach Abhängigkeit geordnet — von oben nach unten abarbeiten. Pro Session: Tool, Ziel, Session-Prompt (zum Einfügen), Deliverables. Nach jeder Session: alle Häkchen setzen, committen, erst dann die nächste starten.

Tool-Legende: 🛠 Claude Code · 💻 Continue + Qwen · 🏛 Continue + Mistral Modell wechseln: llama-switch → [1] Architect / [2] Coder


Session 1 · Scaffold & Projektgerüst 🛠

Ziel: Lauffähiges Flask-Grundgerüst mit App-Factory, SQLite, Basis-Layout, Static-Einbindung und Team-Scoping-Stub.

Prompt:

Lies CLAUDE.md. Erstelle das Projektgerüst gemäß der vorgeschlagenen Struktur:
Flask-App-Factory, SQLAlchemy mit SQLite (instance/), requirements.txt,
ein base.html mit eingebundener tokens.css und components.css, sowie ein
leeres Team-Scoping (Helper, der das aktive Team aus der Session liest).
Zeig mir zuerst den Plan und die Dateiliste, bevor du schreibst.

Deliverables:

  • App startet lokal (flask run) und zeigt eine leere Startseite
  • tokens.css + components.css in base.html eingebunden
  • SQLite initialisiert, instance/ in .gitignore
  • Team-Scoping-Helper vorhanden (noch ohne echte Logik)
  • requirements.txt minimal gehalten

Session 2 · Datenmodell & Mandanten 💻

Ziel: Alle Modelle aus CLAUDE.md, jedes mit team_id. Seed für das erste Team (CheckPoint) inkl. Brand-Tokens und den zwei Chat-Kanälen.

Prompt:

@file app/models.py
@file CLAUDE.md

Erst den Ansatz erklären, dann implementieren — ein Modell nach dem anderen.
Baue die Modelle: team, user, planungszeitraum, einsatz, verfuegbarkeit,
zuteilung, dokument, kanal, nachricht. Jedes mit team_id. Danach ein Seed-Skript,
das das CheckPoint-Team mit Brand-Tokens und den Kanälen "ankuendigungen" und
"team" anlegt. Halte dich an die Feldvorgaben in CLAUDE.md.

Deliverables:

  • Alle Modelle vorhanden, jedes mit team_id
  • Beziehungen sauber (Einsatz↔Planungszeitraum, Zuteilung↔User/Einsatz)
  • Seed legt CheckPoint-Team + 2 Kanäle an
  • DB lässt sich anlegen, Seed läuft ohne Fehler

Session 3 · Auth & Admin-Anlage 💻

Ziel: Login (Nutzername + Passwort, gehasht), Session, Logout, Team-Scoping aktiv, Admin kann Nutzer anlegen. Keine Selbstregistrierung.

Prompt:

@file app/auth.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Baue: Login mit Nutzername+Passwort (werkzeug-Hashing), Session,
Logout. Aktiviere das Team-Scoping (aktives Team aus der Session). Admin-geschützte
Route zum Anlegen neuer Nutzer (Rolle wählbar). Geschützte Routen leiten ohne
Login zur Anmeldung um. Ein Stück nach dem anderen.

Deliverables:

  • Login/Logout funktioniert, Passwörter gehasht
  • Geschützte Routen ohne Login → Redirect
  • Admin kann Nutzer mit Rolle anlegen
  • Alle Queries laufen team-gescoped
  • 🏛 Mini-Review (Mistral): Auth gegen CLAUDE.md prüfen — als Liste, nicht umschreiben

Session 4 · Base-Layout, Theming & Dark-Mode-Fix 💻

Ziel: base.html final (Topbar, Bottom-Nav Start/Termine/Team/Profil, FAB-Slot), Brand-Tokens pro Team in den <head> injizieren, Mockup-CSS auf Tokens umstellen.

Prompt:

@file app/templates/base.html
@file app/static/components.css
@file app/static/tokens.css
@file CLAUDE.md

Ansatz zuerst. 1) base.html mit Topbar (Logo, Glocke, Avatar) und Bottom-Nav
(Start, Termine, Team, Profil). 2) Brand-Tokens des aktiven Teams serverseitig
in den <head> schreiben. 3) Im components.css alle fest verdrahteten Weißwerte
(Topbar, Bottom-Nav, .cp-page-Verlauf) auf Tokens umstellen, damit der Dunkelmodus
greift. Erst die Token-Umstellung erklären, dann umsetzen.

Deliverables:

  • base.html mit korrekter Bottom-Nav (4 Punkte, „Termine")
  • Brand-Tokens kommen pro Team aus der DB in den <head>
  • Keine festen Weiß-/Schwarzwerte mehr im components.css (weiße Button-Schrift jetzt über Token --cp-on-brand, themeunabhängig)
  • Hell- und Dunkelmodus optisch sauber (System-Umschaltung testen)

Session 5 · Planungszeitraum & Einsätze (Admin) 💻

Ziel: Admin legt Planungszeiträume an und trägt Einsätze ein (Datum, Zeit, Art).

Prompt:

@file app/routes/planung.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Admin-Ansichten: Planungszeitraum anlegen (Status in_planung) und
darin Einsätze hinzufügen/bearbeiten/löschen (Datum, Start/Ende, Art/Ort, je 2 Haupt-
+ 1 Springerplatz). Reine POST-Formulare, kein JS. Liste der Einsätze eines Zeitraums.

Deliverables:

  • Admin kann Zeitraum anlegen
  • Admin kann Einsätze anlegen/bearbeiten/löschen
  • Einsatz kennt seine Platzstruktur (2 + Springer)
  • Alles team-gescoped, ohne JavaScript

Session 6 · Verfügbarkeit melden (Ehrenamtliche) 💻

Ziel: Ehrenamtliche melden pro Einsatz „kann / kann nicht", solange in_planung.

Prompt:

@file app/routes/planung.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Ansicht für Ehrenamtliche: Liste der Einsätze im laufenden Zeitraum
mit Umschaltung kann/kann_nicht pro Einsatz (POST-Formular). Änderung nur bei Status
in_planung. Übersichtlich für mobile.

Deliverables:

  • Ehrenamtliche sehen die Einsätze des aktuellen Zeitraums
  • kann/kann_nicht wird gespeichert und ist änderbar (nur in_planung)
  • Nach Veröffentlichung gesperrt
  • Mobile sauber bedienbar (44px-Ziele)

Session 7 · Dienstplan bauen (Admin) 💻

Ziel: Admin verteilt manuell 2 Haupt + 1 Springer pro Einsatz, mit Fairness-Anzeige.

Prompt:

@file app/routes/dienste.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Admin-Ansicht pro Einsatz: verfügbare Personen auswählen und auf
Haupt/Springer setzen. Pro Person anzeigen: Anzahl bisheriger Einsätze und letzter
Einsatz (Fairness-Hilfe). Einsatz als „unterbesetzt" markieren, wenn zu wenige.
Keine automatische Verteilung — nur Anzeige + manuelle Auswahl.

Deliverables:

  • Admin kann Haupt- und Springerplätze besetzen
  • Fairness-Anzeige (Anzahl + letzter Einsatz) pro Person sichtbar
  • Unterbesetzte Einsätze klar markiert
  • 🏛 Review (Mistral): Zuteilungslogik gegen CLAUDE.md prüfen

Session 8 · Veröffentlichen & persönliche Terminübersicht 💻

Ziel: Admin veröffentlicht den Zeitraum; jede:r sieht „Meine Termine" als Liste.

Prompt:

@file app/routes/dienste.py
@file app/templates/
@file CLAUDE.md

Ansatz zuerst. 1) Admin-Aktion „Veröffentlichen" (Status veroeffentlicht, sperrt
Verfügbarkeit). 2) Ansicht „Meine Termine": Liste der eigenen zugeteilten Einsätze,
chronologisch, mit Rolle (Haupt/Springer) und Status. Keine Kalenderansicht.

Deliverables:

  • Veröffentlichen funktioniert und sperrt die Verfügbarkeit
  • „Meine Termine" zeigt eigene Einsätze als Liste
  • Haupt/Springer und Status erkennbar (nicht nur über Farbe)

Session 9 · Absage & Übernahme 💻

Ziel: Absage einer Hauptperson → Springer rückt automatisch nach → Springerplatz wird offen → „Übernehmen" für alle.

Prompt:

@file app/routes/dienste.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Logik laut CLAUDE.md: Sagt eine Hauptperson ab, rückt der Springer
automatisch nach (status uebernommen) und der Springerplatz wird offen. Offene
Plätze erscheinen mit „Übernehmen"-Button; wer zuerst klickt, bekommt ihn (sauber
gegen Doppel-Klicks absichern). Kein Springer → Platz direkt offen.

Deliverables:

  • Absage einer Hauptperson → Springer rückt automatisch nach
  • Frei gewordener Springerplatz wird offen zum Übernehmen
  • „Übernehmen" sicher gegen gleichzeitige Klicks (atomares UPDATE)
  • Fall „kein Springer" korrekt behandelt
  • Review der Übernahme-Logik (Randfälle) — mit Claude Code statt Mistral

Session 10 · Dokumente & Freigabe 💻

Ziel: Upload (alle), Freigabe-Warteschlange (Admin), Liste Aktuell/Archiv.

Prompt:

@file app/routes/dokumente.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Upload (PDF/Word/Bild) mit Pflicht-Titel → Status wartet_auf_freigabe
(nur Admin + Uploader sichtbar). Admin-Ansicht „Freigaben": freigeben/ablehnen
(optional Grund). Admin-Uploads direkt freigegeben. Liste geteilt in Aktuell/Archiv,
Verschieben durch Admin. Dateigrößen-Limit und Dateityp-Prüfung serverseitig.

Deliverables:

  • Upload landet in wartet_auf_freigabe (nicht öffentlich sichtbar)
  • Admin kann freigeben/ablehnen, Admin-Uploads direkt sichtbar
  • Liste Aktuell + Archiv, Verschieben durch Admin
  • Server prüft Dateityp und -größe

Session 11 · Chat (2 Kanäle, Polling) 💻

Ziel: Ankündigungen (nur Admin postet) + Team (alle). Nur Text. Neue Nachrichten per fetch-Polling (einzige v1-JS-Ausnahme).

Prompt:

@file app/routes/chat.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Zwei Kanäle: ankuendigungen (nur Admin darf posten, alle lesen) und
team (alle posten). Nur Text. Nachrichten chronologisch. Dazu ein kleiner
JSON-Endpunkt „neue Nachrichten seit X" und ~30 Zeilen Vanilla-JS, das im
Hintergrund pollt und neue Nachrichten anhängt. Kein Framework, kein WebSocket.

Deliverables:

  • Beide Kanäle funktionieren, Rechte korrekt (Ankündigungen nur Admin)
  • Nachrichten werden gespeichert und angezeigt (nur Text)
  • Polling lädt neue Nachrichten ohne Seiten-Reload
  • JS ist minimal und vanilla

Session 12 · Profil 💻

Ziel: Profilbild-Upload + Platzhalter für optionale freiwillige Angaben.

Prompt:

@file app/routes/profil.py
@file app/models.py
@file CLAUDE.md

Ansatz zuerst. Profil-Ansicht: Profilbild hochladen/ändern, Anzeigename, optionale
freiwillige Felder (vorerst ein, zwei Freitextfelder als Platzhalter — Struktur so,
dass Felder später leicht ergänzt werden). Nichts davon Pflicht.

Deliverables:

  • Profilbild hochladbar
  • Optionale Felder vorhanden, nichts Pflicht
  • Struktur erlaubt späteres Ergänzen von Feldern

Session 13 · In-App-Benachrichtigungen 💻

Ziel: Dezente in-App-Hinweise (neuer Dienst, offener Dienst, neue Nachricht).

Prompt:

@file app/models.py
@file app/templates/base.html
@file CLAUDE.md

Ansatz zuerst. Einfaches Benachrichtigungsmodell + Anzeige (Glocke in der Topbar mit
Zähler, Liste beim Antippen). Auslöser: neue Zuteilung, neuer offener Dienst, neue
Nachricht. Als gelesen markierbar. Kein Push, keine E-Mail.

Deliverables:

  • Benachrichtigungen werden bei den drei Auslösern erzeugt
  • Glocke zeigt ungelesene an, Liste antippbar
  • Als gelesen markierbar

Session 14 · Gesamt-Review 🏛

Ziel: Durchsicht des fertigen Stands gegen CLAUDE.md — Korrektheit, Konsistenz, Barrierearmut, Dunkelmodus.

Prompt:

@file CLAUDE.md
@file app/models.py
@file app/routes/

Review den aktuellen Stand gegen CLAUDE.md. Korrektheitsprobleme zuerst, dann
Konsistenz und Wartbarkeit, dann Barrierearmut und Dunkelmodus-Lücken. Nichts
umschreiben — alles als nummerierte Liste mit Fundstelle.

Deliverables:

  • Review-Liste erstellt
  • Gefundene Korrektheitsprobleme in 💻-Folgeschritten behoben
  • A11y- und Dark-Mode-Lücken geschlossen

Session 15 · Deployment auf den VPS 🛠

Ziel: App läuft auf dem EU-VPS hinter einem produktiven Server.

Prompt:

Lies CLAUDE.md. Hilf mir beim Deployment auf einen EU-VPS: WSGI-Server (z. B.
gunicorn) hinter nginx, Umgebungsvariablen/Secrets, Persistenz für SQLite und
Uploads, einfaches Backup der DB, HTTPS. Gib mir die Schritte als Fish-Befehle,
wo Terminal nötig ist. Plan zuerst.

Deliverables:

  • App läuft unter gunicorn hinter nginx
  • HTTPS aktiv
  • Secrets über Umgebungsvariablen, nicht im Code
  • DB + Uploads persistent, einfaches DB-Backup eingerichtet

Future Log (nicht in v1)

1:1-Chat · Push-/E-Mail-Benachrichtigungen · E-Mail+Code-Login (Magic Link) · automatische Fairness-Verteilung · weitere Rollen · Laptop-Spiegelung / Desktop-Fallback über LAN · komfortablere Zeit-Auswahl (Rad-/Scroll-Picker für Startzeit & Dauer statt Dropdown).

Härtung (vor Produktiv-Deploy / Session 15)

  • CSRF-Schutz für alle POST-Formulare. Erledigt (nach Session 3): eigenes, Session-gebundenes Token in app/csrf.py, ohne Flask-WTF. csrf_token() als Jinja-Global, Prüfung aller unsicheren Methoden via before_request. Pflicht für alle künftigen POST-Formulare: verstecktes Feld <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> einbauen.
  • Brand-Tokens im <head> werden mit |safe ausgegeben (base.html, wegen der Anführungszeichen im Font). Quelle ist aktuell nur Admin/Seed, daher für v1 vertretbar. Sobald eine UI zum Bearbeiten der Brand-Felder entsteht: Werte serverseitig validieren/escapen (CSS-Injection / </style>-Ausbruch verhindern) z. B. Hex-Farben per Regex prüfen, Font auf Whitelist begrenzen.