INBOX/CLAUDE.md
2026-08-07 16:01:24 +02:00

268 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` (User-Shell) + `components-admin.css` (Admin-Shell) |
| 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.** Zwei JS-Ausnahmen in v1: der Chat holt
neue Nachrichten per kleinem `fetch`-Polling, und die Admin-Sidebar wird auf
schmalen Bildschirmen per Hamburger-Icon als Off-Canvas-Overlay ein-/ausgeklappt
(Klasse toggeln, kein Framework). 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.
---
## Zwei Oberflächen, zwei Shells (Pflichtregel)
Es gibt **zwei eigenständige Layout-Shells**, eine pro Rolle. Sie sind keine
Variante derselben Vorlage, sondern zwei getrennte Templates mit jeweils eigenem
Tokensatz:
| | **User-Shell** | **Admin-Shell** |
|---|---|---|
| Für wen | Ehrenamtliche | Admin |
| Vorlage | `base_user.html` | `base_admin.html` |
| Navigation | Bottom-Nav, 4 Punkte (Start, Termine, Team, Profil) | Sidebar links, fest: Start, Planung, Dienste, Freigaben, Team, Chat-Verwaltung, Profil, Abmelden |
| Grundform | Mobile-first (App-Breite 360460px) | Desktop-first (Sidebar 260px), responsiv bis Mobile |
| Mobiles Verhalten | nativ mobil, keine Anpassung nötig | Sidebar wird unter dem Breakpoint zu einer **Off-Canvas-Navigation**: Hamburger-Icon oben links öffnet sie als Overlay |
| Tokens | `--cp-user-*` (Türkis/Rot, DM Sans) | `--cp-admin-*` (Navy/Teal/Gelb/Pink, Roboto Condensed + Alfa Slab One für Seitentitel) |
| CSS-Wurzelklasse | `.cp-shell-user` | `.cp-shell-admin` |
**Wichtig:** Die Admin-Startseite hat **keine eigene Kachel-Navigation** wie die
User-Startseite — die Sidebar selbst trägt die Hauptaktionen. Die Admin-Inhaltsfläche
zeigt direkt die Arbeit (Tabellen, Listen, Formulare), nicht zusätzliche Navigations-
Buttons.
**Mobile Sidebar-Mechanik (einzige zusätzliche v1-JS-Ausnahme neben dem Chat):**
Unter dem Breakpoint kollabiert die Sidebar zu einem Hamburger-Icon in einer
schmalen Topbar. Klick öffnet die Sidebar als Off-Canvas-Overlay (kleines
Vanilla-JS: Klasse toggeln, Overlay schließt bei Klick daneben oder auf einen
Menüpunkt). Kein Framework, keine Bibliothek.
**Mandantenfähigkeit gilt für beide Shells unabhängig:** ein neues Team tauscht
sowohl den `--cp-user-brand-*`- als auch den `--cp-admin-brand-*`-Block. Die beiden
Themes werden nie gemischt — Komponenten in der User-Shell nutzen ausschließlich
`--cp-user-*`, Komponenten in der Admin-Shell ausschließlich `--cp-admin-*`.
---
## 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.
- **user** — `rolle` (admin | ehrenamt), Nutzername, Passwort-Hash, Anzeigename,
optionales Profilbild, optionale freiwillige Angaben.
- **planungszeitraum** — Block von mind. 2 Monaten. `status`: in_planung | veroeffentlicht.
- **einsatz** — gehört zu einem Planungszeitraum. 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 Planungszeitraum (≥ 2 Monate) an und trägt die kuratierten Einsätze ein
(Freitags-Touren, Samstags-Einsätze/Partys, Sonderveranstaltungen).
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`** — enthält **zwei vollständig getrennte
Tokensätze**, `--cp-user-*` (User-Shell) und `--cp-admin-*` (Admin-Shell), je
mandantenfähig und mit hell + dunkel via `light-dark()`.
- **User-Theme:** Türkis/Rot, Schrift DM Sans. Status-Mapping: Türkis =
offen/bestätigt/verfügbar · Rot = dringend/Vertretung · Neutral = Info/intern/erledigt.
- **Admin-Theme:** Navy-Sidebar (in beiden Farbmodi gleich dunkel — bewusst, sie ist
das feste Markenelement), helle Arbeitsfläche, Teal für Aktionen/aktive Navigation,
Gelb nur für Sidebar-Icons, Pink nur als Markenakzent (nie als Fehlerfarbe — dafür
ist Rot da). Schrift: Roboto Condensed für UI/Tabellen/Formulare, Alfa Slab One nur
für kurze Seitentitel, Roboto Mono für Zahlen/IDs.
- **Hell/Dunkel** folgt automatisch der Systemeinstellung. Manueller Override über
`<html data-theme="dark|light">` ist vorbereitet (Toggle = Future Log).
- **Nie feste Farben** im Komponenten-CSS — immer Tokens. **Nie Theme-Tokens
mischen** — eine Komponente innerhalb der User-Shell nutzt nur `--cp-user-*`,
innerhalb der Admin-Shell nur `--cp-admin-*`.
- Bekanntes To-do: vorhandenes Mockup-CSS hat fest verdrahtetes Weiß (Topbar,
Bottom-Nav, `.cp-page`-Verlauf). Beim Refactor auf Tokens umstellen, sonst bricht
der Dunkelmodus.
---
## UI-Regeln
### User-Shell
- App-Breite 360460px, 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".
### Admin-Shell
- Desktop-Grundraster: Sidebar 260px + fließender Hauptbereich, Seitenabstand 32px.
- **Sidebar-Punkte (fest, in dieser Reihenfolge):** Start · Planung · Dienste ·
Freigaben · Team · Chat-Verwaltung · Profil — Abmelden unten abgetrennt.
- Aktiver Menüpunkt: Teal-Fläche, weißer Text, gelbes Icon. Inaktiv: gedimmtes Weiß,
gelbes Icon.
- Cards/Panels: Radius 812px (max. 14px), Innenabstand 2030px, sehr dezenter Schatten,
Panel-Header darf `--cp-admin-surface-soft` nutzen.
- Tabellenkopf in Navy mit weißem, fettem Text. Statusspalten farbig **mit Text**, nie
nur über Farbe.
- **Unter dem Breakpoint:** Sidebar kollabiert zu Hamburger-Icon, öffnet als
Off-Canvas-Overlay. Touch-Ziele bleiben ≥ 44px auch im Admin-Bereich.
### Beide Shells
- 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/
│ │ ├── base_user.html # User-Shell: Bottom-Nav
│ │ ├── base_admin.html # Admin-Shell: Sidebar + mobiles Off-Canvas
│ │ └── ... # Teilansichten je Route
│ └── static/
│ ├── tokens.css # beide Theme-Tokensätze (--cp-user-*, --cp-admin-*)
│ ├── components.css # Komponenten der User-Shell
│ ├── components-admin.css # Komponenten der Admin-Shell
│ └── sidebar.js # Hamburger/Off-Canvas-Logik (Vanilla, ~20 Zeilen)
├── 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.