292 lines
19 KiB
Markdown
292 lines
19 KiB
Markdown
# Kimi-Kontext: Hinterstein Immobilien · Mieterportal (mieterportal.hocks.eu)
|
||
|
||
> Projekt-Kontextdatei für Kimi Work. Stand: 02.10.2026, 13:00 Uhr.
|
||
> Bitte bei größeren Änderungen am Projekt aktualisieren.
|
||
> Konventionen und Workflow sind am Projekt Schulportal (sfg.hocks.eu) orientiert.
|
||
|
||
## 1. Projektüberblick
|
||
|
||
Mieterportal der **Hinterstein Immobilien** (Demo, Inhaber Joseph Hinterstein) für
|
||
**50 Wohnungen in 3 Häusern** (Hauptstraße 12 · Ringweg 3 · Am Park 5). Analog zum
|
||
Schulportal: alle Mietangelegenheiten digital an einem Ort.
|
||
|
||
**Datenhaltung (seit v1.3):** zentral serverseitig in **PostgreSQL** über eine
|
||
**Node-API** (Express) – kein localStorage mehr für Mietdaten. Mehrere Nutzer
|
||
sehen denselben Datenstand in Echtzeit; Rechte werden serverseitig erzwungen
|
||
(Mieter nur eigene Wohnung, Verwaltung alles).
|
||
|
||
**Authentifizierung:** Login-Pflicht auf `/login` (Route-Guard in `App.tsx`).
|
||
Gruppen `verwaltung` und `mieter`; Mieter registrieren sich per einmaligem
|
||
**Registrierungscode** (`/registrieren`). Passwörter als SHA-256-Hash (im Browser
|
||
gerechnet, Vergleich serverseitig), Sitzung als HttpOnly-Cookie `mp_session`
|
||
(8 h, Tabelle `sessions`). Demo-Zugänge (Passwort `0815`): `j.hinterstein`
|
||
(Verwaltung), `a.berger` (Mieterin, Hauptstraße 12 Whg. 7), `m.wolf` (Mieter,
|
||
Ringweg 3 Whg. 4). Demo-Registrierungscode: `MP-2026-0815`.
|
||
|
||
**Die 6 Module:**
|
||
|
||
1. **Dashboard** (`/`) – Mieter: Begrüßung, nächste Zahlung, Mietdiagramm, Ankündigungen,
|
||
offene Meldungen. Verwaltung: Kennzahlen (Vermietungsquote, Miet-Soll, Rückstände),
|
||
Einnahmenverlauf + Belegung pro Haus (Recharts).
|
||
2. **Mietkonto & Zahlungen** (`/mietkonto`) – Buchungsverlauf 2026 mit Statusfilter,
|
||
Nebenkostenguthaben, Zahlungsdaten. Verwaltung: Zahlungsstatus aller Wohnungen,
|
||
Rückstandsliste, Haus-Filter.
|
||
3. **Schadensmeldungen** (`/schadensmeldungen`) – Tickets mit Kategorie, Dringlichkeit,
|
||
Status; Neuanlage per Dialog; Verwaltung pflegt Status per Select.
|
||
4. **Dokumente** (`/dokumente`) – Verträge/Abrechnungen/Hausordnung/Protokolle,
|
||
Suche + Kategorie-Chips. Mieter sieht eigene + Hausdokumente (unitId=null).
|
||
5. **Nachrichten** (`/nachrichten`) – Chat Mieter ↔ Verwaltung, Ungelesen-Markierung,
|
||
neue Unterhaltungen.
|
||
6. **Benutzerverwaltung** (`/benutzer`, nur Gruppe `verwaltung`) – Nutzerliste mit
|
||
Gruppen und Wohnungsbezug, Registrierungscodes erzeugen/deaktivieren,
|
||
Demo-Zugänge zurücksetzen.
|
||
|
||
## 2. Technischer Stack
|
||
|
||
| Teil | Technologie |
|
||
|---|---|
|
||
| Frontend | React 18 + TypeScript, Vite 7, Tailwind v3.4 + shadcn/ui (Radix), React Router 7 (BrowserRouter), Recharts |
|
||
| State | Store-Kontext im Browser, **alle Daten serverseitig** (kein localStorage mehr); Ladezustand `bereit`, Schreibzugriff async |
|
||
| API | `server/`: Node 20 + Express + pg, Session-Cookie, Rollenrechte, serverseitige Mail-Benachrichtigungen |
|
||
| Datenbank | PostgreSQL 16 (`mp-db`), Schema/Seed in `server/src/db.js` + `seed.js`, Volume `mp_pgdata` |
|
||
| Daten | `server/seed/generated.json` (50 Wohnungen + 552 Buchungen via `beispieldaten.py`) + `server/src/seed-data.js` (handschriftlich) |
|
||
| Auth | SHA-256-Hash (Browser) + HttpOnly-Cookie-Session (8 h), `src/lib/api.ts`, `src/lib/auth.ts` |
|
||
| Branding | Kunde: `src/assets/hinterstein/` (logo.png, joseph-hinterstein.jpg, kontakt.jpg); KI-generiert: `src/assets/logo.png`, `hero.jpg`, `modules.jpg` |
|
||
| Webserver | Docker-Container `mp-portal` (nginx), statisches `dist/`, proxiet `/api/` → `mp-api:3000` |
|
||
| Mail | `mail-server/`: Postfix-Relay (`mp-mail`) + Python-API (`mp-mail-api`) – **live**, `/opt/mp-mail`; Portal-nginx proxyt `POST /api/mail/send` mit Token aus `portal.env` |
|
||
| Server | Root-VPS hocks.eu (IONOS), Docker + Portainer, Subdomain via NPM (Nginx Proxy Manager, Let's Encrypt) |
|
||
|
||
## 3. Wichtige Dateien
|
||
|
||
Projektverzeichnis: `C:\Users\ah\Documents\Kimi\Workspaces\Mieterportal`
|
||
**Git:** `https://git.hocks.eu/ah-admin/Mieterportal` (Branch `main`). Secrets
|
||
ausgesperrt via `.gitignore` (`mail-server/mail.env` etc.).
|
||
|
||
| Datei | Inhalt |
|
||
|---|---|
|
||
| `src/store/store.tsx` | Store-Kontext: lädt `/api/bootstrap`, stellt Collections + `me`/`role`/`meineEinheit` bereit, async-Methoden für alle Schreibaktionen, `fmtEUR` |
|
||
| `src/lib/api.ts` | Fetch-Client (same-origin, JSON, `ApiFehler` mit deutscher Meldung) |
|
||
| `src/lib/auth.ts` | SHA-256 für Passwörter, `DEMO_PASSWORT` |
|
||
| `server/src/index.js` | Express-API: Auth (Login/Logout/me/Register), Bootstrap, Tickets, Threads/Messages, Benutzerverwaltung, Codes, `/api/healthz` |
|
||
| `server/src/db.js` | pg-Pool + idempotentes Schema (11 Tabellen, snake_case) |
|
||
| `server/src/seed.js` | Idempotenter Seed (läuft nur bei leerer users-Tabelle) |
|
||
| `server/src/seed-data.js` | Handschriftliche Demo-Daten (Tickets, Dokumente, Threads, Ankündigungen, Benutzer, Codes) |
|
||
| `server/src/mail.js` | Serverseitiger Versand über mp-mail-api (fire-and-forget) |
|
||
| `server/seed/generated.json` | 50 Wohnungen + 552 Buchungen, erzeugt von `beispieldaten.py` (Seed 20261002) |
|
||
| `beispieldaten.py` | Deterministischer Generator: `python beispieldaten.py [seed]` → `server/seed/generated.json` |
|
||
| `src/types/index.ts` | Alle Typen (Unit, Transaction, Ticket, DocumentItem, Thread, Announcement, Benutzer, RegistrierungsCode) |
|
||
| `src/components/AppLayout.tsx` | Sidebar (Desktop) + Mobile Top-Bar/Nav, Logout, Ungelesen-Badge, ThemeToggle |
|
||
| `src/components/ThemeToggle.tsx` | Dark-Mode-Umschalter (Sonne/Mond) |
|
||
| `src/lib/theme.ts` | `mp-theme` in localStorage (nur noch Theme!), Init vor erstem Render (main.tsx) |
|
||
| `src/pages/Login.tsx` | Login-Pflicht: Hero mit Joseph-Hinterstein-Portrait, Logo, Feature-Liste, Login + Registrierung + Demo-Einstiege |
|
||
| `src/pages/BenutzerVerwaltung.tsx` | Benutzerverwaltung (nur Verwaltung): Nutzer anlegen/pflegen, Registrierungscodes erzeugen |
|
||
| `docker/templates/default.conf.template` | nginx-Site als envsubst-Template: SPA, `/api/` → mp-api, `POST /api/mail/send` → mp-mail-api mit `${MAIL_API_TOKEN}` |
|
||
| `docker-compose.yml` | Stack: `mp-portal` (nginx), `mp-api` (Node, Build ./server), `mp-db` (PostgreSQL 16, Volume mp_pgdata), Netz npm_default |
|
||
| `deploy.sh` | Deploy-Workflow: Build, Paket (dist + compose + nginx + server), Upload, `docker compose up -d --build`, Health-Check |
|
||
| `mail-server/` | Postfix-Relay + schlanke Mail-API (Muster Schulportal, angepasst) – separater Stack unter /opt/mp-mail |
|
||
|
||
## 4. Deploy-Workflow (bewährt, aus Schulportal übernommen)
|
||
|
||
```bash
|
||
# 1. Bauen (im Projektverzeichnis)
|
||
npm run build
|
||
|
||
# 2. Paketieren + Hochladen (pscp braucht cwd = Projektverzeichnis)
|
||
tar -czf mp-dist.tar.gz -C dist .
|
||
"/c/Program Files/PuTTY/pscp.exe" -batch \
|
||
-hostkey "SHA256:4G3UxsugNkHH6BrPXScLXh+vX8P1sLgWKn8cZBKSRxw" \
|
||
-i "Z:\Devel\ssh\priv_ionos_hocks_vps.ppk" -P 38592 \
|
||
mp-dist.tar.gz root@hocks.eu:/tmp/
|
||
|
||
# 3. Entpacken + Container neu starten + Hash prüfen
|
||
"/c/Program Files/PuTTY/plink.exe" -batch -hostkey "SHA256:4G3UxsugNkHH6BrPXScLXh+vX8P1sLgWKn8cZBKSRxw" \
|
||
-i "Z:\Devel\ssh\priv_ionos_hocks_vps.ppk" -P 38592 root@hocks.eu \
|
||
"rm -rf /opt/mieterportal/dist && mkdir -p /opt/mieterportal/dist && \
|
||
tar -xzf /tmp/mp-dist.tar.gz -C /opt/mieterportal/dist && \
|
||
cd /opt/mieterportal && docker compose up -d && sleep 2 && \
|
||
curl -s https://mieterportal.hocks.eu/ | grep -o 'index-[^\"]*\.js'"
|
||
|
||
# Alternativ alles in einem Schritt:
|
||
./deploy.sh
|
||
```
|
||
|
||
- SSH: Port **38592**, Key `Z:\Devel\ssh\priv_ionos_hocks_vps.ppk` (Pageant), Hostkey-Flag zwingend.
|
||
- **`portal.env` auf dem Server** (gitignored, liegt nur dort): liefert
|
||
`MAIL_API_TOKEN` (für nginx-envsubst und mp-api) und `POSTGRES_PASSWORD`
|
||
(für mp-db und die DATABASE_URL des mp-api). Einmalig angelegt:
|
||
`grep '^MAIL_API_TOKEN=' /opt/mp-mail/mail.env > /opt/mieterportal/portal.env`
|
||
plus zufälliges `POSTGRES_PASSWORD=…`. Wichtig: compose interpoliert
|
||
`${VARIABLE}` nur aus einer `.env`-Datei im Projektverzeichnis (nicht aus
|
||
`env_file:`!) – daher auf dem Server `/opt/mieterportal/.env` als
|
||
**Symlink auf portal.env**:
|
||
`cd /opt/mieterportal && ln -sf portal.env .env`
|
||
- deploy.sh macht `docker compose up -d --build` (baut das mp-api-Image auf
|
||
dem Server, npm ci im Container) und prüft danach Container-Status,
|
||
Portal-Hash und `GET /api/healthz`.
|
||
- **Vorsicht Fail2Ban:** zu viele gescheiterte SSH-Versuche von einer IP führen zu einem
|
||
Ban (Timeout-Verbindungsbild). Ban aufheben auf dem Server: `fail2ban-client unban --all`.
|
||
- **Live (seit 02.10.2026):** Container `mp-portal` läuft auf hocks.eu, statisches `dist/`
|
||
unter `/opt/mieterportal/dist` (gemountet). NPM-Proxy-Host **id 7** (Datei
|
||
`/data/compose/1/data/nginx/proxy_host/7.conf`, DB-Tabelle proxy_host), Zertifikat
|
||
**npm-9** (Let's Encrypt, läuft bis 31.12.2026; via certbot/webroot erstellt, liegt im
|
||
npm-Container unter `/etc/letsencrypt/live/npm-9/`). HTTP→HTTPS-Redirect aktiv
|
||
(HSTS, Block-Exploits, HTTP/2). Änderungen am Proxy-Host im NPM-UI werden die
|
||
DB-Konfiguration konsistent halten; manuelle Conf-Edits werden beim nächsten
|
||
UI-Speichern überschrieben.
|
||
- HTML wird mit `no-cache` geliefert (nginx-Config), Assets hash-benannt → Reload genügt.
|
||
Der eingebettete Kimi-Browser cached hart → beim Testen Cache-Buster anhängen: `?v=X`.
|
||
|
||
## 5. Zugänge & Konfiguration
|
||
|
||
- **Demo-Zugänge (Passwort `0815`):** `j.hinterstein` (Verwaltung), `a.berger`
|
||
(Mieterin, Hauptstraße 12 Whg. 7), `m.wolf` (Mieter, Ringweg 3 Whg. 4).
|
||
Demo-Registrierungscode: `MP-2026-0815`. Passwörter liegen als SHA-256-Hash
|
||
in der users-Tabelle; Sitzung als HttpOnly-Cookie (Tabelle sessions).
|
||
Abmelden reicht zum „Reset" – nichts liegt mehr im Browser-localStorage
|
||
(außer dem Dark-Mode-Theme).
|
||
- **Verwaltungs-E-Mail:** `axel@hocks.eu` (echtes, zustellbares Postfach, damit
|
||
Benachrichtigungen ankommen) – im Portal änderbar.
|
||
- **Mail-API-Token:** bewusst nicht hier dokumentiert – liegt auf dem Server in
|
||
`/opt/mp-mail/mail.env` (Vorlage `mail.env.example` im Repo).
|
||
- **Mail-Stack live (seit 02.10.2026):** Container `mp-mail` + `mp-mail-api` laufen
|
||
auf hocks.eu unter `/opt/mp-mail` (Relay über `hocks-eu.mail.protection.outlook.com`).
|
||
Testmail und API-`/send` (mit `X-Api-Token`) verifiziert (status=sent); ohne Token 401.
|
||
- **Mail-Benachrichtigungen (seit v1.2 nginx-Proxy, seit v1.3 serverseitig,
|
||
seit v1.4 im HTML-Format wie im Schulportal):** Der Portal-nginx proxiet
|
||
`POST /api/mail/send` an `http://mp-mail-api:8080/send` mit Token aus
|
||
`portal.env` (403 für alles außer POST). **Versand aus der Node-API**
|
||
(`server/src/mail.js`, fire-and-forget): neue Schadensmeldung → alle aktiven
|
||
Verwaltungsbenutzer, neue Nachricht/Antwort → Gegenstelle. HTML im
|
||
Schulportal-Stil (`baueHtmlMail`: 600-px-Karte, Kopfzeile in Hinterstein-
|
||
Farben #22333b/Amber, Zeilen-Tabelle, Status-Box, Zitat-Box, Button „Zum
|
||
Mieterportal“, Footer) immer mit Plain-Text-Fallback (multipart/alternative).
|
||
E2E verifiziert: Zustellung an axel@hocks.eu, Postfix status=sent.
|
||
|
||
## 6. Konventionen & Besonderheiten
|
||
|
||
- **Dark Mode:** class-Strategie, Präferenz `mp-theme`, Init vor erstem Render.
|
||
Feste Farbklassen werden in `index.css` für `.dark` umrechnen
|
||
(`.dark .bg-white`/`.bg-slate-50`/`.bg-teal-50`); Sidebar ist eigenes Dunkel-Teal.
|
||
- **Barrierefreiheit:** aria-pressed/labels am ThemeToggle und Rollenwechsel, Fokus-Ringe.
|
||
- **Formatierung:** Beträge via `fmtEUR` (Intl de-DE), Datumsformate TT.MM.JJJJ.
|
||
- **Datenpflege:** Bestandsdaten ändern → `beispieldaten.py` anpassen und neu ausführen,
|
||
nicht generated.json von Hand editieren.
|
||
- **Sicherheit:** kein offenes Relay (Postfix mynetworks loopback + Docker-Netz,
|
||
sender_canonical zentral). Upload/Download-Funktionen sind Demo-Darstellungen.
|
||
- **Keine destruktiven Aktionen auf dem Server ohne ausdrückliche Bestätigung.**
|
||
|
||
## 7. Testing
|
||
|
||
- `npm run build` (`tsc -b`) ist die echte Typprüfung; `npx tsc --noEmit` prüft wegen
|
||
Solution-tsconfig ggf. nichts. Server-Syntax: `node --check server/src/*.js`.
|
||
- API-Livetests mit curl (Cookie-Jar): Login → `/api/auth/me` → `/api/bootstrap`
|
||
(Mieter-Sicht zählt kleiner!) → Ticket/Thread schreiben → Postfix-Log auf
|
||
Zustellung prüfen (`docker logs mp-mail | grep to=<empfaenger>`).
|
||
- Headless-Screenshots (Dark Mode = Systempräferenz, `--virtual-time-budget=10000`
|
||
wartet auf den Session-Check):
|
||
`"/c/Program Files/Google/Chrome/Application/chrome.exe" --headless --disable-gpu --screenshot=... --window-size=WxH "URL"`
|
||
- Screenshots ausgeliefert nach `preview/`.
|
||
|
||
## 8. Verlauf / offene Punkte
|
||
|
||
**Erledigt 02.10. (v1.8):** Schadensmeldungen starten jetzt automatisch eine
|
||
Unterhaltung (Thread „Schadensmeldung: …" mit erster Nachricht inkl. Kategorie/
|
||
Priorität, ungelesen für die Gegenseite) – Antworten darauf lösen über
|
||
`/api/threads/:id/messages` wie gehabt Mails an Verwaltung + Mieter aus.
|
||
Zusätzlich Eingangsbestätigungs-Mail an den Mieter bei jeder Meldung.
|
||
Verwaltungs-Mails gehen jetzt an zwei echte Postfächer: joseph@hinterstein-immo.com
|
||
(Benutzer j.hinterstein, Seed + Live-DB geändert) und axel@hocks.eu (neuer
|
||
Verwaltungsbenutzer a.hocks, Passwort 0815, Seed + Live-DB). E2E verifiziert:
|
||
Meldung + Antwort → je Mail an beide Postfächer zugestellt (Postfix status=sent);
|
||
Mieter-Adressen der Demoseeds sind example.de und bouncen bewusst.
|
||
|
||
**Erledigt 02.10. (v1.7):** Responsive Layout repariert. Sidebar skaliert jetzt in zwei
|
||
Stufen (`w-64` ab `lg`, `xl:w-72`) statt fixer 288 px. Mobile Ansicht (Top-Bar +
|
||
horizontal scrollende Nav) gilt jetzt bis 1024 px (`md:hidden` → `lg:hidden`) – vorher
|
||
stand zwischen 768–1024 px die volle Sidebar und quetschte Inhalt + Fußzeile.
|
||
Sidebar-Fußzeile bricht um (`flex-wrap`, `truncate`-sichere Buttons), `main`-Padding
|
||
folgt dem `lg`-Breakpoint. Tailwind war bereits das CSS-Framework (kein Wechsel nötig).
|
||
Screenshots: `preview/09-mobile-900px.png`, `preview/10-desktop-1280px.png`.
|
||
|
||
**Erledigt 02.10. (v1.6):** Login-Race behoben: `setMe` läuft jetzt erst nach
|
||
`ladeAlles()` (Start/Login/Registrierung) – vorher rendereten die Seiten gegen
|
||
noch leere Daten → Absturz → schwarzer Bildschirm, erst Reload half. Zusätzlich
|
||
`FehlerGrenze` (ErrorBoundary) in `App.tsx`: Render-Fehler zeigen Hinweis +
|
||
Reload-Button statt schwarzem Bildschirm.
|
||
|
||
**Erledigt 02.10. (v1.5):** Lokales Datenbank-Backup: `backup/vps-db-backup.cmd`
|
||
holt nächtlich (Aufgabenplanung „Mieterportal DB-Backup", täglich 03:17 Uhr,
|
||
Benutzer ah, interaktiv) per plink ein `pg_dump | gzip` vom Container mp-db und
|
||
legt es nach `D:\VPS_Backup\mieterportal\mieterportal-db-YYYY-MM-DD.sql.gz`
|
||
(14-tägige Aufbewahrung via forfiles, Log: `backup.log`). Probelauf OK
|
||
(11 KB, Dump-Format geprüft). Einschränkung: läuft nur, wenn der Rechner an
|
||
und Benutzer ah angemeldet ist (Z:-Laufwerk mit dem SSH-Key, Pageant).
|
||
|
||
**Erledigt 02.10. (v1.0):** Portal komplett neu aufgesetzt (5 Module, Mieter-/Verwaltungsansicht,
|
||
KI-Branding: Logo/Hero/Illustration), Docker-Setup (Dockerfile, nginx, compose),
|
||
Repo in git.hocks.eu angelegt, Deploy-Workflow + Dark Mode + beispieldaten.py aus dem
|
||
Schulportal übernommen, mail-server-Struktur angelegt (noch nicht live verkabelt).
|
||
|
||
**Erledigt 02.10. (v1.0 live):** Deployment auf hocks.eu durchgeführt: Container `mp-portal`
|
||
läuft (`/opt/mieterportal`, compose + gemountetes dist), NPM-Proxy-Host id 7 + LE-Zertifikat
|
||
npm-9 eingerichtet (per certbot/webroot, DB-Insert, 7.conf aus 5.conf abgeleitet, nginx reload).
|
||
Live geprüft: `https://mieterportal.hocks.eu/` → HTTP 200, Titel korrekt, SPA-Routing
|
||
(`/mietkonto`) 200, HTTP→HTTPS-Redirect 301, Zertifikat CN=mieterportal.hocks.eu gültig
|
||
bis 31.12.2026. Zertifikatsdateien liegen im npm-Container unter `/etc/letsencrypt/live/npm-9/`
|
||
(Backup der Zertifikate auf dem Host: `/root/le-mp/`). Fail2Ban-Ban nach frühen
|
||
Fehlversuchen ist nach ~40 min automatisch ausgelaufen.
|
||
|
||
**Erledigt 02.10. (v1.1 live):** Rebrand auf „Hinterstein Immobilien" (Kunden-Logo,
|
||
Joseph-Hinterstein-Portrait auf der Login-Seite, Kontakt-Banner), echtes
|
||
Authentifizierungssystem (Login-Pflicht, Gruppen Verwaltung/Mieter, SHA-256,
|
||
Session 8 h), Mieter-Registrierung per einmaligem Code, Benutzerverwaltung als
|
||
6. Modul (`/benutzer`), Demo-Zugänge mit Passwort `0815`. Mail-Stack auf dem Server
|
||
aktiviert (`/opt/mp-mail`, Testmail + API-/send verifiziert). Store-Key auf
|
||
`hinterstein-mieterportal-v2` gehoben. Live deployed und geprüft (HTTP 200, Titel
|
||
„Hinterstein Immobilien · Mieterportal").
|
||
|
||
**Erledigt 02.10. (v1.2 live):** E-Mail-Benachrichtigungen an das Portal
|
||
angeschlossen: nginx-Proxy `/api/mail/send` mit serverseitig injiziertem Token
|
||
(envsubst-Template + `portal.env` auf dem Server), `src/lib/mail.ts` sendet bei
|
||
neuen Schadensmeldungen (→ Verwaltung) und Nachrichten/Antworten (→ Gegenstelle).
|
||
E2E-Versand live verifiziert (versandt: true), GET auf den Endpunkt 403.
|
||
|
||
**Erledigt 02.10. (v1.3 live):** Serverseitige Datenbank: PostgreSQL 16 (`mp-db`,
|
||
Volume `mp_pgdata`) + Node-API (`mp-api`, Express + pg, eigenes Image via
|
||
deploy.sh `--build`). Schema 11 Tabellen (idempotent), Seed einmalig aus
|
||
`server/seed/generated.json` + `seed-data.js` (Verwaltungs-E-Mail auf echtes
|
||
Postfach axel@hocks.eu gesetzt). Frontend komplett auf API umgestellt:
|
||
`src/lib/api.ts`, Store lädt `/api/bootstrap`, kein localStorage mehr (außer
|
||
Theme), Ladebildschirm während Session-Check. Rollenrechte serverseitig
|
||
durchgesetzt und getestet (Mieterin sieht nur hs-7: 12 Buchungen/2 Tickets,
|
||
403 auf fremde Unterhaltung; Verwaltung sieht alles: 552 Buchungen/8 Tickets).
|
||
Registrierung, Code-Erzeugung, Ticket inkl. Mail-Benachrichtigung (status=sent
|
||
an axel@hocks.eu) E2E verifiziert; Testdaten danach bereinigt. deploy.sh baut
|
||
das API-Image auf dem Server; `.env`-Symlink auf portal.env für
|
||
Compose-Interpolation beachten (POSTGRES_PASSWORD!).
|
||
|
||
**Erledigt 02.10. (v1.4 live):** HTML-E-Mail-Benachrichtigungen im Schulportal-
|
||
Stil: `baueHtmlMail`/`buttonHtml` in `server/src/mail.js` (600-px-Karte,
|
||
Kopfzeile Hinterstein-Farben, Zeilen, Status-Box, Zitat, Aktions-Button, Footer),
|
||
immer mit Plain-Text-Fallback (multipart/alternative). Umgesetzt für
|
||
Schadensmeldung, neue Unterhaltung und Antwort. Vorschauen lokal renderbar
|
||
(`mail-vorschau*.html`, Screenshots in `preview/08-*.png`). Live getestet:
|
||
Zustellung an axel@hocks.eu status=sent, Test-Ticket bereinigt.
|
||
|
||
**Offen:**
|
||
- Zertifikatserneuerung prüfen (per 01.12.2026): NPM-Renewer sollte cert 9 über HTTP-Challenge
|
||
erneuern; sonst certbot/webroot + Kopie nach npm-9 wiederholen.
|
||
- Demo-Empfängeradressen der Mieter (example.de) durch echte ersetzen, sobald bekannt.
|
||
- Backup ggf. serverseitig ergänzen (zweite Sicherungslinie, falls lokaler Rechner
|
||
nachts aus ist), Backup-Wiederherstellung einmal testen.
|
||
- Sicherheit für Produktion: Passwort-Hash serverseitig salten (bcrypt/argon2), CSRF-Token,
|
||
Rate-Limiting auf /api/auth/login.
|
||
- Mögliche nächste Schritte: E-Mail-Verifizierung bei Registrierung, Dokumenten-Download
|
||
mit echten Dateien.
|
||
|
||
## 9. Sonstiges
|
||
|
||
- User kommuniziert auf Deutsch; alle UI-Texte und Antworten auf Deutsch.
|
||
- Dateien außerhalb des Workspaces immer erst in den Workspace kopieren.
|
||
- Vorsicht mit destruktiven Aktionen (Explizite Bestätigung einholen).
|