# 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:`. ``` 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.