268 lines
13 KiB
Markdown
268 lines
13 KiB
Markdown
# 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 360–460px.
|
||
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 360–460px) | 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 360–460px, 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 8–12px (max. 14px), Innenabstand 20–30px, 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.
|