From 49b5b7a523e22bf3e98562820bb6b8497a73a07b Mon Sep 17 00:00:00 2001 From: nexxo Date: Sat, 25 Jul 2026 09:16:17 +0200 Subject: [PATCH] docs: state/continuation handoff (2026-07-25) Full project state for a fresh session: env facts, stack, docker workflow, what's built (landing + customer portal + admin console), verification workflow (pest / R12 puppeteer / R15 codex), hard-won gotchas, open items, and the recommended next block (provisioning engine v1.0). Co-Authored-By: Claude Opus 4.8 --- .../2026-07-25-clupilot-state-handoff.md | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 docs/handoffs/2026-07-25-clupilot-state-handoff.md diff --git a/docs/handoffs/2026-07-25-clupilot-state-handoff.md b/docs/handoffs/2026-07-25-clupilot-state-handoff.md new file mode 100644 index 0000000..5c72ad7 --- /dev/null +++ b/docs/handoffs/2026-07-25-clupilot-state-handoff.md @@ -0,0 +1,117 @@ +# Handoff — CluPilot (Stand 2026-07-25) + +**Für:** frische Claude-Code-Session +**Art:** Zustands-/Fortsetzungs-Handoff +**Zuerst lesen:** dieses Dokument komplett, dann `git log --oneline -15`. + +--- + +## 0. TL;DR + +CluPilot = **Managed-Nextcloud-Cloud-Business** (fertige, betreute Firmen-Cloud). Laravel-App auf einer lokalen Dev-VM. Gebaut & gepusht sind bereits: **öffentliche Landingpage**, **helles Kundenportal** (Login/2FA + Dashboard + 6 Reiter) und eine **dunkle Admin-/Operator-Konsole** (`/admin`, 6 Sektionen) — alles mit Chart.js, 48 Pest-Tests grün, jeder Commit Codex-(R15)-clean, überall 0 Konsolenfehler. + +**Nächster großer Schritt:** die **Provisionierungs-Engine v1.0** (aus Bestellung → laufende Nextcloud-Instanz). Design-Spec liegt beim Nutzer (nicht im Repo). Superpowers-Plugin (TDD) ist installiert. + +--- + +## 1. Umgebung / Fakten + +- **VM:** Debian, User **`nexxo`** (uid/gid **1000**), IP **`10.10.90.185`**, nur Docker (kein PHP/Composer/Node auf dem Host → alles im Container, **R8**). +- **Projekt:** `/home/nexxo/clupilot` (eigenes Git-Repo). +- **Remote:** `https://git.bave.dev/boban/CluPilotCloud.git`. **Token liegt in `.env`** (`GIT_ACCESS_TOKEN`, gitignored). Push: Token nur zur Push-Zeit inline injizieren, danach `git config branch..remote origin` und `.git/config` auf Token prüfen. **Nie** `.env`/Token committen. +- **Aktueller Branch:** `feat/portal-design` (alles hier, gepusht). `main` existiert lokal ohne Commits — Merge/PR steht aus. +- **Docker sudo-frei** (nexxo in docker-Gruppe). `sudo` bräuchte Passwort → vermeiden. + +## 2. Stack + +Laravel **13.8**, Livewire **3** (klassenbasiert, kein Volt — **R2**), **Tailwind v3** (bewusst von v4 zurückgebaut, Nutzer-Entscheid), Vite, **Laravel Fortify** (Login + TOTP-2FA), **Laravel Reverb**, **MariaDB 11.4**, **Redis**, **Chart.js 4**, **phpseclib**, wire-elements/modal, **Pest 4** (Tests). Fonts: **IBM Plex** self-hosted via @fontsource (**R14**, kein CDN). + +## 3. Docker / Befehle (alles im Container, R8) + +Helper `clupilot` (global via `~/.local/bin`, + `cp-*` Aliases): +```bash +clupilot up | down | restart [svc] | rebuild | ps | logs [svc] | health +clupilot artisan … | composer … | npm … | tinker | migrate | shell +``` +Roh, falls nötig (User 1000, HOME für Composer-/npm-Cache): +```bash +docker compose run --rm --no-deps -u 1000:1000 -e HOME=/tmp app +docker compose exec -T -u 1000:1000 -e HOME=/tmp app php artisan … +``` +Services: `app` (php-fpm+nginx+**vite** via supervisor — EIN Container), `reverb`, `queue`, `scheduler`, `mariadb`, `redis`. App auf **:80**, Vite HMR **:5173** (`VITE_HMR_HOST=10.10.90.185`). + +## 4. Was gebaut ist + +**Öffentlich** +- `/` → **Landingpage** (`resources/views/landing.blade.php`) — Marketing, self-contained CSS/JS in `@verbatim`, System-Fonts, **absichtlich außerhalb** des App-Token-Systems. Login-Link → `route('login')`. +- `/legal/{impressum,datenschutz,agb,status}` → **Platzhalter** (`legal.blade.php`). ⚠️ **Echter Rechtstext fehlt** (Nutzer muss liefern — gesetzl. Pflicht vor Launch). + +**Kundenportal (hell)** — `layouts/portal.blade.php` (Auth) + `layouts/portal-app.blade.php` (App-Shell) +- Auth: `/login`, `/two-factor-challenge` (Fortify, `views=false`, Seiten als full-page Livewire — **R1/R2**). +- `/dashboard` + Reiter `/cloud /users /backups /invoices /support` — je full-page Livewire (`app/Livewire/*`), Chart.js, Tabellen, lokalisiert DE/EN. + +**Admin-Konsole (dunkel)** — `layouts/admin.blade.php` (`class="theme-admin"`), gate `is_admin` +- `/admin` + `/admin/{customers,instances,hosts,provisioning,revenue}` (`app/Livewire/Admin/*`). Middleware `['auth','admin']` (EnsureAdmin). + +**Design-System** (Kern!) +- Tokens als CSS-Variablen: `resources/css/portal-tokens.css` (hell) + `resources/css/admin-tokens.css` (`.theme-admin` überschreibt alle Tokens dunkel). Tailwind mappt Tokens → Utilities (`tailwind.config.js`). **Nur Token-Utilities in Markup (R3), keine Hex.** +- Komponenten: `resources/views/components/ui/` — button, input, checkbox, alert, card, badge, stat-tile, otp-input, progress-stepper, nav-item, icon (Lucide, **keine Emoji im App-UI, R9**), **chart** (Alpine-Island). +- Chart-Island: PHP-Config-Array, Farben als `"token:accent"`/`"token:accent/0.12"` (in `resources/js/app.js` zur Laufzeit aus CSS-Vars aufgelöst, liest vom Element → theme-aware). + +## 5. Verifikations-Workflow (jede Änderung) + +1. **Tests:** `docker compose run --rm --no-deps -u 1000:1000 -e HOME=/tmp app ./vendor/bin/pest` (aktuell **48 grün**). +2. **R12 Browser (0 Konsolenfehler):** Prod-Assets bauen → `npm run build`, `supervisorctl stop vite` + `rm -f public/hot`, dann Puppeteer: + ```bash + docker run --rm --network host -v /pfad/probe.js:/home/pptruser/probe.js \ + -w /home/pptruser ghcr.io/puppeteer/puppeteer:latest node probe.js + ``` + Probe: `page.on('console'/'pageerror'/'requestfailed')`, HTTP 200 + 0 Fehler pro Seite; Login-Flow via `#email`/`#password` + submit. **Danach `docker compose restart app`** (Vite/`public/hot` zurück). (Probe-Skripte liegen NICHT im Repo — bei Bedarf neu schreiben.) +3. **R15 Codex-Review (Pflicht vor „fertig"):** + ```bash + export CLAUDE_PLUGIN_ROOT=/home/nexxo/.claude/remote/plugins/e3a3a3c04ad124ae + node "$CLAUDE_PLUGIN_ROOT/scripts/codex-companion.mjs" review "--scope working-tree --background" + ``` + Ergebnis pollen: neuestes `/tmp/codex-companion/*/jobs/review-*.log` (`awk '/Final output/{f=1}f'`). `/codex:review` ist `disable-model-invocation` → Skript direkt aufrufen. **Working-tree-Scope** (nicht branch/base). Loop bis „no actionable regressions". Findings waren durchweg echt (a11y, i18n, Portabilität, Security) — ernst nehmen. + +**Dev-Logins** (beide PW `password`): `admin@clupilot.local` (Admin, sieht `/admin`+`/dashboard`), `kunde@clupilot.local` (Kunde, `/admin`=403). Nach DB-Reset: `clupilot artisan db:seed`. + +## 6. Gotchas (teuer gelernt — beachten!) + +- **`@js()` wird NICHT kompiliert in `@click`/Attributen von Blade-Komponenten** (``) → landet literal, bricht Alpine. Lösung: `@js()` in `x-data` eines *plain* Elements, Buttons referenzieren die Variable. +- **Test-Isolation:** `env_file: .env` in docker-compose wurde **entfernt** — es injizierte Dev-DB-Config als echte Env-Vars und überschrieb phpunit-`force` → Tests liefen gegen die **Dev-MariaDB** und wischten sie. Laravel liest `.env` von der Platte; nur Vite-Vars sind explizit gesetzt. Tests nutzen jetzt sqlite `:memory:` (`phpunit.xml` mit `force="true"`). +- **CSRF in Tests:** `$this->post()` sendet kein Token → 419. In Auth-Tests Session-Token setzen: `withSession(['_token'=>'t'])->post(..., ['_token'=>'t', ...])`. +- **Großes rohes HTML/CSS/JS** in Blade → `@verbatim … @endverbatim` (sonst zerlegt Blade `@keyframes`/`${}`/`{{ }}`). +- **AA-Kontrast:** `#f97316` (accent) fällt für weißen/kleinen Text durch AA → Buttons/Links nutzen `accent-active`/`accent-text` (dunkleres Orange hell / helleres Orange dunkel). `--accent` nur Deko/Rahmen/Tints. +- **Locale:** Fixture-Daten immer locale-aware (`Carbon::isoFormat`, `Number::format/currency`), sonst mischt EN deutsche Formate — Codex flaggt das zuverlässig. +- **Vite reload:** `docker compose restart` liest `env_file`/Config **nicht** neu → `docker compose up -d app` (recreate) wenn Env/Compose geändert. + +## 7. Offene Punkte + +| Prio | Punkt | +|---|---| +| Hoch | **Echter Rechtstext** (Impressum/Datenschutz/AGB) — Nutzer liefert; ich erfinde keine Rechtsangaben | +| Mittel | Merge `feat/portal-design` → `main` (Gitea-PR) | +| Mittel | **Provisionierungs-Engine v1.0** (s. u.) | +| Niedrig | Multi-Domain-Split `www.` / `app.` / `admin.clupilot.com` (Nutzer legt Domains an) — aktuell pfad-basiert | +| Niedrig | v1.1-Auth: Passwort-Reset / „Passwort vergessen" (in Fortify bewusst deaktiviert) | +| Niedrig | Breiteres Komponenten-Kit (Modal-Nutzung, Tabs, Toast-Komponente, Skeleton, Tooltip …) falls gebraucht | + +## 8. Nächster großer Block: Provisionierungs-Engine v1.0 + +**Ziel:** aus bezahlter Bestellung vollautomatisch eine laufende, gesicherte, überwachte Nextcloud-Instanz. Modell = **DB-State-Machine + Tick-Orchestrator** (kein Monolith-Job). + +- **Design-Spec liegt beim Nutzer** (war als „Engine-v1.0-Handoff" vorhanden, ist NICHT im Repo). **Vor Baubeginn anfordern.** +- **TDD** (Superpowers `test-driven-development` ist ab dieser Session verfügbar). ProxmoxClient in Step-Tests mocken. +- Grob: Migrations/Models (`customers, orders, hosts, instances, provisioning_runs, provisioning_step_events, run_resources, …`) → Orchestrator-Kern (Step-Interface, StepResult advance/retry/fail, AdvanceRunJob, Per-Run-Lock, Timeout, Tick im `scheduler`) → **ProxmoxClient** (NEU, REST/UPID-Polling) → 15 idempotente Kunden-Pipeline-Steps → Stripe-Webhook (Idempotency-Key) → Livewire-Live-Fortschritt via Reverb. +- **Nicht anfassen/vermischen:** Alt-Domäne existiert hier nicht (frischer Build) — Engine ist additiv. Panel-Reverb/Queue/Scheduler sind da und wiederverwendbar. +- Die Admin-`/admin/provisioning`-Seite ist aktuell **Fixture-View** → später an echte `provisioning_runs`/`provisioning_step_events` binden (live via Reverb). + +## 9. Regeln (Kurzfassung — verbindlich) + +R1/R2 full-page **klassenbasierte Livewire** als Routen (kein Volt, kein Page-Controller) · R3 nur `@theme`/Token-Utilities, kein Hex · R4 keine Inline-Styles außer Progress-`width` · R5 destruktiv → wire-elements/modal · R6 Ordner-Map · R7 responsive 375/768/1280, Touch ≥44px · R8 alles im Container · R9 UI-Copy DE, **keine Emoji** (Status via Farbe/Dots/Pills) · R10 Design-System wiederverwenden · R11 URLs per **UUID** (nicht Integer-PK) · R12 **Browser-verifiziert HTTP 200 + 0 Konsolenfehler** · R13 Routen-Pfade/Namen **englisch** · R14 Fonts **self-hosted** · R15 **Codex-Review clean** vor „fertig" · R16 alles lokalisiert **DE+EN** (identische Keys) · R17 Blade-`@php`-Block-Regeln. +> Volltext `rules.md`/`CLAUDE.md` hat der Nutzer (nicht im Repo). Bei Konflikt: STOP & fragen. + +## 10. Session-Memory + +Persistente Notizen unter `~/.claude/projects/-home-nexxo/memory/` (MEMORY.md + `clupilot-project-state`, `clupilot-portal-progress`, `clupilot-r15-codex-review`) — beim Start werden die relevanten automatisch eingespielt.