Vier Befunde aus dem Abschluss-Review ueber d62a2c8/c815aee/11ba7ee:
- Die Migration renamt nur Hosts mit dns_name; pve-fsn-1/pve-hel-1 blieben
unrepariert und stumm. Sie werden jetzt gesammelt und gemeldet (Log +
Konsole), ohne die Migration abzubrechen - diese Hosts laufen weiter.
- Die Vorabpruefung verglich in PHP byteweise, die Spalte liegt auf
utf8mb4_unicode_ci. Umgestellt auf GROUP BY/HAVING in SQL, damit dieselbe
Kollation entscheidet, die spaeter den Unique-Index baut.
- Ein Fehlschlag nach der Vorabpruefung liess einen zweiten Anlauf sofort an
"Duplicate column name" sterben. Die beiden betroffenen Schema-Schritte
stehen jetzt hinter Schema::hasColumn(), macht den Kommentar darueber wahr.
- Seeder (DatabaseSeeder, DemoCustomerSeeder) sind auf pve-*-Namen sitzen
geblieben, weil sie dns_name nie benutzt hatten. Auf fsn-01/hel-01
umgestellt, next_host_number entsprechend vorbelegt.
Dazu vier Kleinigkeiten: ein Test nagelte den falschen Config-Schluessel fest
(dns.zone statt platform_zone), HostName::claim() erzwingt jetzt wirklich
eine Transaktion statt es nur zu verlangen, down() vergisst nicht mehr den
Settings-Cache, und der Kommentar ueber HostName::free() nennt jetzt ehrlich
die Einschraenkung auf einen einzelnen Thread.
Alle vier Migrationslaeufe (Vorabpruefung-Kollision, Meldung fuer
unreparierte Hosts, Fehlschlag-und-erneuter-Anlauf, Rueckbau mit
Cache-Invalidierung) gegen echtes MariaDB auf einer Scratch-Datenbank
geprueft, um die parallele Billing-Session nicht zu beruehren. Voller
Testlauf: 2395 bestanden. Bericht mit allen Befehlen und Ausgaben unter
.superpowers/sdd/2026-08-01-hostname-vergabe/final-fix-report.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 5 operator roles (Owner/Admin/Support/Billing/Read-only) seeded via migration
with a capability catalogue; app checks capabilities via Gate, never role names
- every mutating admin action authorizes server-side (hosts/datacenters/customers/
impersonate/provisioning); is_admin reads migrated to console.view / isOperator()
- admin /settings: own account + Owner-only staff invite/role/revoke with
last-owner, self-role and customer-collision guards (transactional)
- sidebar 'zum Kundenportal' link replaced with Settings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
datacenters table/model + admin CRUD (/admin/datacenters, nav). HostCreate
picks from active datacenters (validated); hosts show the datacenter code.
Seeded fsn/hel. 5 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Separate admin console at /admin, gated to is_admin users (EnsureAdmin middleware
+ migration/seed; a plain customer user is seeded to prove the gate). Distinct dark
aesthetic achieved purely by token scoping: .theme-admin overrides every CSS design
token to a dark graphite / signal-orange palette, so ALL shared components (button,
card, badge, table, stat, chart) render dark with zero new markup (R3). Chart island
now reads tokens from its own element, so charts are theme-aware.
Sections (each full-page class-based Livewire, English routes R13, localized DE/EN):
- Overview: fleet KPIs, fleet-growth line, host-load bars, MRR bars, active runs, alerts.
- Customers: table + plan doughnut. Instances: fleet table (vmid/host/storage).
- Hosts: capacity cards (storage/CPU bars). Provisioning: runs table + live stepper.
- Revenue: MRR/ARR/ARPU/churn KPIs, MRR line, plan doughnut, recent payments.
- Locale-aware month labels/currency (Carbon/Number).
18 new Pest tests (guest redirect / non-admin 403 / admin render per section) → 44
green. R12 browser: all six admin pages HTTP 200, ZERO console errors (Chart.js dark).
Codex (R15) — clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>