Laravel Implementation — Component Inventory
Every package and infrastructure component used in this implementation, with a clear explanation of why it is needed and what it replaces or provides.
Application Server
Laravel Octane (Swoole driver)
Package: laravel/octane
Driver: Swoole (recommended over RoadRunner for connection pooling support)
PHP-FPM discards the entire application state after every request and rebuilds it from scratch on the next. For a Filament application with ~96 models, 3 panels, and a full RBAC resolver, that bootstrap cost is significant on every request.
Octane keeps the application resident in memory. The bootstrap runs once at server start. Subsequent requests skip the boot phase entirely and go straight to request handling.
What this means in practice:
| Operation | PHP-FPM | Octane |
|---|---|---|
| Laravel boot | ~40–80ms per request | Once at startup |
| Filament panel load | ~30–50ms per request | Amortised |
| Route + middleware resolution | ~5–15ms per request | Cached in memory |
| Rate plan resolution (cached) | DB query per request | In-memory Octane table |
Critical constraint: Any class registered as a singleton that holds per-request
state will leak between requests. Use scoped() for anything that touches the current
user, tenant, or request context. See Octane for the full
memory safety guide.
Admin UI
Filament v3
Package: filament/filament
The admin panel is the primary interface for internal staff (lawyers, paralegals, billing admin). Building this as a custom React frontend would require months of work. Filament provides CRUD resources, relation managers, table filters, form components, actions, widgets, and a complete panel framework.
Three panels are registered:
| Panel | Path | User Type |
|---|---|---|
| Admin | /admin | FIRM_USER_PROFILES (internal staff) |
| Client Portal | /portal | CLIENT_USERS (clients) |
| Partner Portal | /partner | PARTNER_ATTORNEY_USERS (partner attorneys) |
Each panel has its own auth guard, middleware stack, and set of resources. Filament's
built-in tenancy system scopes all queries to the current LAW_FIRMS record automatically.
Authentication
Laravel Fortify (via Filament)
Built into Filament — no separate installation needed.
Provides email + password authentication, password reset, and email verification for all three user types. Filament wraps Fortify's features into panel-specific login pages.
Laravel Sanctum
Package: laravel/sanctum
Even though Filament uses session-based auth, external consumers (mobile apps, third-party
integrations) need stateless API token authentication. Sanctum issues personal_access_tokens
scoped to a user with named abilities (e.g., time-entries:write, invoices:read).
Sanctum adds one table: personal_access_tokens. It requires no separate server or
infrastructure — tokens are validated in the same Laravel request cycle as Filament.
Database
PostgreSQL 15+
The original schema uses several PostgreSQL-specific features that make it the required database driver:
jsonbcolumns —app_preferences,default_fields,condition_jsonon RBAC tables- Partial indexes — enforcing uniqueness on non-null subsets
bigintprimary keys throughout — consistent with PostgreSQL's sequence generator
Laravel Migrations
Schema migrations translate the schema changes from the
original DBML into versioned, reversible PHP migration files. The 15-batch ordering in
the schema changes document ensures foreign key constraints are never violated during
php artisan migrate.
Cache & Sessions
Redis
Redis serves three roles simultaneously:
| Role | Laravel config | Purpose |
|---|---|---|
| Cache driver | CACHE_DRIVER=redis | Rate plan resolution cache, permission trees, Octane warm data |
| Session driver | SESSION_DRIVER=redis | Faster than database sessions under Octane's persistent connections |
| Queue driver | QUEUE_CONNECTION=redis | Backing store for Horizon |
A single Redis instance handles all three in development. Production should use separate Redis instances or databases for cache vs. sessions vs. queues to prevent eviction interference.
Background Processing
Laravel Horizon
Package: laravel/horizon
Background jobs are critical to this system — invoice PDF generation, ERP export queue flushing, document processing, and notification dispatch all run asynchronously. Horizon provides:
- A real-time dashboard showing queue throughput and failure rates
- Per-queue worker configuration (billing jobs get dedicated workers)
- Automatic worker supervision and restart on failure
- Failed job inspection and retry without shell access
Horizon requires Redis as the queue driver. It adds no database tables — all state lives in Redis.
Queue Tables
Three database tables support Laravel's queue and batch processing system:
| Table | Purpose |
|---|---|
jobs | Pending jobs waiting for a worker |
failed_jobs | Failed jobs preserved for inspection and retry |
job_batches | Coordination state for batch job groups |
failed_jobs is particularly important for financial jobs. If an invoice generation job
fails, the failure must be inspectable and retryable — not silently dropped.
Real-time
Laravel Reverb
Package: laravel/reverb
Lawyers need live notifications when a matter is assigned, an invoice is paid, or an appointment is updated. Polling the API every few seconds is wasteful and introduces lag. Reverb is Laravel's first-party WebSocket server.
Reverb integrates directly with Laravel's broadcasting system — the same broadcast()
calls used for Filament's notification component push to the WebSocket server. No
separate Node.js process or third-party service (Pusher, Ably) is needed.
Search
Laravel Scout + Meilisearch
Packages: laravel/scout, meilisearch/meilisearch-php
Lawyers search across matters, clients, and documents by keyword. Full-text search using
PostgreSQL ILIKE queries degrades badly at scale and does not support typo-tolerance or
relevance ranking.
Scout provides the Eloquent abstraction (Matter::search('contract dispute')).
Meilisearch provides typo-tolerant, sub-50ms full-text search with configurable
relevance ranking.
Searchable models: Matter, Client, Document, FirmUserProfile.
Domain Packages
spatie/laravel-activitylog
Package: spatie/laravel-activitylog
Every change to a financial record must be logged immutably for ABA compliance and audit
trail purposes. This package hooks into Eloquent model events and records before/after
states in the activity_log table.
Applied to: all financial models (Invoice, Payment, LawyerTimeEntry,
ExpenseEntry), plus Matter, Client, FirmUserProfile, and UserRoleAssignment.
The activity_log table stores subject_type, subject_id, causer_type,
causer_id, event, and a properties JSON column containing the full before/after
diff.
spatie/laravel-media-library
Package: spatie/laravel-media-library
The DOCUMENTS table tracks files with S3 paths, version history, MIME types, and
metadata. Media Library handles S3 upload, presigned URL generation, file versioning, and
polymorphic attachment to any model.
This replaces manually managing S3 paths in the documents table with a managed media
table that supports collections (e.g., matter-documents, profile-photos) and
conversions (e.g., thumbnail generation).
spatie/laravel-pdf
Package: spatie/laravel-pdf
Invoice PDFs must be generated as print-quality documents. This package uses a headless Chromium instance to render Blade templates — pixel-perfect output that handles complex table layouts, page breaks, and headers/footers correctly.
The alternative (barryvdh/laravel-dompdf) uses a PHP-based HTML-to-PDF renderer that
struggles with multi-page financial documents and CSS positioning.
Custom RBAC (no package)
The PERMISSIONS, ROLES, USER_ROLE_ASSIGNMENTS, and RESOURCE_ACCESS_GRANTS schema
is more sophisticated than any off-the-shelf RBAC package provides. It supports:
- Role scoping (GLOBAL, FIRM, ORG_UNIT, MATTER)
- Polymorphic resource-level ACLs
- Field-level visibility policies per role
- Temporal role assignments (
starts_at,ends_at)
spatie/laravel-permission does not support these. Instead, custom Laravel Policies query
the existing schema directly. Filament respects Laravel Policies automatically — no
additional wiring is needed.
See RBAC & Policies for the full implementation.
Development Tools
Laravel Telescope
Package: laravel/telescope
With complex multi-tenant RBAC and billing logic, N+1 query problems are easy to introduce. Telescope provides per-request query inspection, job monitoring, cache hit/miss tracking, and exception detail in a local web UI.
Telescope is installed in development and staging only. It is excluded from production
via an environment check in TelescopeServiceProvider. Its three tables
(telescope_entries, telescope_entries_tags, telescope_monitoring) exist only in
non-production environments.
Pest PHP
Package: pestphp/pest + pestphp/pest-plugin-laravel
The billing logic (rate resolution, invoice generation) and RBAC checks are the highest-
risk parts of the system. Pest's expressive, function-based syntax reduces test boilerplate
and makes test intent clear. Its arch() plugin can enforce architectural rules (e.g.,
"no controller directly queries the database").
All tests are written with Pest. PHPUnit is the underlying runner — Pest is a layer on top, not a replacement.
Component Summary
| Component | Package | Category |
|---|---|---|
| Application server | laravel/octane (Swoole) | Performance |
| Admin UI | filament/filament | UI |
| API token auth | laravel/sanctum | Auth |
| WebSockets | laravel/reverb | Real-time |
| Queue dashboard | laravel/horizon | Infrastructure |
| Full-text search | laravel/scout + Meilisearch | Search |
| Audit logging | spatie/laravel-activitylog | Compliance |
| File management | spatie/laravel-media-library | Documents |
| PDF generation | spatie/laravel-pdf | Billing |
| Dev inspection | laravel/telescope | Developer tools |
| Testing | pestphp/pest | Quality |
| Database | PostgreSQL 15+ | Data |
| Cache / Queue | Redis | Infrastructure |