Overview
Optics Terminal is a Laravel 13 application with a React 19 front end served through Inertia. There is no separate API tier: controllers render Inertia pages directly with typed props.
System architecture
Section titled “System architecture”The components the app runs on, and where each one lives.
architecture-beta
group azure(cloud)[Microsoft Azure]
group vm(azure:virtual-machine)[Virtual Machine] in azure
service app(server)[Laravel app] in vm
service redis(database)[Redis] in vm
service worker1(server)[Queue worker 1] in vm
service worker2(server)[Queue worker 2] in vm
service db(azure:postgresql)[Azure Database for PostgreSQL] in azure
service blob(azure:blob-storage)[Azure Blob Storage] in azure
service mail(azure:communication-services)[Communication Services Email] in azure
service browser(internet)[Browser]
service workos(internet)[WorkOS SSO]
browser:R --> L:app
workos:R --> L:app
app:T --> B:db
app:B --> T:blob
app:R --> L:redis
redis:R --> L:worker1
redis:R --> L:worker2
worker1:R --> L:mail
worker2:R --> L:mail
WorkOS is the only external dependency; everything else runs in Azure. Redis backs the queue, cache and session store, and the two workers consume jobs from it.
| Layer | Technology |
|---|---|
| Backend | Laravel 13, PHP 8.4 |
| Database | PostgreSQL — Azure Database for PostgreSQL in production |
| Frontend | React 19 + Inertia 3, Mantine UI |
| Admin | Filament 5 at /admin, staff only |
| Auth | WorkOS SSO |
| Files | Laravel filesystem abstraction — Azure Blob Storage in production |
Azure Communication Services Email (azure mailer); SMTP or log locally | |
| Queue | Redis, drained by two workers on the VM |
| Cache & sessions | Redis |
Multi-tenancy
Section titled “Multi-tenancy”All business data is scoped to an Organization. Users belong to one organization, and every model holding business data carries an organization_id. Isolation is enforced at the query level rather than by a package.
Request flow
Section titled “Request flow”sequenceDiagram
participant B as Browser
participant R as Route
participant C as Controller
participant S as Service
participant P as pages/{name}.tsx
B->>R: Inertia visit
R->>C: single-action controller
C->>S: business logic
S-->>C: data
C->>P: Inertia::render('page-name', $props)
P-->>B: typed props, client render
Controllers follow the single-action pattern — one class per action, grouped into feature subdirectories under app/Http/Controllers/. Business logic lives in app/Services/.
Data model
Section titled “Data model”The core entities and how they hang together. Every model is documented individually in the Entities section.
erDiagram
ORGANIZATION ||--o{ USER : "has"
ORGANIZATION ||--o{ PROJECT : "owns"
ORGANIZATION ||--o{ REPORT : "owns"
ORGANIZATION ||--o{ INVOICE : "billed"
ORGANIZATION ||--o{ SUPPORT_REQUEST : "raises"
ORGANIZATION ||--o{ CONFIGURATION_RESOURCE : "supplies"
PROJECT ||--o{ REPORT : "produces"
PROJECT ||--o{ FOCUS_INDIVIDUAL : "profiles"
PROJECT ||--o{ PROJECT_CITY : "spans"
PROJECT ||--o{ PROJECT_EXTRACTION : "derives"
REPORT }o--|| ATTACHMENT : "file"
ATTACHMENT ||--o| DOCUMENT_TEXT : "extracted text"
USER ||--o{ AGENT_SESSION : "starts"
AGENT_SESSION ||--o{ AGENT_RETRIEVAL : "retrieves"
USER ||--o{ FEEDBACK : "leaves"