Commit Graph

3 Commits (master)

Author SHA1 Message Date
Boban Blaskovic 555101c993 Step 1/5: Workspace multi-tenancy foundation
User accepted 5-step plan: Workspace → Sub-Sidebar → Switcher → Plan/
Quota → Billing.

This step adds the workspace layer underneath everything:
- Workspace model with HasUuids + relations (sites/servers/clusters/
  backups/members/invitations/activities) + plan-based quotas + feature
  flags + isOverQuota() + hasFeature() helpers.
- Plan presets: free/starter/pro/agency/enterprise with sites,
  servers, team, storage_gb, features map (audit/monitoring/
  email_relay/multi_workspace/white_label/reports/sso).
- BelongsToWorkspace trait: global scope filters by app('current
  Workspace'), creating-hook auto-fills workspace_id from container.
  Falls back to no-scope when no workspace bound (tests, console).
- Migrations: workspaces table + workspace_id foreignUuid added to
  all 10 domain tables (clusters/servers/sites/backups/team_members/
  invitations/security_events/certificates/activities/crons).
- users gets current_workspace_id nullable FK.
- team_members unique changed to composite (workspace_id, user_id) so
  one user can belong to multiple workspaces.
- ResolveCurrentWorkspace middleware: resolves active workspace from
  ?workspace=slug → session → user.current_workspace_id → first owned.
  Wired into web middleware group via bootstrap/app.php.
- WorkspaceFactory + workspace_id added to all 10 domain factories
  so tests/seed work without explicit workspace context.
- DatabaseSeeder rewritten: creates Marie Weber as owner of 'Acme
  Agency' (Pro plan) workspace + 'Marie · Personal' (Free) workspace
  for switcher demo. Binds app('currentWorkspace') so seeded sites/
  servers/backups/etc. land in the right workspace.
- Sidebar component reads auth user's current workspace for the ws-
  switch panel — no more hard-coded 'Acme Cluster' string.

Full Pest regression: 47/47 green. 2 workspaces seeded:
- Acme Agency (pro): 87 sites, 6 servers, 128 sec events, 102 backups
- Marie · Personal (free): 0 sites
2026-06-01 01:12:00 +02:00
Boban Blaskovic 7276e27408 Domain models: Cluster/Server/Site/Backup/TeamMember/Invitation/SecurityEvent/Certificate/Activity/Cron
Full Eloquent foundation matching template data:
- 10 migrations (clusters, servers, sites, backups, team_members,
  invitations, security_events, certificates, activities, crons).
- 10 models with relationships + casts + accessors.
- 10 factories.
- DatabaseSeeder seeds matching template stats:
  - Marie Weber (m.weber@acme-cluster.de / clupilot) as owner
  - Admin (admin@clupilot.test / clupilot)
  - 1 Acme Cluster, 6 named servers (eu-prod-01/-02, edge-ams,
    us-east-01, staging, ap-bom-01) with CPU/RAM/disk loads from template
  - 87 sites distributed [23,19,14,18,6,7] per server
  - 102 backups, 87 SSL certificates, 47 cronjobs
  - 128 security events (matches template 'Blocked / 24h')
  - 5 team members + 3 pending invitations
  - 30 activity feed entries.
2026-05-31 22:33:09 +02:00
Boban Blaskovic 624b21fcb9 Initial CluPilot stack setup
Laravel 12 + Livewire v3 + Tailwind v4 + Reverb WebSocket
behind Nginx Proxy Manager (external SSL termination, HTTP-only internal).
MariaDB 11, Redis 7, Mailpit. Dark auth views.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:00:14 +02:00