v1.3: Serverseitige Datenbank (PostgreSQL + Node-API) ersetzt localStorage

- server/: Express-API (Auth, Bootstrap, Tickets, Threads, Benutzerverwaltung, Codes)
  mit pg-Schema (11 Tabellen), idempotem Seed (50 Wohnungen, 552 Buchungen)
- mp-db (PostgreSQL 16, Volume mp_pgdata) + mp-api im Compose-Stack,
  nginx proxiet /api/ an mp-api; deploy.sh baut API-Image auf dem Server
- Frontend: Store laedt /api/bootstrap, Schreibzugriff async, kein localStorage
  mehr (ausser Theme), Ladebildschirm beim Session-Check, vite-Proxy fuer Dev
- Rollenrechte serverseitig: Mieter nur eigene Wohnung (getestet, 403-Verweis)
- Mail-Benachrichtigungen komplett serverseitig (server/src/mail.js)
- beispieldaten.py schreibt server/seed/generated.json; Verwaltungs-Mail = axel@hocks.eu
- E2E live verifiziert: Login, Scoping, Ticket + Zustellung (status=sent),
  Registrierung, Codes; Testdaten bereinigt; Doku nachgefuehrt
This commit is contained in:
2026-10-02 12:54:44 +02:00
parent 5503ce5fc5
commit 311153b3c3
26 changed files with 8873 additions and 894 deletions
+19 -8
View File
@@ -15,16 +15,23 @@ Live-Ziel: `https://mieterportal.hocks.eu`.
**Anmeldung erforderlich** – Gruppen: **Verwaltung** und **Mieter** (Registrierung der Mieter per Code auf der Startseite).
Demo-Zugänge (Passwort jeweils `0815`): `j.hinterstein` (Verwaltung) · `a.berger` (Mieterin) · Demo-Registrierungscode: `MP-2026-0815`.
Alle Demo-Daten werden lokal im Browser (localStorage) gespeichert. Dark-Mode-Umschalter
in der Seitenleiste bzw. Mobilen Kopfzeile.
## Architektur (v1.3)
- **Frontend:** React-SPA (statisch, nginx-Container `mp-portal`)
- **API:** Node/Express (`server/`, Container `mp-api`) – Auth, Daten, Rollenrechte,
serverseitige E-Mail-Benachrichtigungen
- **Datenbank:** PostgreSQL 16 (Container `mp-db`, Volume `mp_pgdata`) – zentrale
Datenhaltung für alle Nutzer, kein localStorage mehr (außer Dark-Mode-Theme)
- Sitzung: HttpOnly-Cookie (8 h), Passwörter als SHA-256-Hash
## Entwicklung
```bash
npm install
npm run dev # http://localhost:3000
npm run dev # http://localhost:3000 (proxyt /api an localhost:3001)
npm run build # Produktionsbuild nach dist/
python beispieldaten.py # generiert src/data/generated.json (Seed wählbar)
python beispieldaten.py # generiert server/seed/generated.json (Seed wählbar)
```
Projekt-Kontext für Kimi Work: [kimi.md](kimi.md).
@@ -35,9 +42,13 @@ Projekt-Kontext für Kimi Work: [kimi.md](kimi.md).
./deploy.sh
```
baut das Frontend, lädt das `dist/`-Paket per `pscp` auf den Server (Port 38592,
Pageant-Key `Z:\Devel\ssh\priv_ionos_hocks_vps.ppk`) und startet den nginx-Container
`mp-portal` neu. TLS/Subdomain liefert der Nginx Proxy Manager (npm_default-Netz).
baut das Frontend, lädt Paket (dist + compose + nginx-Template + `server/`) per `pscp`
auf den Server (Port 38592, Pageant-Key `Z:\Devel\ssh\priv_ionos_hocks_vps.ppk`) und
startet den Stack neu inkl. API-Image-Build (`docker compose up -d --build`):
`mp-portal` (nginx), `mp-api` (Node-API), `mp-db` (PostgreSQL). TLS/Subdomain liefert
der Nginx Proxy Manager (npm_default-Netz). Voraussetzung auf dem Server:
`portal.env` mit `MAIL_API_TOKEN` + `POSTGRES_PASSWORD` und `.env`-Symlink darauf
(s. kimi.md Kap. 4).
Alternativ lokal ohne Server: `docker build -t mieterportal . && docker run -p 8080:80 mieterportal`.
@@ -50,7 +61,7 @@ Alternativ lokal ohne Server: `docker build -t mieterportal . && docker run -p 8
Auf dem Server läuft der Stack unter `/opt/mp-mail`. Das Portal ist verkabelt:
Der nginx des `mp-portal`-Containers proxiet ausschließlich `POST /api/mail/send`
an die Mail-API und authentifiziert sich dabei serverseitig mit dem Token aus
`portal.env` (nur auf dem Server, gitignored). Das Frontend benachrichtigt die
`portal.env` (nur auf dem Server, gitignored). Die **Node-API** benachrichtigt die
Verwaltung bei neuen Schadensmeldungen und die jeweilige Gegenstelle bei
Nachrichten – Versand fire-and-forget, ein Ausfall der Mail-API beeinträchtigt
das Portal nicht.