Schulportal-Konventionen übernommen: Dark Mode (ThemeToggle), beispieldaten.py + generated.json, kimi.md, mail-server (Postfix-Relay + API), Deploy-Workflow (pscp/plink, npm_default), Screenshots in preview/

This commit is contained in:
2026-10-02 10:46:10 +02:00
parent ca97ea028f
commit b3dfb8ab7c
27 changed files with 7284 additions and 163 deletions
+150
View File
@@ -0,0 +1,150 @@
# Kimi-Kontext: Hocks Mieterportal (mieterportal.hocks.eu)
> Projekt-Kontextdatei für Kimi Work. Stand: 02.10.2026, 11: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 Hocks Verwaltung 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. **Rollenmodus statt echter Anmeldung** (Demo): Umschalten Mieter ↔
Verwaltung über die Seitenleiste (Schaltfläche „Als Verwaltung anzeigen").
**Die 5 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.
**Login-Seite** (`/login`): Hero mit generiertem Foto, Feature-Liste, Demo-Einstiege
(„Als Mieterin anmelden" / „Als Verwaltung anmelden"). Kein echtes Auth – der
Rollenwechsel setzt nur den Store.
## 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 (`hocks-mieterportal-v1`) |
| Daten | `src/data/seed.ts` (handschriftlich) + `src/data/generated.json` (maschinell via `beispieldaten.py`) |
| Branding | KI-generiert: `src/assets/logo.png` (Haus-Schlüssel-Emblem, transparent), `hero.jpg`, `modules.jpg` |
| Webserver (Ziel) | Docker-Container `mp-portal` (nginx), statisches `dist/`, gemountet `/opt/mieterportal/dist` |
| Mail (optional) | `mail-server/`: Postfix-Relay (`mp-mail`) + Python-API (`mp-mail-api`), Muster aus Schulportal |
| 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` | Landing/Login mit Hero-Bild und Demo-Einstiegen |
| `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)
```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.
- **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`.
- Erst-Einrichtung auf dem Server (einmalig):
`mkdir -p /opt/mieterportal` + `docker-compose.yml` und `docker/nginx.conf` dorthin kopieren,
dann `docker compose up -d`. NPM-Proxy-Host `mieterportal.hocks.eu` → Container `mp-portal:80`.
- 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
- Keine echten Zugänge (Demo). Rollenwechsel im UI; Store-Reset über Browser-DevTools
(localStorage-Key `hocks-mieterportal-v1` löschen).
- Demo-Mieterin: **Anna Berger**, Hauptstraße 12, Whg. 7 (id `hs-7`).
- **Mail-API-Token:** bewusst nicht hier dokumentiert – liegt in `mail-server/mail.env`
(nicht im Repo; Vorlage `mail.env.example`).
## 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.
- 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).
**Offen:**
- Deployment auf hocks.eu ausstehend (SSH-Zugang per Pageant-ppk geklärt; Fail2Ban-Ban
nach früher Fehlversuchen abwarten/aufheben, dann `./deploy.sh`).
- Mail-Stack optional einrichten: `mail.env` aus Vorlage befüllen, Relay-Ziel in
`postfix/main.cf` setzen, npm_default-Netz prüfen.
- Mögliche nächste Schritte: echte Anmeldung + serverseitige Datenbank (PostgreSQL/Node-API),
E-Mail-Benachrichtigung bei neuen Schadensmeldungen, 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).