System Overview
This document describes the Laravel + Filament system architecture — how the four subsystems are structured, how requests flow through the stack, and how this maps to the existing C4 container diagram.
The Four Subsystems
┌──────────────────────────────────────────────────────────────────┐
│ Laravel Octane (Swoole) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
│ │ Admin Panel │ │ Client Portal │ │ Partner Portal │ │
│ │ /admin/* │ │ /portal/* │ │ /partner/* │ │
│ │ │ │ │ │ │ │
│ │ Internal staff │ │ CLIENT_USERS │ │ PARTNER_ │ │
│ │ (lawyers, │ │ Read matters, │ │ ATTORNEY_USERS │ │
│ │ billing, admin)│ │ pay invoices │ │ Submit time │ │
│ │ │ │ │ │ │ │
│ │ Filament panel │ │ Filament panel │ │ Filament panel │ │
│ │ Session auth │ │ Session auth │ │ Session auth │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └───────────────────┴────────────────────┘ │
│ │ │
│ ┌────────────────▼───────────────┐ │
│ │ REST API Layer │ │
│ │ /api/v1/* │ │
│ │ │ │
│ │ Implements OpenAPI contracts │ │
│ │ Sanctum token authentication │ │
│ │ Used by mobile / integrations │ │
│ └────────────────┬───────────────┘ │
│ │ │
│ ┌────────────────────────────▼──────────────────────────────┐ │
│ │ Domain Services Layer │ │
│ │ │ │
│ │ RateResolutionService InvoiceGeneratorService │ │
│ │ RbacCheckerService TenantResolverService │ │
│ │ DocumentService │ │
│ └────────────────────────────┬──────────────────────────────┘ │
│ │ │
└───────────────────────────────┼──────────────────────────────────┘
│
┌───────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌────────────┐ ┌────────────┐
│ PostgreSQL│ │ Redis │ │ S3 / R2 │
│ (primary) │ │ Cache + │ │ Documents │
│ │ │ Sessions + │ │ │
│ │ │ Queues │ │ │
└───────────┘ └────────────┘ └────────────┘
External: Stripe (payments) · Meilisearch (search) · SMTP (email)
Subsystem 1 — Admin Panel (/admin)
Users: Internal staff — lawyers, paralegals, billing administrators, firm admins.
Auth: Laravel guard web backed by the users table, linked to FIRM_USER_PROFILES.
Filament's built-in login page handles authentication.
Tenancy: The firm is resolved from the URL slug (/admin/{firm-slug}/...). Filament's
HasTenants interface on LawFirm automatically scopes all Eloquent queries to the
current firm.
What it provides:
- Full CRUD for matters, clients, time entries, invoices, documents
- Billing workflows: generate invoice, record payment, issue credit note
- HR: staff profiles, org units, performance reviews, bonus awards
- RBAC management: role assignment, access grant administration
- Partner management: partner firms, partner attorneys, partner bills
- Reporting widgets: billable hours this month, outstanding invoices, active matters
Subsystem 2 — Client Portal (/portal)
Users: CLIENT_USERS — clients who have been invited to the portal.
Auth: Laravel guard client backed by the users table, linked via CLIENT_USERS
to CLIENT_CONTACTS. A client can only see records associated with their own client record.
What it provides (read-heavy, limited write):
- View their active matters and matter status
- Download invoices and documents shared with them
- Pay outstanding invoices (Stripe integration)
- View and respond to appointment invitations
Subsystem 3 — Partner Portal (/partner)
Users: PARTNER_ATTORNEY_USERS — attorneys from partner firms who collaborate on
shared matters.
Auth: Laravel guard partner backed by the users table, linked via
PARTNER_ATTORNEY_USERS to PARTNER_ATTORNEYS.
What it provides:
- View matters they are assigned to via
MATTER_PARTNER_ATTORNEYS - Submit time entries for billing
- View partner bills issued to their firm
- Download matter documents they have access to
Subsystem 4 — REST API Layer (/api/v1)
Users: Mobile apps, external integrations, third-party consumers.
Auth: Laravel Sanctum API tokens (Bearer token in Authorization header). Tokens are
scoped with named abilities matching the permission codes in the PERMISSIONS table.
Contract: Implements the same OpenAPI specification defined in
/openapi/user-apis.yaml and
/openapi/admin-api.yaml. Any client that works against the
original API spec works against this implementation without changes.
Request Flow
Filament Panel Request
Browser
│ HTTPS POST /admin/{firm}/matters
▼
Octane Worker (in memory)
│ 1. TenantMiddleware resolves LAW_FIRMS from slug → sets app tenant
│ 2. FilamentAuthMiddleware validates session → resolves User + FirmUserProfile
│ 3. PolicyMiddleware checks Laravel Policy for the resource action
▼
Filament Livewire Component
│ 4. Form validated, Eloquent model saved (scoped to tenant)
│ 5. Domain service called if business logic involved
│ 6. Activity logged via spatie/activitylog observer
│ 7. Notification broadcast via Reverb
▼
Response rendered (Livewire diff, not full page)
API Request (Sanctum)
Mobile App
│ HTTPS POST /api/v1/matters
│ Authorization: Bearer {token}
▼
Octane Worker
│ 1. SanctumMiddleware validates token → resolves User
│ 2. TenantMiddleware resolves firm from token's user FK to firm_user_profiles
│ 3. PolicyMiddleware checks Laravel Policy
▼
API Controller
│ 4. Request validated (Form Request class)
│ 5. Domain service called
│ 6. Activity logged
│ 7. JSON response via API Resource class
▼
JSON Response
Background Job Flow
Trigger (e.g., "Generate Invoice" Filament Action)
│
▼
GenerateInvoiceJob dispatched to Redis queue
│
▼
Horizon worker picks up job
│
├── InvoiceGeneratorService::generate(Matter $matter)
│ ├── Fetches approved time entries
│ ├── Resolves rates via RateResolutionService
│ ├── Creates Invoice + InvoiceLineItems (append-only)
│ └── Marks time entries as invoiced
│
├── spatie/laravel-pdf generates PDF → uploads to S3
│
└── Notification dispatched → Reverb → browser
Deployment Architecture
┌──────────────┐
│ Nginx / │
HTTPS ────►│ Caddy │
│ (reverse │
│ proxy) │
└──────┬───────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Octane │ │ Octane │ │ Octane │
│ Worker 1 │ │ Worker 2 │ │ Worker N │
└──────────┘ └──────────┘ └──────────┘
│
├──► PostgreSQL (primary + read replica)
├──► Redis (cache + sessions + queues)
├──► S3-compatible storage
└──► Meilisearch
┌──────────┐
│ Horizon │ (separate process, same codebase)
│ Queue │──► PostgreSQL, Redis, S3
│ Worker │
└──────────┘
┌──────────┐
│ Reverb │ (WebSocket server, same codebase)
│ WebSocket│──► Redis (pub/sub)
└──────────┘
Octane, Horizon, and Reverb all run from the same Laravel application codebase. They
are separate OS processes but share the same config/, app/, and database/ code.