docs: Wiki-Seiten mit Projektdokumentation befüllen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Daniel Krähenbühl
2026-05-20 08:26:32 +02:00
parent 91cffbe10b
commit fd3ea0c5af
5 changed files with 579 additions and 0 deletions
+120
@@ -1,2 +1,122 @@
# Architektur-Übersicht # 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/<key>/` | 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/<year>/` | Jahr-Detail |
| POST | `/api/financial-years/<year>/copy-from/<source>/` | Jahr kopieren |
| GET/POST | `/api/financial-years/<year>/incomes/` | Einnahmen |
| GET/POST | `/api/financial-years/<year>/budget-items/` | Fixkosten |
| GET/POST | `/api/households/` | Haushalte |
| POST | `/api/households/<pk>/invite/` | Mitglied einladen |
| POST | `/api/households/<pk>/accept/` | Einladung annehmen |
| POST | `/api/households/<pk>/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
+88
@@ -1,2 +1,90 @@
# Contributing Guide # 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
+110
@@ -1,2 +1,112 @@
# Deployment-Guide # 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
+111
@@ -1,2 +1,113 @@
# Developer Setup # 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<boolean>`)
+150
@@ -1,2 +1,152 @@
# Feature-Dokumentation # 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