From fd3ea0c5af6a165afda39d260ba6a8dcec1a5ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Kr=C3=A4henb=C3=BChl?= Date: Wed, 20 May 2026 08:26:32 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Wiki-Seiten=20mit=20Projektdokumentatio?= =?UTF-8?q?n=20bef=C3=BCllen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- Architektur-Uebersicht.md | 120 ++++++++++++++++++++++++++++++ Contributing-Guide.md | 88 ++++++++++++++++++++++ Deployment-Guide.md | 110 ++++++++++++++++++++++++++++ Developer-Setup.md | 111 ++++++++++++++++++++++++++++ Feature-Dokumentation.md | 150 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 579 insertions(+) diff --git a/Architektur-Uebersicht.md b/Architektur-Uebersicht.md index 2df3d7f..a1c2a0e 100644 --- a/Architektur-Uebersicht.md +++ b/Architektur-Uebersicht.md @@ -1,2 +1,122 @@ # Architektur-Übersicht +## Stack + +| Schicht | Technologie | +|---|---| +| Frontend | Angular 21, Standalone Components, Signals | +| Styling | Tailwind CSS v4, Flowbite Design System | +| Charts | ApexCharts 3.46 | +| i18n | ngx-translate (DE, FR, IT, EN) | +| Backend | Django REST Framework, Python 3.12 | +| Auth | SimpleJWT (Access 60min, Refresh 7d, Rotation + Blacklist) | +| Datenbank | PostgreSQL | +| E-Mail | Brevo SMTP (`smtp-relay.brevo.com:587`) | +| Server | Hetzner Ubuntu 24.04, Gunicorn + Nginx, Certbot (HTTPS) | +| Font | Roboto via `@fontsource/roboto` (selbst-gehostet, DSGVO-konform) | + +## Verzeichnisstruktur + +``` +armarium-suite/ +├── backend/ +│ ├── core/ # Django-Projektkonfiguration (settings, urls) +│ ├── finance/ # Haupt-App (Models, Views, Serializers) +│ │ ├── migrations/ +│ │ ├── models.py +│ │ ├── views.py +│ │ ├── serializers.py +│ │ ├── email.py # send_email() Helper +│ │ └── backends.py # EmailAuthBackend +│ ├── templates/emails/ # HTML + Plaintext E-Mail-Templates +│ ├── requirements.txt +│ └── .env # Nicht im Repo +└── frontend/ + ├── src/app/ + │ ├── auth/ # Login, Register, ForgotPassword, ResetPassword, VerifyEmail + │ ├── dashboard/ + │ ├── services/ # ApiService, AuthService, FinancialYearService, ... + │ ├── layout/ # Shell, Navbar, Sidebar + │ └── ... + ├── src/assets/i18n/ # de.json, en.json, fr.json, it.json + └── src/budget-app-theme.css # Tailwind v4 Custom Theme (Violet Primary) +``` + +## Datenmodelle + +| Modell | Beschreibung | +|---|---| +| `Profile` | Erweitertes User-Profil (Avatar, Kanton, 2FA, Tokens, Prefs) | +| `Account` | Konten (asset, expense, revenue) | +| `Transaction` | Doppelte Buchführung (source + destination Account) | +| `Budget` | Budgetkategorien (7 Kategorien) | +| `Expense` | Ausgaben mit Fälligkeitsdatum | +| `Deadline` | Termine (Steuern, Versicherung, Rechnung, etc.) | +| `UserSession` | Aktive Sessions mit Gerätename, IP, JWT-JTI | +| `BackupCode` | 2FA-Backup-Codes (SHA-256-Hash) | +| `FinancialYear` | Jahresplanung (User oder Haushalt) | +| `YearlyIncome` | Einnahmen pro Jahr | +| `YearlyBudgetItem` | Fixkosten pro Jahr | +| `Household` | Gemeinsamer Haushalt | +| `HouseholdMembership` | Haushalt-Mitgliedschaft mit Rolle und Status | + +## API-Endpunkte (Übersicht) + +### Auth +| Methode | Endpunkt | Beschreibung | +|---|---|---| +| POST | `/api/auth/register/` | Registrierung (sendet Bestätigungsmail) | +| POST | `/api/auth/verify-email/` | E-Mail bestätigen | +| POST | `/api/auth/token/` | Login | +| POST | `/api/auth/token/refresh/` | JWT erneuern | +| POST | `/api/auth/logout/` | Logout + Blacklist | +| POST | `/api/auth/password/` | Passwort ändern | +| POST | `/api/auth/password-reset/` | Reset anfordern | +| POST | `/api/auth/password-reset/confirm/` | Neues Passwort setzen | +| POST | `/api/auth/2fa/login/` | TOTP-Verifikation | +| POST | `/api/auth/2fa/setup/` | 2FA einrichten | +| POST | `/api/auth/2fa/enable/` | 2FA aktivieren | +| POST | `/api/auth/2fa/disable/` | 2FA deaktivieren | +| POST | `/api/auth/2fa/recover/` | Recovery-Code anfordern | +| POST | `/api/auth/2fa/recover/confirm/` | Recovery bestätigen | +| GET | `/api/auth/sessions/` | Session-Liste | +| DELETE | `/api/auth/sessions//` | Session widerrufen | +| DELETE | `/api/auth/sessions/revoke-all/` | Alle anderen Sessions widerrufen | + +### Daten +| Methode | Endpunkt | Beschreibung | +|---|---|---| +| GET/PUT | `/api/profile/` | Profil lesen/aktualisieren | +| GET/POST/PUT/DELETE | `/api/accounts/` | Konten | +| GET/POST/PUT/DELETE | `/api/transactions/` | Transaktionen | +| GET/POST/PUT/DELETE | `/api/budgets/` | Budgets | +| GET/POST/PUT/DELETE | `/api/expenses/` | Ausgaben | +| GET/POST/PUT/DELETE | `/api/deadlines/` | Termine | +| GET | `/api/export/` | ZIP-Export (6 PDFs) | +| GET | `/api/search/` | Globale Suche | +| GET | `/api/notifications/` | Benachrichtigungen | +| PATCH | `/api/notifications/prefs/` | Benachrichtigungs-Prefs | + +### Jahresplanung +| Methode | Endpunkt | Beschreibung | +|---|---|---| +| GET/POST | `/api/financial-years/` | Jahre auflisten / erstellen | +| GET/PATCH/DELETE | `/api/financial-years//` | Jahr-Detail | +| POST | `/api/financial-years//copy-from//` | Jahr kopieren | +| GET/POST | `/api/financial-years//incomes/` | Einnahmen | +| GET/POST | `/api/financial-years//budget-items/` | Fixkosten | +| GET/POST | `/api/households/` | Haushalte | +| POST | `/api/households//invite/` | Mitglied einladen | +| POST | `/api/households//accept/` | Einladung annehmen | +| POST | `/api/households//leave/` | Haushalt verlassen | + +## Sicherheits-Architektur + +- **JWT**: Access-Token 60min, Refresh-Token 7 Tage, Rotation + Blacklist +- **2FA**: TOTP (pyotp), HMAC-signierter Temp-Token (5min), Replay-Schutz, 8 Backup-Codes (SHA-256) +- **Passwort-Reset**: Token als SHA-256-Hash in DB, 15min TTL, anti-enumeration Response +- **E-Mail-Verifikation**: Token als SHA-256-Hash, 24h TTL +- **Rate-Limiting**: 5/min Auth, 200/min User, 20/min Anon +- **Sessions**: Alle Sessions werden bei Passwortänderung/-reset invalidiert +- **Produktion**: HTTPS-Redirect, HSTS (1 Jahr), Secure Cookies, Content-Type-Nosniff +- **CAPTCHA**: Cloudflare Turnstile auf Login + Register diff --git a/Contributing-Guide.md b/Contributing-Guide.md index a320bea..caf2db3 100644 --- a/Contributing-Guide.md +++ b/Contributing-Guide.md @@ -1,2 +1,90 @@ # Contributing Guide +## Branch-Strategie + +``` +main ← Produktions-Stand (entspricht Live-Server) +develop ← Aktiver Entwicklungs-Branch +feature/* ← Feature-Branches (werden in develop gemergt) +fix/* ← Bugfix-Branches +``` + +- Neue Features immer von `develop` abzweigen +- Fertige Features via Merge (no-ff) in `develop` +- `develop` → `main` nur bei einem Release + +## Commit-Konventionen + +Format: `type: kurze Beschreibung` + +| Typ | Verwendung | +|---|---| +| `feat` | Neues Feature | +| `fix` | Bugfix | +| `chore` | Build, Konfiguration, Abhängigkeiten | +| `docs` | Dokumentation | +| `refactor` | Refactoring ohne Funktionsänderung | +| `security` | Sicherheits-Fix | + +Beispiele: +``` +feat: email verification on registration +fix: mobile navbar overflow on small screens +chore: update Brevo SMTP config in .env.example +``` + +## Release-Prozess + +1. `develop` vollständig und getestet +2. CHANGELOG.md aktualisieren (`[Unreleased]` → `[x.y.z] - YYYY-MM-DD`) +3. Commit auf `develop`, Push +4. `develop` → `main` mergen (no-ff) +5. Tag `vx.y.z` erstellen und pushen +6. Deploy auf Hetzner (siehe [Deployment-Guide](Deployment-Guide)) + +## Versionierung + +Semantic Versioning: `MAJOR.MINOR.PATCH` + +| | Wann | +|---|---| +| PATCH | Bugfixes, kleine Anpassungen | +| MINOR | Neue Features, abwärtskompatibel | +| MAJOR | Breaking Changes | + +## Codeberg Remote + +``` +SSH: ssh://git@codeberg.org/Armarium-Suite/armarium-suite.git +HTTPS: https://codeberg.org/Armarium-Suite/armarium-suite.git +``` + +## i18n-Regel + +Neue Texte immer in **allen 4 Sprachdateien** gleichzeitig erfassen: + +``` +frontend/src/assets/i18n/de.json ← Deutsch (Primärsprache) +frontend/src/assets/i18n/en.json +frontend/src/assets/i18n/fr.json +frontend/src/assets/i18n/it.json +``` + +## Design-Regeln + +- Primary Color: Violet (`#7c3aed` / `bg-violet-700`) +- Icons: Flowbite Outline für Navbar/Modals, Fill für Sidebar-Navigation +- Kein Flowbite JS Runtime — alle Interaktionen als Angular Signals +- Touch-Targets: mindestens `p-2` auf Icon-Buttons +- Mobile-first: `grid-cols-1 sm:grid-cols-2`, `flex-col sm:flex-row` + +## Sicherheits-Checkliste + +Vor jedem Merge in `develop` prüfen: + +- [ ] Keine Credentials im Code (Tokens, Passwörter, API-Keys) +- [ ] Neue Endpunkte mit `IsAuthenticated` oder `AllowAny` korrekt gesetzt +- [ ] Neue `AllowAny`-Endpunkte mit `AuthThrottle` (5/min) gesichert +- [ ] Neue Felder in Serializer-`exclude` wenn nötig +- [ ] Migrations erstellt und geprüft +- [ ] i18n in allen 4 Sprachen aktualisiert diff --git a/Deployment-Guide.md b/Deployment-Guide.md index b75bd50..0c89d1b 100644 --- a/Deployment-Guide.md +++ b/Deployment-Guide.md @@ -1,2 +1,112 @@ # Deployment-Guide +## Server-Infos + +| | | +|---|---| +| Server | `armarium-test` | +| IPv4 | `178.104.167.52` | +| OS | Ubuntu 24.04 | +| SSH | `ssh root@178.104.167.52` | +| App-Verzeichnis | `/home/armarium/armarium-suite/` | +| Frontend-Dist | `/home/armarium/armarium-suite/frontend/dist/budget-frontend/browser` | +| Systemd-Service | `armarium.service` | +| Gunicorn Socket | `unix:/run/armarium/armarium.sock` | +| Nginx-Config | `/etc/nginx/sites-enabled/` | +| Domain | `https://app.armarium.ch` (Certbot, HTTPS) | + +## Deploy-Schritte + +```bash +# 1. Einloggen +ssh root@178.104.167.52 + +# 2. Code aktualisieren +cd /home/armarium/armarium-suite +git pull origin main + +# 3. Backend: Abhängigkeiten + Migrationen +cd backend +source venv/bin/activate +pip install -r requirements.txt --quiet +python manage.py migrate + +# 4. Frontend bauen +cd ../frontend +npm install --silent +npm run build -- --configuration production + +# 5. Service neu starten +systemctl restart armarium +``` + +## Logs + +```bash +# Live-Logs (Gunicorn/Django) +journalctl -u armarium -f + +# Nginx Access-Log +tail -f /var/log/nginx/access.log +``` + +## .env auf dem Server + +Die Datei `/home/armarium/armarium-suite/backend/.env` ist **nicht im Repo** und muss nach dem ersten Setup manuell gepflegt werden. + +Neue Variablen nach einem Update manuell ergänzen: + +```bash +nano /home/armarium/armarium-suite/backend/.env +``` + +### Wichtige Produktions-Variablen + +```env +SECRET_KEY=... +DEBUG=False +ALLOWED_HOSTS=178.104.167.52,app.armarium.ch +CSRF_TRUSTED_ORIGINS=https://app.armarium.ch +CORS_ALLOWED_ORIGINS=https://app.armarium.ch +DB_NAME=armarium_db +DB_USER=armarium_user +DB_PASSWORD=... +DB_HOST=localhost +DB_PORT=5432 +TURNSTILE_SECRET_KEY=... +FRONTEND_URL=https://app.armarium.ch +EMAIL_HOST=smtp-relay.brevo.com +EMAIL_PORT=587 +EMAIL_USE_TLS=True +EMAIL_HOST_USER=... +EMAIL_HOST_PASSWORD=... +DEFAULT_FROM_EMAIL=noreply@armarium.ch +``` + +## Nginx + +Nginx-Config unter `/etc/nginx/sites-enabled/`. Nach Änderungen: + +```bash +nginx -t && systemctl reload nginx +``` + +> **Wichtig:** Die `/api/`- und `/admin/`-Location-Blöcke müssen `proxy_set_header X-Forwarded-Proto https;` enthalten — sonst erzeugt Django's `SECURE_SSL_REDIRECT` eine 301-Schleife. + +## E-Mail testen + +```bash +cd /home/armarium/armarium-suite/backend +source venv/bin/activate +python manage.py shell +``` + +```python +from finance.email import send_email +send_email('password_changed', {}, 'Test', 'deine@email.ch') +``` + +## Bekannte Hinweise + +- Roboto-Fonts erscheinen als 404 in Nginx-Logs (`/media/roboto-*`) — unkritisch, Fonts laden aus dem Angular-Bundle +- `DEBUG=False` aktiviert automatisch SMTP, HTTPS-Redirect, HSTS und Secure Cookies diff --git a/Developer-Setup.md b/Developer-Setup.md index f7c6b0b..17c5ae9 100644 --- a/Developer-Setup.md +++ b/Developer-Setup.md @@ -1,2 +1,113 @@ # Developer Setup +## Voraussetzungen + +- WSL2 (Ubuntu) auf Windows — oder direkt Linux/macOS +- Python 3.12 +- Node.js 20+ +- PostgreSQL +- Git + +## Repository klonen + +```bash +git clone ssh://git@codeberg.org/Armarium-Suite/armarium-suite.git +cd armarium-suite +``` + +## Backend Setup + +```bash +cd backend + +# Virtuelle Umgebung erstellen und aktivieren +python3 -m venv venv +source venv/bin/activate + +# Abhängigkeiten installieren +pip install -r requirements.txt + +# .env erstellen (Vorlage: .env.example) +cp .env.example .env +# .env mit eigenen Werten befüllen (DB, Secret Key, etc.) + +# Datenbank erstellen (PostgreSQL) +createdb budget_db + +# Migrationen anwenden +python manage.py migrate + +# Entwicklungsserver starten +python manage.py runserver +``` + +### Wichtige `.env`-Variablen + +```env +SECRET_KEY=... +DEBUG=True +ALLOWED_HOSTS=localhost,127.0.0.1 +DB_NAME=budget_db +DB_USER=... +DB_PASSWORD=... +DB_HOST=localhost +DB_PORT=5432 +TURNSTILE_SECRET_KEY=... # Cloudflare Turnstile (bei DEBUG=True automatisch bypassed) +EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend # Brevo auch lokal nutzen +EMAIL_HOST=smtp-relay.brevo.com +EMAIL_PORT=587 +EMAIL_USE_TLS=True +EMAIL_HOST_USER=... +EMAIL_HOST_PASSWORD=... +DEFAULT_FROM_EMAIL=noreply@armarium.ch +FRONTEND_URL=http://localhost:4200 +``` + +> Bei `DEBUG=True` werden Mails standardmässig nur im Terminal ausgegeben. `EMAIL_BACKEND` auf SMTP setzen um Brevo auch lokal zu nutzen. + +## Frontend Setup + +```bash +cd frontend + +# Abhängigkeiten installieren +npm install + +# Dev-Server starten (Proxy zu Django auf :8000) +npm start +``` + +Die App ist dann unter `http://localhost:4200` erreichbar. Der Angular Dev-Server proxied `/api/`-Requests automatisch via `proxy.conf.json` zu Django. + +## Beide Server gleichzeitig starten + +```bash +# Im Root-Verzeichnis +./start.sh +``` + +## Branch-Strategie + +| Branch | Zweck | +|---|---| +| `main` | Produktions-Stand, entspricht dem Live-Server | +| `develop` | Aktiver Entwicklungs-Branch, Basis für Features | +| `feature/*` | Feature-Branches, werden in `develop` gemergt | + +## i18n + +Alle 4 Sprachdateien immer gleichzeitig aktualisieren: + +``` +frontend/src/assets/i18n/de.json +frontend/src/assets/i18n/en.json +frontend/src/assets/i18n/fr.json +frontend/src/assets/i18n/it.json +``` + +## Design System + +- **Primary Color**: Violet (`#7c3aed`) +- **Theme**: `frontend/src/budget-app-theme.css` (Tailwind v4) +- **Icons**: Flowbite Outline für Navbar/Modals, Fill für Sidebar-Navigation +- **Kein Flowbite JS**: Dropdowns/Modals als Angular Signals (`signal`) diff --git a/Feature-Dokumentation.md b/Feature-Dokumentation.md index fdc4b4a..4adc396 100644 --- a/Feature-Dokumentation.md +++ b/Feature-Dokumentation.md @@ -1,2 +1,152 @@ # Feature-Dokumentation +## Authentifizierung + +### Registrierung +- E-Mail + Passwort (min. 8 Zeichen) +- Cloudflare Turnstile CAPTCHA +- Nach Registrierung: Bestätigungsmail mit Link (24h gültig) +- Route: `/register` + +### Login +- E-Mail-basiert (kein Username), case-insensitiv +- "Angemeldet bleiben"-Checkbox: `localStorage` (persistent) vs. `sessionStorage` +- Bei aktivierter 2FA: zweistufiger Flow (Credentials → TOTP-Code) +- Route: `/login` + +### Passwort vergessen +- E-Mail eingeben → Reset-Link per Mail (15min gültig) +- Anti-Enumeration: gleiche Antwort unabhängig ob Konto existiert +- Route: `/forgot-password` + +### Passwort zurücksetzen +- Token aus Mail-Link, neues Passwort eingeben +- Bei Erfolg: alle aktiven Sessions werden invalidiert +- Route: `/reset-password?token=...` + +### E-Mail-Verifikation +- Token aus Bestätigungsmail, automatische Verifikation beim Laden +- Route: `/verify-email?token=...` + +--- + +## 2-Faktor-Authentifizierung (2FA) + +- **Setup**: QR-Code scannen mit Authenticator-App (Proton Pass, Aegis, Raivo OTP) +- **Login**: 6-stelliger TOTP-Code, wechselt alle 30 Sekunden +- **Backup-Codes**: 8 Codes im Format `XXXXXXXX-XXXXXXXX`, SHA-256-Hash in DB; Copy + PDF-Download +- **Recovery**: E-Mail-Code (15min) wenn Gerät verloren; deaktiviert 2FA +- Verwaltung unter: `/settings` + +--- + +## Dashboard (`/dashboard`) + +### KPI-Cards +- Gesamteinnahmen, Fixkosten, Variable Ausgaben, Verfügbarer Betrag, Sparquote + +### Einnahmen vs. Ausgaben (Bar Chart) +- 3 Serien: Einnahmen, Fixkosten, Variable Ausgaben +- Jahres-Dropdown (öffnet nach oben) +- ApexCharts, custom Tooltip in Landessprache + +### Fixkostenaufschlüsselung (Pie Chart) +- %-Labels direkt auf Segmenten +- Toggle-Button wechselt zur Listenansicht (Name, CHF, %) + +### Sparquote +- Progress-Bar mit Violet Ziel-Marker +- Ziel personalisierbar über Settings-Toggle (gespeichert im Profil) + +--- + +## Jahresplanung (`/financial-year`) + +- **Jahres-Dropdown**: verfügbare Jahre auswählen +- **3 Summary-Cards**: Einnahmen, Fixkosten, Verfügbar + Sparquote +- **Tab Einnahmen**: Inline-CRUD für Einnahmequellen pro Jahr +- **Tab Fixkosten**: Inline-CRUD für Fixkostenpositionen pro Jahr +- **Neues Jahr starten**: max. 1 Jahr im Voraus, Daten aus Vorjahr kopierbar +- **Haushalt**: gemeinsamen Haushalt gründen, Mitglieder einladen, Rollen verwalten + +--- + +## Kalender (`/calendar`) + +- Jahresansicht mit Monats-Klick für Detailansicht +- Schweizer Feiertage und Schulferien nach Kanton (OpenHolidays API, mit Fallback) +- Persönliche Termine (Deadlines) einpflegen +- iCal-Feed abonnieren (persönlicher Link unter Einstellungen) + +--- + +## Konten (`/accounts`) + +- Drei Kontotypen: Asset (Bank/Cash), Expense (Empfänger), Revenue (Einnahmequelle) +- Vollständiges CRUD + +--- + +## Budgets (`/budgets`) + +- 7 Kategorien: Fixkosten, Mobilfunk/Internet, Abonnements, Freizeit, Steuerrücklagen, Versicherungen, Kredite +- Info-Modal wenn keine Konten vorhanden + +--- + +## Ausgaben (`/expenses`) + +- 10 Kategorien, optionales Fälligkeitsdatum +- Kategoriefilter +- Info-Modal wenn keine Konten vorhanden + +--- + +## Transaktionen (`/transactions`) + +- Doppelte Buchführung (Source + Destination Account) +- Vollständiges CRUD + +--- + +## Einstellungen (`/settings`) + +| Bereich | Beschreibung | +|---|---| +| Profil | Avatar, Name, Kanton, Sprache, Recovery-E-Mail | +| 2FA | Aktivieren/Deaktivieren, QR-Code, Backup-Codes | +| Aktive Sessions | Alle eingeloggten Geräte, einzeln widerrufbar | +| Benachrichtigungen | Toggles für Termine, Budget-Warnungen, Monatszusammenfassung | +| Datenexport | ZIP mit 6 PDFs (Profil, Konten, Budgets, Ausgaben, Transaktionen, Termine) | +| Danger Zone | Account löschen (dreistufig: Export → Passwort + Phrase → Redirect) | + +--- + +## E-Mail-Benachrichtigungen + +| Trigger | Template | Gültigkeit | +|---|---|---| +| Registrierung | `registration_confirm` | 24h | +| Passwort zurücksetzen | `password_reset` | 15min | +| Passwort geändert | `password_changed` | — | +| E-Mail-Adresse geändert | `email_changed` | — | +| 2FA-Recovery | `2fa_recovery` | 15min | + +Alle Mails: HTML + Plaintext-Fallback, Absender `noreply@armarium.ch` via Brevo. + +--- + +## Lokalisierung + +- 4 Sprachen: Deutsch, Englisch, Französisch, Italienisch +- Sprachwahl auf Login/Register und in den Einstellungen +- Browser-Sprache wird automatisch erkannt +- Schweizer Feiertage in der gewählten App-Sprache + +--- + +## Globale Suche + +- Suche über Konten, Budgets, Ausgaben, Transaktionen, Termine +- Mindestlänge: 2 Zeichen +- Erreichbar via Suchfeld in der Navbar