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

10 KiB
Raw Permalink Blame History

CLAUDE.md — CheckPoint Ehrenamt App

Projektanker. Claude Code liest diese Datei automatisch zu Beginn jeder Session. Sie ist die verbindliche Quelle für Stack, Regeln und Logik. Bei Widerspruch zwischen Wunsch und dieser Datei: nachfragen, nicht raten.


Zweck

Interne, mobile-first Web-App für das Vor-Ort-Team Prävention der AIDS-Hilfe. Sie organisiert Einsätze (Terminabstimmung + Dienstverteilung) und ersetzt schrittweise die WhatsApp/Signal-Zettelwirtschaft. Das Herzstück ist die Dienstplanung — alles andere ordnet sich dem unter.


Stack & Rahmenbedingungen (fest)

Bereich Entscheidung
Sprache/Backend Python + Flask
Templating Jinja2, server-gerendertes HTML (klassische Multi-Page-App)
ORM/DB SQLAlchemy, SQLite für v1 (ein VPS, 17 Nutzer). Keine Annahmen treffen, die einen späteren Umstieg auf PostgreSQL verbauen.
Passwörter werkzeug.security (Hashing), nie Klartext
CSS selbst gebaut, kein CSS-Framework. Basis: tokens.css + components.css
JavaScript so wenig wie möglich, nur Vanilla, kein Framework. Einzige Ausnahme v1: Chat-Polling (s. u.)
Hosting eigener VPS in der EU
Plattform mobile-first Web-App, kein App Store, „zum Homescreen" möglich
UI-Sprache Deutsch

Erlaubte Zusatz-Bibliotheken (klein halten): Flask, SQLAlchemy/Flask-SQLAlchemy, Werkzeug, optional Flask-Login. Keine schweren Frameworks, kein CSS-/JS-Framework.


Architektur-Prinzipien

  1. Server-rendered first. Seiten kommen fertig vom Server. Formulare sind echte POST-Formulare. Kein clientseitiges Routing, kein SPA-Verhalten.
  2. JavaScript nur, wo es sich beweist. Einzige JS-Ausnahme in v1: der Chat holt neue Nachrichten per kleinem fetch-Polling. Sonst nirgends JS verlangen.
  3. Mandantenfähig ab Tag 1. Siehe eigener Abschnitt. Jeder Datensatz gehört zu genau einem Team.
  4. Mobile-first. Getestet in App-Breite 360460px.
  5. Barrierearmut ist Pflicht, kein Extra. 44px Touch-Ziele, sichtbarer Fokus, Status nie nur über Farbe, sinnvolle aria-label.

Rollen

Rolle Rechte
Admin Logins vergeben, Planungszeiträume und Einsätze anlegen, Dienstplan bauen und veröffentlichen, Dokumente/Fotos freigeben, im Kanal „Ankündigungen" posten, Team verwalten.
Ehrenamtliche:r Verfügbarkeit melden, eigenen Dienstplan sehen, freie Dienste übernehmen, Dokumente/Fotos hochladen (Freigabe nötig), im Kanal „Team" schreiben, Profil pflegen.
  • Keine Selbstregistrierung. Logins legt ausschließlich der Admin an.
  • v1: Nutzername + Passwort. (E-Mail + Code = Future Log.)

Mandantenfähigkeit (Pflichtregeln)

  • Zentrale Einheit team (= Mandant). Das CheckPoint-Team ist das erste von perspektivisch mehreren.
  • Jeder Datensatz (user, planungszeitraum, einsatz, verfuegbarkeit, zuteilung, dokument, kanal, nachricht) trägt eine team_id.
  • Jede Datenbankabfrage filtert nach dem Team des eingeloggten Nutzers. Nie Daten über Teamgrenzen hinweg ausliefern. Das aktive Team wird aus der Session abgeleitet.
  • Das Corporate Design wird pro Team über die Brand-Tokens in tokens.css gesetzt (serverseitig in den <head> injiziert). Code darf keine Markenfarbe fest verdrahten — immer Tokens verwenden.

Datenmodell (Regeln, konzeptionell)

Jede Tabelle hat team_id. Namen/Felder sind Richtwerte, keine starre Vorgabe.

  • team — Mandant. Felder u. a.: Name, Brand-Tokens (Primär, Primär-stark, Akzent, Akzent-stark, Schrift), Logo-Pfad.
  • userrolle (admin | ehrenamt), Nutzername, Passwort-Hash, Anzeigename, optionales Profilbild, optionale freiwillige Angaben.
  • planungszeitraum — Block über einen frei wählbaren Zeitraum (kein Mindest­zeitraum). status: in_planung | veroeffentlicht.
  • einsatz — gehört optional zu einem Planungszeitraum (planungszeitraum_id nullbar). Ohne Zeitraum = Einzeltermin, der direkt zu besetzen ist. Datum, Uhrzeit (Start/Ende), Art/Ort (z. B. Tour Altstadt, Party, Sonderveranstaltung). Braucht 2 Hauptplätze + 1 Springerplatz.
  • verfuegbarkeit — (user × einsatz) → kann | kann_nicht.
  • zuteilung — (user × einsatz) mit platztyp (haupt | springer) und status (zugeteilt | abgesagt | offen | uebernommen).
  • dokument — Datei (PDF/Word/Bild). Felder: Titel (Pflicht), Uploader, status (wartet_auf_freigabe | freigegeben | abgelehnt), ablage (aktuell | archiv).
  • kanal — pro Team zwei feste: ankuendigungen, team.
  • nachricht — Kanal, Autor, Text, Zeitstempel. Nur Text.

Kern-Business-Logik (verbindlich)

Planungszyklus

  1. Admin legt einen Planungszeitraum (frei wählbare Länge) an und trägt die kuratierten Einsätze ein (Freitags-Touren, Samstags-Einsätze/Partys, Sonderveranstaltungen). Alternativ: einzelne Einzeltermine ohne Zeitraum, direkt zum Besetzen.
  2. Status in_planung → Ehrenamtliche melden pro Einsatz kann / kann nicht. Änderung der Verfügbarkeit nur solange in_planung.
  3. Admin baut den Plan manuell: pro Einsatz 2 Haupt + 1 Springer. Die App zeigt pro Person Anzahl bisheriger Einsätze und letzten Einsatz als Hilfe (keine automatische Verteilung in v1).
  4. Bei zu wenigen Verfügbaren: Einsatz als unterbesetzt markieren.
  5. Admin veröffentlicht → alle sehen ihren persönlichen Dienstplan.

Absage & Übernahme

  • Sagt eine Hauptperson ab → Springer rückt automatisch nach (Status uebernommen).
  • Der frei gewordene Springerplatz wird offen → zum „Übernehmen" für alle.
  • Gibt es keinen Springer / sagt er auch ab → offener Platz für alle.
  • „Übernehmen" dient nur dem Nachrücken, nie der Erstverteilung.

Dokumente

  • Upload durch alle, aber Status startet wartet_auf_freigabe (nur Admin + Uploader sichtbar).
  • Admin gibt frei oder lehnt ab (optional Grund). Erst nach Freigabe für alle sichtbar.
  • Admin-Uploads gehen direkt durch.
  • Liste geteilt in Aktuell und Archiv (Verschieben macht der Admin).
  • Foto-Regel: nur ohne erkennbare Dritte bzw. mit deren Einverständnis.

Chat

  • Zwei Kanäle: Ankündigungen (nur Admin postet, alle lesen) und Team (alle posten).
  • Nur Text. Neue Nachrichten via Hintergrund-fetch-Polling (einzige v1-JS-Ausnahme).

Benachrichtigungen

  • v1: nur in-App (neuer Dienst, offener Dienst, neue Nachricht). Push/E-Mail = Future Log.

Designsystem

  • Quelle der Wahrheit: tokens.css (mandantenfähig, hell + dunkel via light-dark()).
  • Hell/Dunkel folgt standardmäßig der Systemeinstellung. Zusätzlich gibt es einen manuellen Umschalter (Topbar-Icon, schaltet System → Hell → Dunkel). Er läuft serverseitig ohne JS: ein POST setzt ein theme-Cookie, der Server schreibt data-theme="light|dark" an <html> (bei „System" kein Attribut). „System" ist Default und jederzeit wieder wählbar.
  • Nie feste Farben im Komponenten-CSS — immer Tokens (var(--cp-...)).
  • Erledigt (Session 4 + Nachzug): components.css enthält kein Farb-Literal mehr. Die früher feste weiße Button-Schrift auf Türkis/Rot läuft jetzt über das Token --cp-on-brand (BRAND-Ebene, bewusst themeunabhängig, kein light-dark(), da die Flächen --cp-teal/--cp-red in beiden Themes derselbe Vollton sind). Pro Team überschreibbar. Regel daher ausnahmslos: nie Farb-Literale im Komponenten-CSS.
  • Status-Mapping: Türkis = offen/bestätigt/verfügbar · Rot = dringend/Vertretung · Neutral = Info/intern/erledigt.
  • Schrift: DM Sans.

UI-Regeln

  • Mobile-first bei 360460px Basisbreite; auf Tablet/Desktop wächst die zentrierte Spalte (inkl. fixierter Topbar/Bottom-Nav) ab 768px auf ~720px. Viel Weißraum, klare Karten (Radius 12px, Innenabstand 16px), keine verschachtelten Karten.
  • Bottom-Navigation, 4 Punkte: Start · Termine · Team · Profil. (Nicht „Kalender".)
  • Jede Ansicht hat eine klare Hauptaktion (Button oder FAB).
  • Buttons: Primär = Türkis/weiß · Dringend = Rot/weiß · Ghost = Fläche mit feinem Rahmen. Kurze Beschriftungen: „Speichern", „Eintragen", „Übernehmen", „Details".
  • Formulare: Labels immer sichtbar über dem Feld, Felder ≥ 44px, kurze freundliche Hilfetexte, Fehler klar und nicht nur über Farbe.

Texte / Copy

  • Deutsch, Satzanfang groß (sentence case), aktive Verben, keine Floskeln.
  • Eine Aktion heißt im ganzen Flow gleich (Button „Übernehmen" → Bestätigung „Übernommen").
  • Fehlermeldungen sagen, was passiert ist und wie es weitergeht — ohne Entschuldigung.

Bewusst raus aus v1 (Out of Scope)

Keine öffentlichen Seiten · keine Klient:innendaten · keine Bezahlfunktion · kein Kalender-Sync (Terminübersicht = Liste) · keine Dateien/Bilder im Chat · keine automatische Dienstverteilung · kein 1:1-Chat · kein Push/E-Mail.


Vorgeschlagene Projektstruktur

checkpoint-ehrenamt/
├── CLAUDE.md
├── TASKS.md
├── app/
│   ├── __init__.py        # App-Factory, DB-Init, Team-Scoping
│   ├── models.py          # SQLAlchemy-Modelle (alle mit team_id)
│   ├── auth.py            # Login, Logout, Admin-Anlage
│   ├── routes/           # Blueprints: planung, dienste, dokumente, chat, profil
│   ├── templates/        # Jinja2 (base.html + Teilansichten)
│   └── static/
│       ├── tokens.css
│       └── components.css
├── instance/             # SQLite-DB, Uploads (nicht im Git)
└── requirements.txt

Arbeitsweise mit den Modellen (Continue)

  • Mistral (Architect): Planung, Design-Entscheidungen, Reviews. Nie zum Schreiben von Produktivcode.
  • Qwen (Coder): Implementierung, Bugfixes, Inline-Edits (Ctrl+I). Immer ein Stück nach dem anderen (Datenmodell → Service → Route → Template).
  • Claude Code: Scaffold, Mehrdateien-Arbeit, übergreifendes Verdrahten.
  • Eine Aufgabe pro Session. Immer @file-Kontext. Plan vor Code.