#Product architecture
#System context
Browser
Central frontend (Next.js 16, frontend-2)
Central backend
sa-central-api-2 (Laravel 13, Sanctum, MySQL sv_central_2, Redis, Horizon) — Phase 1 built 2026-10-08, API at /api/v1
External
Each server's OSS panel API (Bearer sv_central_…)Payment gatewaysCloud providers (DigitalOcean, Linode, Vultr, Hetzner, Lightsail…)MailTurnstileGoogle / GitHub OAuth
- The browser only talks to sa-central-api-2. It never calls an OSS panel or a provider directly. Server keys and provider tokens stay on the backend. V8 requirement R5 (common OSS client) · Security
- sa-central-api-2 holds accounts, organizations, billing, roles and a small link record per server. It calls OSS panels through one shared OSS client (built with the Servers phase, not the Foundation phase — backend update 2026-10-03) that handles auth headers, timeouts, retries, error mapping and secret-free logging. V8 requirement §2.2
- OSS panels answer with live data. The Central key signs in as a machine administrator account on that panel (
CentralSystemGuard). It can use the whole OSS API except creating, changing or deleting panel users and roles. OSS API
#What lives where (V8 rule R5)
| Central database (stored) | OSS panel (fetched live, never stored in Central) |
|---|---|
| Users, login data, 2FA, IP whitelist, sessions | Server facts, metrics, processes |
| Organizations, members, roles, permissions | Applications and everything inside them |
| Plans, subscriptions, wallet, transactions, invoices | Databases, system users, services, firewall, cron, backups… |
| Providers (encrypted tokens) | OSS's own activity log ("central" machine account) |
| A few link fields per server (which ones is still open, Q1) | Panel version, health |
| Blueprints (Central stores them, as V7 did; OSS runs them) OSS API | Add-on run results |
| Central audit log, notifications |
V8 requirement §2.1
#Request path
Browsersa-central-api-2 (auth + organization + permission + plan checks)OSS client (server key, timeout, retry)OSS panel APIresponse mapped to Central error codesBrowser
#Frontend architecture
| Layer | Choice | Status |
|---|---|---|
| Framework | Next.js 16 App Router, JavaScript only | Confirmed scaffold |
| UI | shadcn/ui primitives in components/ui/ (button, card, dialog, dropdown, input, select, sheet, table, tabs, tooltip, sonner…), Tailwind v4 | Confirmed scaffold |
| i18n | next-intl without a locale URL segment (locale from a cookie), messages/<locale>.json | Required by project rules. Not installed yet Missing |
| Forms | react-hook-form + zod | zod installed · react-hook-form not installed Missing |
| Tables | TanStack Table v8 | Not installed Missing |
| HTTP | axios instance in lib/api/ with interceptors | axios installed · client not written |
| State | Zustand for cross-component UI state (current organization, sidebar) | installed |
| Charts | Recharts | installed |
| Theme | next-themes | installed |
Rule for the build: server components by default, "use client" only where state, effects or browser APIs are needed. Every route group gets loading, error and not-found. The frontend is a view layer with no business logic.
#Backend architecture (from the V8 doc)
| Concern | Decision | Source |
|---|---|---|
| Framework | Laravel 13 | V8 requirement Phase 1 |
| Database | MySQL — target 8.4 LTS, driver mysql (changed from MariaDB on 2026-10-08), separate per pair (sv_central_backend for Pair 1 — renamed 2026-10-09 because sv_central already holds the Central WordPress site — and sv_central_2 for Pair 2, which is the one this frontend talks to), utf8mb4 with utf8mb4_unicode_ci, strict mode. Development runs on the server's existing MariaDB 10.11, with the code kept MySQL-compatible (Eloquent only, no MariaDB-only SQL, json columns via casts, UUIDs as char(36)) | V8 requirement (currently still SQLite in .env) |
| Cache / sessions / queue | Redis; Horizon queues default, notifications, emails | V8 requirement |
| API auth | Laravel Sanctum (changed from Passport on 2026-10-08): Bearer API tokens only, no SPA cookie / stateful mode. Access 15 days; refresh 30 days built by Central, because Sanctum has none; token abilities used for scopes. The personal API token (3.13, excluded from the frontend) never expires — corrected 2026-10-09, when 3.13 was built and said so plainly; this row previously read "its own expiry when created", inferred from Phase 1's note that Sanctum's global expiry is deliberately left empty. V7's fixed 6 months is gone, and nothing replaces it | V8 requirement |
| CORS | Only the configured frontend URL; api/*, oauth/*; Authorization header | V8 requirement |
| Logs | Daily, 14 days, never tokens/passwords/Authorization | V8 requirement |
| Tests | Pest for every endpoint; OSS faked with Http::fake | V8 requirement |