- nginx-Proxy POST /api/mail/send -> mp-mail-api:8080 (nur POST, 64k Limit) - Token serverseitig via envsubst-Template + portal.env (gitignored, nur Server) - src/lib/mail.ts: fire-and-forget Versand, Empfaenger-Aufloesung (Verwaltung/Mieter) - Benachrichtigung: neue Schadensmeldung -> Verwaltung, Nachrichten/Antworten -> Gegenstelle - E2E live verifiziert (versandt: true an axel@hocks.eu), GET 403 - Doku (kimi.md, README) nachgefuehrt
13 KiB
Kimi-Kontext: Hinterstein Immobilien · Mieterportal (mieterportal.hocks.eu)
Projekt-Kontextdatei für Kimi Work. Stand: 02.10.2026, 14:30 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.
Authentifizierung (echtes Login seit v1.1): Startseite /login mit
Login-Pflicht (Route-Guard RequireAuth in App.tsx leitet unangemeldete Besucher
auf /login um). Gruppen: verwaltung und mieter. Mieter können sich über
einen Registrierungscode selbst registrieren (/registrieren); Codes legt die
Verwaltung in der Benutzerverwaltung an (einmalig nutzbar, Wohnungsbezug).
Passwörter als SHA-256-Hash in localStorage, Session 8 h
(Key mp_benutzer_session). Demo-Zugänge (Passwort 0815):
j.hinterstein (Verwaltung, Joseph Hinterstein), a.berger (Mieterin,
Hauptstraße 12 Whg. 7), m.wolf (Mieter). Demo-Registrierungscode: MP-2026-0815.
Die 6 Module:
- 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). - Mietkonto & Zahlungen (
/mietkonto) – Buchungsverlauf 2026 mit Statusfilter, Nebenkostenguthaben, Zahlungsdaten. Verwaltung: Zahlungsstatus aller Wohnungen, Rückstandsliste, Haus-Filter. - Schadensmeldungen (
/schadensmeldungen) – Tickets mit Kategorie, Dringlichkeit, Status; Neuanlage per Dialog; Verwaltung pflegt Status per Select. - Dokumente (
/dokumente) – Verträge/Abrechnungen/Hausordnung/Protokolle, Suche + Kategorie-Chips. Mieter sieht eigene + Hausdokumente (unitId=null). - Nachrichten (
/nachrichten) – Chat Mieter ↔ Verwaltung, Ungelesen-Markierung, neue Unterhaltungen. - Benutzerverwaltung (
/benutzer, nur Gruppeverwaltung) – 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 | React Context + useReducer, Persistenz in localStorage (hinterstein-mieterportal-v2) |
| Daten | src/data/seed.ts (handschriftlich) + src/data/generated.json (maschinell via beispieldaten.py) |
| Auth | src/lib/auth.ts (SHA-256, Session 8 h, Keys mp_benutzer/mp_benutzer_session), Route-Guard in App.tsx |
| Branding | Kunde: src/assets/hinterstein/ (logo.png, joseph-hinterstein.jpg, kontakt.jpg); KI-generiert: src/assets/logo.png, hero.jpg, modules.jpg |
| Webserver (Ziel) | Docker-Container mp-portal (nginx), statisches dist/, gemountet /opt/mieterportal/dist |
mail-server/: Postfix-Relay (mp-mail) + Python-API (mp-mail-api) – live, /opt/mp-mail auf dem Server; verkabelt: Portal-nginx proxyt POST /api/mail/send → mp-mail-api:8080 und injiziert das Token aus portal.env (serverseitig, nie im Browser/Repo) |
|
| 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-Provider, Reducer, Actions (setRole/addTicket/setTicketStatus/addMessage/newThread/markThreadRead), fmtEUR |
src/data/seed.ts |
Tickets, Dokumente, Nachrichten-Threads, Ankündigungen + Re-Export units/transactions aus generated.json |
src/data/generated.json |
50 Wohnungen + 552 Buchungen, erzeugt von beispieldaten.py (Seed 20261002) |
beispieldaten.py |
Deterministischer Generator: python beispieldaten.py [seed] |
src/types/index.ts |
Alle Typen (Unit, Transaction, Ticket, DocumentItem, Thread, Announcement) |
src/components/AppLayout.tsx |
Sidebar (Desktop) + Mobile Top-Bar/Nav, Rollenwechsel, Ungelesen-Badge, ThemeToggle |
src/components/ThemeToggle.tsx |
Dark-Mode-Umschalter (Sonne/Mond) |
src/lib/theme.ts |
mp-theme in localStorage, Init vor erstem Render (main.tsx) |
src/pages/Login.tsx |
Login-Pflicht: Hero mit Joseph-Hinterstein-Portrait, Logo, Feature-Liste, Login-Formular + Registrierung-Link + Demo-Einstiege |
src/lib/mail.ts |
E-Mail-Benachrichtigungen: sendeBenachrichtigung (fire-and-forget) an /api/mail/send, Empfänger-Auflösung (Verwaltung / Mieter je Wohnung) |
docker/templates/default.conf.template |
nginx-Site als envsubst-Template; proxiet POST /api/mail/send → mp-mail-api:8080 mit ${MAIL_API_TOKEN} aus portal.env |
src/pages/Benutzer.tsx |
Benutzerverwaltung (nur Verwaltung): Nutzer, Gruppen, Registrierungscodes |
Dockerfile |
Optionaler All-in-One-Build (node build → nginx) für docker build-Workflow |
docker/nginx.conf |
nginx-Site: SPA-Fallback, Gzip, Cache-Header für /assets/, Security-Header |
docker-compose.yml |
mp-portal (nginx + gemountetes dist) im externen Netz npm_default; Mail-Stack separat |
deploy.sh |
Bewährter Deploy-Workflow (s. Kap. 4) |
mail-server/ |
Postfix-Relay + schlanke Mail-API (Muster Schulportal, angepasst) |
4. Deploy-Workflow (bewährt, aus Schulportal übernommen)
# 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.envauf dem Server wird vom compose alsenv_filegebraucht (liefertMAIL_API_TOKENfür den nginx-envsubst). Einmalig angelegt:grep '^MAIL_API_TOKEN=' /opt/mp-mail/mail.env > /opt/mieterportal/portal.envLiegt nur auf dem Server (gitignored), wird von deploy.sh nicht hochgeladen.- 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-portalläuft auf hocks.eu, statischesdist/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-cachegeliefert (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). Demo-Registrierungscode:MP-2026-0815. Passwörter werden als SHA-256-Hash gespeichert; Store-Reset über Browser-DevTools (localStorage-Keysmp_benutzer,mp_benutzer_session,hinterstein-mieterportal-v2löschen). - Mail-API-Token: bewusst nicht hier dokumentiert – liegt auf dem Server in
/opt/mp-mail/mail.env(Vorlagemail.env.exampleim Repo). - Mail-Stack live (seit 02.10.2026): Container
mp-mail+mp-mail-apilaufen auf hocks.eu unter/opt/mp-mail(Relay überhocks-eu.mail.protection.outlook.com). Testmail und API-/send(mitX-Api-Token) verifiziert (status=sent); ohne Token 401. - Mail-Benachrichtigungen im Portal (seit 02.10., v1.2): Der Portal-nginx
(
docker/templates/default.conf.template, envsubst) proxiet ausschließlichPOST /api/mail/sendanhttp://mp-mail-api:8080/sendund setzt das Token aus/opt/mieterportal/portal.env(chmod 600, nicht im Repo, gitignored). Das Frontend (src/lib/mail.ts) sendet fire-and-forget: neue Schadensmeldung → alle aktiven Verwaltungsbenutzer, neue Nachricht/Antwort → Gegenstelle (Mieter ↔ Verwaltung, Empfänger über Wohnungsbezug). E2E verifiziert: POST überhttps://mieterportal.hocks.eu/api/mail/send→versandt: true(Test an axel@hocks.eu); GET wird mit 403 blockiert. Demo-Empfängeradressen (z. B. joseph@hinterstein-immo.de) sind fiktiv → dort kein Empfang möglich, echte Adressen in der Benutzerverwaltung pflegen.
6. Konventionen & Besonderheiten
- Dark Mode: class-Strategie, Präferenz
mp-theme, Init vor erstem Render. Feste Farbklassen werden inindex.cssfür.darkumrechnen (.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.pyanpassen 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 --noEmitprüft wegen Solution-tsconfig ggf. nichts.- Headless-Screenshots (Dark Mode = Systempräferenz):
"/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.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.
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 durch echte ersetzen, sobald bekannt.
- Mögliche nächste Schritte: serverseitige Datenbank (PostgreSQL/Node-API) statt localStorage, Mehrseitigkeit für 50 echte Mietverhältnisse.
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).