213 lines
10 KiB
Markdown
213 lines
10 KiB
Markdown
# CLAUDE.md — Projekt-Hub
|
|
|
|
Diese Datei beschreibt den Kontext, die Architektur und die Konventionen für dieses Projekt.
|
|
Sie dient Claude (und anderen Entwicklern) als Einstiegspunkt, bevor Code geschrieben wird.
|
|
|
|
## Hintergrund / Idee
|
|
|
|
Der Nutzer hat ADHS und führt ein analoges Bullet Journal (Logbuch, Weekly Bridge, Monthly
|
|
Log). Projektbezogene Arbeitsaufgaben sollen davon getrennt digital verwaltet werden.
|
|
|
|
Ein erster Prototyp war eine einzelne HTML-Datei mit LocalStorage (Projekte, Aufgaben,
|
|
Fälligkeitsdaten, Export/Import als JSON). Diese Datei dient als **funktionale Referenz**
|
|
für Feature-Set und UI/UX — siehe `reference/projekte.html` (wird vom Nutzer bereitgestellt).
|
|
|
|
Das Ziel jetzt: aus dieser Idee eine **Flask-Webapp** machen, die auf einem eigenen VPS
|
|
läuft (volle Datenhoheit, kein Drittanbieter-Cloud-Dienst). Diese App ist der erste Baustein
|
|
eines **Hubs**, der später um weitere kleine Apps/Module erweitert wird — alle hinter einem
|
|
gemeinsamen Login.
|
|
|
|
## Kernprinzipien
|
|
|
|
1. **Datenschutz / Selbsthosting**: Alle Daten bleiben auf dem eigenen VPS. Keine externen
|
|
Tracker, kein CDN-Zwang für kritische Funktionen (Fallback ohne Internet sollte
|
|
funktionieren oder zumindest nicht hart brechen).
|
|
2. **ADHS-freundlich**: Niedrigschwellig, wenig Klicks, schnelles Erfassen ("Brain dump"),
|
|
sofortiges visuelles Feedback (Fälligkeits-Badges: überfällig/bald/ok), keine
|
|
überladenen Screens.
|
|
3. **Erweiterbarkeit**: Architektur so anlegen, dass weitere "Mini-Apps" als eigene
|
|
Module/Blueprints unter demselben Login + derselben Navigation ergänzt werden können,
|
|
ohne den Kern umzubauen.
|
|
4. **Einfacher Login**: Kein Passwort. Login per E-Mail-Adresse + zeitlich begrenztem
|
|
Code (10 Minuten gültig), der per Mail zugeschickt wird ("Magic Code" / OTP-Login).
|
|
|
|
## Tech-Stack
|
|
|
|
- **Backend**: Python, Flask
|
|
- **Datenbank**: SQLite (ausreichend für Einzelnutzer/kleine Gruppe; Pfad konfigurierbar,
|
|
später ggf. auf Postgres migrierbar — daher SQLAlchemy als ORM verwenden)
|
|
- **Auth**: Flask-Login für Session-Verwaltung + eigene Logik für E-Mail-Code-Versand
|
|
(Flask-Mail oder smtplib, SMTP-Zugangsdaten über Umgebungsvariablen)
|
|
- **Frontend**: Server-seitig gerenderte Templates (Jinja2) + minimal JavaScript für
|
|
interaktive Elemente (Checkbox-Toggle, Filter, evtl. htmx für dynamische Updates ohne
|
|
vollständigen Page-Reload). Kein schweres SPA-Framework — Ladezeit und Einfachheit
|
|
haben Priorität.
|
|
- **Styling**: Eigenes CSS im Stil des Prototyps (Dark Theme, siehe Referenzdatei) als
|
|
Basis-Theme für den ganzen Hub, das von allen Modulen genutzt wird.
|
|
- **Deployment**: VPS, lauffähig hinter einem Reverse Proxy (nginx) via gunicorn.
|
|
`.env`-Datei für Secrets (SMTP, SECRET_KEY, Datenbankpfad). `requirements.txt` pflegen.
|
|
|
|
## Architektur-Überblick
|
|
|
|
```
|
|
projekt-hub/
|
|
├── app/
|
|
│ ├── __init__.py # App-Factory, Extensions-Init, Blueprint-Registrierung
|
|
│ ├── config.py # Config-Klassen (liest aus .env)
|
|
│ ├── extensions.py # db, login_manager, mail etc.
|
|
│ ├── models.py # User, LoginCode (gemeinsame Modelle)
|
|
│ ├── auth/ # Auth-Modul (Blueprint)
|
|
│ │ ├── __init__.py
|
|
│ │ ├── routes.py # /login, /verify, /logout
|
|
│ │ └── forms.py # E-Mail-Eingabe, Code-Eingabe
|
|
│ ├── projects/ # Modul 1: Projekte & Aufgaben (aus dem Prototyp)
|
|
│ │ ├── __init__.py
|
|
│ │ ├── routes.py
|
|
│ │ ├── models.py # Project, Task
|
|
│ │ └── templates/projects/
|
|
│ ├── templates/
|
|
│ │ ├── base.html # gemeinsames Layout, Navigation, Theme
|
|
│ │ └── auth/
|
|
│ │ ├── login.html
|
|
│ │ └── verify.html
|
|
│ └── static/
|
|
│ └── css/main.css # Dark-Theme-Basis aus dem Prototyp
|
|
├── migrations/ # Flask-Migrate / Alembic
|
|
├── instance/ # SQLite-Datei (nicht versionieren)
|
|
├── .env.example
|
|
├── requirements.txt
|
|
├── wsgi.py
|
|
└── run.py # lokaler Dev-Server
|
|
```
|
|
|
|
### Erweiterbarkeit für künftige Module
|
|
|
|
Jedes neue Mini-App-Modul:
|
|
- ist ein eigenes Python-Package mit eigenem Blueprint (`app/<modulname>/`)
|
|
- bringt eigene Models, Routes, Templates mit (Templates unter `templates/<modulname>/`)
|
|
- wird in `app/__init__.py` per `app.register_blueprint(...)` eingebunden
|
|
- erscheint automatisch als Eintrag in der gemeinsamen Navigation (`base.html`), idealerweise
|
|
über eine zentrale Liste/Registry, die Modulname + URL + Icon enthält
|
|
- nutzt denselben `current_user` (Flask-Login) — kein eigenes Auth nötig
|
|
|
|
Ziel: ein neues Modul hinzufügen = neuen Ordner anlegen, Blueprint registrieren,
|
|
Navigationseintrag ergänzen. Kern-App, Auth und Theme bleiben unangetastet.
|
|
|
|
## Datenmodell (Modul "Projekte")
|
|
|
|
**User**
|
|
- id
|
|
- email (unique)
|
|
- created_at
|
|
|
|
**LoginCode**
|
|
- id
|
|
- user_id (FK)
|
|
- code (6-stellig, numerisch)
|
|
- created_at
|
|
- expires_at (created_at + 10 Minuten)
|
|
- used (bool)
|
|
|
|
**Project**
|
|
- id
|
|
- user_id (FK)
|
|
- name
|
|
- color (Hex-Wert, aus fester Palette wie im Prototyp)
|
|
- created_at
|
|
|
|
**Task**
|
|
- id
|
|
- user_id (FK)
|
|
- project_id (FK, nullable — Aufgaben ohne Projekt erlaubt)
|
|
- text
|
|
- due_date (nullable)
|
|
- done (bool, default False)
|
|
- created_at
|
|
|
|
## Auth-Flow (E-Mail-Code-Login)
|
|
|
|
1. Nutzer gibt E-Mail-Adresse auf `/login` ein.
|
|
2. Backend prüft, ob User mit dieser E-Mail existiert — falls nicht, wird er angelegt
|
|
(passwortlose Self-Registration; ggf. später auf Allowlist beschränkbar für
|
|
Einzelnutzer-Setup).
|
|
3. Backend generiert 6-stelligen Code, speichert Hash + `expires_at = now + 10min`,
|
|
sendet Code per E-Mail (Betreff klar, kurzer Text, kein HTML-Tracking).
|
|
4. Nutzer landet auf `/verify`, gibt Code ein.
|
|
5. Backend prüft: Code korrekt, nicht abgelaufen, nicht bereits benutzt → Login via
|
|
Flask-Login (`login_user`), Code als `used` markieren.
|
|
6. Alte/abgelaufene Codes regelmäßig aufräumen (z.B. bei jedem neuen Code-Request für
|
|
denselben User).
|
|
7. Rate-Limiting: max. X Code-Anfragen pro E-Mail pro Stunde, um Spam/Missbrauch zu
|
|
verhindern (z.B. Flask-Limiter).
|
|
|
|
Sicherheitsaspekte:
|
|
- Code wird gehasht gespeichert (nicht im Klartext in der DB).
|
|
- Session-Cookie: `Secure`, `HttpOnly`, `SameSite=Lax`.
|
|
- HTTPS wird vom Reverse Proxy (nginx + Let's Encrypt) terminiert — App selbst geht von
|
|
HTTPS aus (`PREFERRED_URL_SCHEME = 'https'`).
|
|
|
|
## Feature-Set Modul "Projekte" (aus dem Prototyp übernehmen)
|
|
|
|
- Projekte anlegen/löschen, mit fester Farbpalette (zyklisch zugewiesen)
|
|
- Aufgaben anlegen mit: Text, optionalem Projekt, optionalem Fälligkeitsdatum
|
|
- Aufgaben abhaken (done/undone), löschen
|
|
- Fälligkeits-Badges: überfällig (rot), diese Woche (orange), normal (grün), kein Datum
|
|
- Ansicht "Nach Projekt" (gruppiert, mit Klapp-/Zähl-Funktion) + Ansicht "Alle Aufgaben"
|
|
(gefiltert: alle / offen / überfällig / diese Woche / erledigt)
|
|
- Statistik-Leiste (offen / erledigt / überfällig / Anzahl Projekte)
|
|
- Da Daten jetzt serverseitig in SQLite liegen und auf dem VPS gesichert werden,
|
|
entfällt der JSON-Export/Import als Sync-/Backup-Mechanismus. Stattdessen:
|
|
**PDF-Export** — eine projektbasierte To-Do-Liste zum Ausdrucken (offene und
|
|
erledigte Aufgaben, erledigte abgehakt/durchgestrichen, Aufgaben ohne Projekt in
|
|
eigenem Abschnitt). Erzeugt mit fpdf2 (reines Python, keine System-Abhängigkeiten);
|
|
DejaVu-Schrift im Repo mitgeliefert für identisches Rendering auf dem VPS.
|
|
|
|
## Nicht-Ziele (für jetzt)
|
|
|
|
- Keine Multi-Tenant-Mandantentrennung über User hinaus (Familien-/Team-Sharing später,
|
|
falls gewünscht)
|
|
- Kein OAuth/Social Login
|
|
- Kein Offline-First/PWA-Sync (kann später ergänzt werden)
|
|
- Kein Rich-Text/Markdown in Aufgaben (bewusst simpel halten)
|
|
|
|
## Nächste Schritte (Vorschlag für Umsetzungsreihenfolge)
|
|
|
|
1. Projektgerüst (App-Factory, Config, `.env.example`, `requirements.txt`)
|
|
2. Models + DB-Migration (User, LoginCode, Project, Task)
|
|
3. Auth-Modul (E-Mail-Code-Login, Templates für `login.html` / `verify.html`)
|
|
4. Basis-Layout `base.html` mit Navigation + Dark-Theme-CSS (aus Prototyp übernehmen)
|
|
5. Modul "Projekte": Routes + Templates, 1:1-Funktionsumfang aus dem HTML-Prototyp
|
|
6. PDF-Export (projektbasierte To-Do-Liste zum Ausdrucken, fpdf2)
|
|
7. Deployment-Vorbereitung: `wsgi.py`, gunicorn-Konfiguration, Beispiel-nginx-Config,
|
|
systemd-Service-Datei
|
|
|
|
## Entscheidungen (geklärt)
|
|
|
|
- **SMTP-Anbieter**: Proton Mail (eigene Adresse). Da Proton Mail Bridge eine
|
|
Desktop-Anwendung ist und nur mit zahlendem Plan läuft, wird sie testweise auf dem
|
|
VPS via Docker betrieben (lokaler SMTP-Relay auf `127.0.0.1`). Falls das auf dem
|
|
Server unzuverlässig läuft, ist ein **Fallback auf einen EU-SMTP-Relay-Dienst**
|
|
(z.B. Infomaniak, Mailjet EU-Region) als austauschbare Alternative vorgesehen — die
|
|
App liest SMTP-Host/Port/User/Passwort ausschließlich aus `.env`, sodass der Anbieter
|
|
ohne Codeänderung wechselbar ist.
|
|
- **Self-Registration**: Vorerst nur **eine** erlaubte E-Mail-Adresse (Allowlist mit
|
|
einem Eintrag in `.env`, z.B. `ALLOWED_EMAILS=deine@adresse.com`). Spätere
|
|
Erweiterung auf mehrere Adressen ist durch eine kommagetrennte Liste oder eigene
|
|
DB-Tabelle vorbereitet, aber jetzt nicht nötig.
|
|
- **Domain**: Noch nicht final. App wird so konfiguriert, dass Domain/Host über `.env`
|
|
(`SERVER_NAME` bzw. Reverse-Proxy-Konfiguration) gesetzt wird. Bis zur
|
|
Domain-Entscheidung ist die App über IP:Port oder eine Subdomain-Platzhalter
|
|
erreichbar; Cookie-Settings (`SESSION_COOKIE_DOMAIN`) werden erst final gesetzt,
|
|
wenn die Domain feststeht.
|
|
|
|
## Referenzdatei
|
|
|
|
`reference/projekte.html` — der funktionsfähige HTML/JS-Prototyp (Dark Theme,
|
|
LocalStorage, Export/Import). Dient als Vorlage für:
|
|
- Farbpalette und CSS-Variablen (Basis für `static/css/main.css`)
|
|
- UI-Struktur (Stats-Leiste, Formular, Projekt-Karten, Aufgabenliste, Filter-Buttons)
|
|
- Fälligkeits-Badge-Logik (`dueBadge`-Funktion → als Jinja-Filter oder Python-Helper
|
|
übernehmen)
|
|
- Datenmodell-Felder (Project: id/name/color; Task: id/text/project/due/done)
|
|
|
|
|