feat: Phase 0 – Gerüst (FastAPI+SQLite, Multi-User-Login, React-App-Shell, Deploy)

Grundgerüst für Certain Finance:
- Backend: FastAPI + SQLAlchemy + SQLite, Alembic-Migrationen (Batch-Mode),
  argon2-Passwort-Hashing, server-seitige Sitzungen im Cookie, Erst-Admin,
  Benutzerverwaltung mit Temporär-Passwort, Einstellungen je Benutzer.
- Ein Prozess, ein Port: uvicorn liefert API (/api) und gebautes SPA aus,
  inkl. SPA-Deeplink-Fallback.
- Frontend: React 18 + Vite + JSX, Design-Tokens (Light/Dark), i18n DE/EN,
  Inline-SVG-Icons (keine Emojis), Login, Passwort-ändern, Dashboard-Platzhalter,
  Benutzer- und Einstellungsseiten.
- Deploy: nativer LXC-Installer + Update-Skript (systemd), env-Vorlage, Doku.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-19 18:27:42 +02:00
co-authored by Claude Opus 4.8
commit 2c795a57c8
59 changed files with 6419 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# Architektur
## Überblick
Ein einzelner Python-Prozess (uvicorn/FastAPI) liefert sowohl die JSON-API unter
`/api/*` als auch das gebaute Frontend (`web/dist`, mit SPA-Fallback) auf **einem**
Port aus. HTTPS terminiert extern der Nginx Proxy Manager; der Dienst lauscht nur
auf `127.0.0.1:<APP_PORT>`.
```
Browser ──HTTPS──> Nginx Proxy Manager ──HTTP──> 127.0.0.1:APP_PORT (uvicorn)
├── /api/* → FastAPI-Router
└── /* → web/dist (SPA)
```
## Verzeichnisse
```
backend/ app/ (config, database, security, deps, main, models, schemas, seed,
migrate, routers/*, services/*), migrations/ (Alembic), requirements.txt
web/ src/ (main.jsx, App.jsx, brand.js, api.js, auth.jsx, settings.jsx,
i18n.js, locales/, format.js, theme.js, styles.css, finance.css,
components/, pages/), package.json, vite.config.js
deploy/ certain-finance.service, install.sh, update.sh, env.example
docs/ ARCHITECTURE.md, ROADMAP.md
```
## Backend
- **Konfiguration** (`app/config.py`): Umgebungsvariablen mit Präfix `APP_`.
Standardwerte sind dev-freundlich; Produktivwerte kommen aus `/etc/certain-finance/env`.
- **Datenbank** (`app/database.py`): SQLite mit WAL, `foreign_keys=ON`, Busy-Timeout.
- **Migrationen**: Alembic (`migrations/`), `render_as_batch=True` (Pflicht für SQLite).
Werden beim App-Start automatisch angewandt (`app/migrate.py`) – und vom Install-/
Update-Skript.
- **Auth** (`app/security.py`, `app/services/sessions.py`, `app/deps.py`): argon2-
Passwort-Hashing; server-seitige Sitzungen (im Cookie nur das Klartext-Token,
in der DB nur dessen SHA-256-Hash). Erst-Admin beim ersten Start; weitere Nutzer
legt der Admin mit Temporär-Passwort an (Änderung beim ersten Login erzwungen).
- **Isolation**: Ab Phase 1 trägt jede fachliche Tabelle ein `owner_id`; jeder
Nutzer sieht ausschließlich seine eigenen Daten.
## Frontend
- React 18 + Vite + reines JSX, Router mit `Protected`-Wrapper (Login immer nötig).
- **Design-Tokens** in `styles.css` (aus der Vorlage übernommen), Ergänzungen in
`finance.css`. Volle Hell/Dunkel-Unterstützung (`prefers-color-scheme` + `data-theme`).
- **i18n** (react-i18next): Deutsch Standard, Englisch optional; Sprache aus der
Benutzer-Einstellung `locale`.
- **Icons**: ausschließlich Inline-SVG (`components/Icon.jsx`), niemals Emojis.
- **API-Client** (`api.js`): alles über `/api`, immer `credentials:"include"`
(Cookie-Sitzung), zentrales 401-Handling.
## Namensgebung
Der Anzeigename „Certain Finance" steht nur in `web/src/brand.js` und
`backend/app/branding.py`. Intern ist alles generisch (Paket `app`, Env-Präfix
`APP_`). Der Betriebs-Slug `certain-finance` (systemd-Dienst, Pfade) steht in den
Deploy-Skripten je einmal oben als Variable.