Shared Laravel infrastructure for application-level framework concerns like audited models, idempotent seeders, API error handling, configuration validation, and snapshot tooling. Chassis serves as the core framework layer for Northwestern University's Laravel Starter, while remaining usable in other Laravel applications that want these features without copying boilerplate between projects.
| Area | Included |
|---|---|
| Eloquent foundations | BaseModel, Auditable, HasAutomaticOrdering, #[AutomaticallyOrdered] |
| Seeding | IdempotentSeeder, #[AutoSeed], dependency resolution, orphan cleanup helpers |
| API infrastructure | ProblemDetails, ProblemDetailsRenderer, token auth middleware, request logging |
| Environment controls | EnvironmentLockdown, EnsureFeatureEnabled |
| Validation | #[ValidatesConfig], ConfigValidator, php artisan config:validate |
| Database tooling | db:rebuild, db:wake, schema-aware snapshot commands |
| Misc utilities | @datetime, DateTimeFormatter, ValidIpOrCidrRule, SentryExceptionHandler |
composer require northwestern-sysdev/chassisThe fastest way to adopt Chassis is to use the parts that remove the most boilerplate first.
use Northwestern\SysDev\Chassis\Models\BaseModel;
class Project extends BaseModel
{
//
}BaseModel extends Eloquent's Model and wires in audit logging plus attribute-driven automatic ordering.
use Northwestern\SysDev\Chassis\Attributes\AutoSeed;
use Northwestern\SysDev\Chassis\Seeding\IdempotentSeeder;
#[AutoSeed]
class RoleSeeder extends IdempotentSeeder
{
protected string $model = Role::class;
protected string $slugColumn = 'slug';
public function data(): array
{
return [
['slug' => 'admin', 'label' => 'Admin'],
['slug' => 'editor', 'label' => 'Editor'],
];
}
}use Northwestern\SysDev\Chassis\Attributes\ValidatesConfig;
use Northwestern\SysDev\Chassis\Contracts\ConfigValidator;
#[ValidatesConfig(description: 'Directory Search credentials')]
class DirectorySearchValidator implements ConfigValidator
{
public function shouldRun(): bool { /* ... */ }
public function validate(): bool { /* ... */ }
public function successMessage(): string { /* ... */ }
public function errorMessage(): string { /* ... */ }
public function hints(): array { /* ... */ }
}Then run:
php artisan config:validateSubclass ProblemDetailsRenderer to keep Chassis' default exception mapping and layer in your domain-specific cases:
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Northwestern\SysDev\Chassis\Exceptions\ProblemDetailsRenderer;
use Northwestern\SysDev\Chassis\Http\Responses\ProblemDetails;
use Throwable;
class AppProblemDetailsRenderer extends ProblemDetailsRenderer
{
protected function mapCustomExceptions(Throwable $e, Request $request): ?JsonResponse
{
return match (true) {
$e instanceof TokenBudgetExceededException => tap(
ProblemDetails::tooManyRequests(detail: $e->getMessage()),
fn () => $this->setFailure('token-budget-exceeded'),
),
default => null,
};
}
}BaseModelis the default model base for chassis-aware apps.Auditableenrichesowen-it/laravel-auditingrecords with request context such as trace IDs, Livewire component names, and impersonator IDs when available.#[AutomaticallyOrdered]adds declarative default ordering, usingorder_index asc, label ascunless you override the columns and directions.HasAutomaticOrderinglets non-BaseModelclasses opt into the same behavior.
See Audit Logging and Framework Defaults: Eloquent behavior.
Chassis' seeding layer is built for repeated execution across local, CI, staging, and production environments.
#[AutoSeed]marks a seeder for discovery.- Dependencies are validated and executed in topological order.
- Rows are upserted by your declared slug column.
- Soft-deleted matches are restored instead of duplicated.
- Orphan cleanup is available when you opt in.
For more advanced cases, override afterUpsert(Model $model, array $row) and list any non-column keys in $transient.
If your seeder cannot extend the base class cleanly, use the lower-level PerformsIdempotentUpserts and CleansUpOrphans concerns directly.
See Idempotent Seeding.
ProblemDetailsbuilds RFC 9457 responses such asunauthorized(),forbidden(),notFound(),unprocessableEntity(), andconflict().ProblemDetailsRenderermaps framework and infrastructure exceptions to RFC 9457 JSON for API and JSON-negotiated requests.AuthenticatesAccessTokensis an abstract middleware base for bearer token auth with hashing, IP allowlisting, expiration checks, and usage recording.LogsApiRequestsrecords request outcome, timing, size, token, and trace metadata, and emitsX-Trace-Idon responses.EnvironmentLockdownrestricts non-production environments to authorized users.EnsureFeatureEnabledshort-circuits routes behind config flags.AccessTokenContractdefines the token model hooks the auth middleware relies on.
See API and RFC 9457 defaults.
php artisan config:validate discovers every class implementing ConfigValidator that is decorated with #[ValidatesConfig].
Validators run concurrently and report pass, fail, or skip states with remediation hints.
See Command reference: config:validate.
Chassis wraps spatie/laravel-db-snapshots with schema checksums so restores can detect drift between the snapshot's source schema and the current app state.
php artisan db:snapshot:create baseline
php artisan db:snapshot:list
php artisan db:snapshot:restore baseline
php artisan db:snapshot:info baseline
php artisan db:snapshot:delete baselineSnapshot commands are registered only when spatie/laravel-db-snapshots is installed. They are intended for non-production use.
PostgreSQL utilities are resolved from config('db-snapshots.pg_bin_directory') when configured. If no directory is configured, Chassis discovers common Herd paths on macOS and Windows, and otherwise falls back to the operating system PATH. Linux CI runners should normally install PostgreSQL client tools through the runner image or setup action rather than hard-coding a local path.
See Database Snapshots.
| Command | Purpose |
|---|---|
config:validate |
Run all discovered #[ValidatesConfig] validators. |
db:rebuild |
Fresh migrate and seed, with cache and related cleanup. |
db:seed:list |
List discovered #[AutoSeed] seeders. Supports dependency output, Mermaid, and JSON. |
db:wake |
Retry database connection until a cold or sleeping database is available. |
db:snapshot:create {name?} |
Create a schema-tagged database snapshot. |
db:snapshot:restore {name?} |
Restore a snapshot and warn if the schema checksum has drifted. |
db:snapshot:list |
List saved snapshots. |
db:snapshot:info {name} |
Show snapshot metadata and schema checksum details. |
db:snapshot:delete {name} |
Delete a snapshot and its metadata. |
restore-env-files |
Restore local-only environment files after a clean checkout. |
RunsSteps is also available if you want the same structured spinner + summary experience in your own multi-step Artisan commands.
Full command docs: https://laravel-starter.entapp.northwestern.edu/reference/commands/
@datetimerenders timestamps in the authenticated user's timezone via theDateTimeFormatterservice.ValidIpOrCidrRulevalidates IPv4, IPv6, and CIDR input.SentryExceptionHandlerenriches Sentry reporting with user context whensentry/sentry-laravelis installed.ApiRequestContextcentralizes request context keys shared across middleware, logging, and exception handling.ApiRequestFailurestandardizes API failure labels, descriptions, and icons for UI consumption.
Some features stay opt-in so applications only install what they use.
| Package | Enables |
|---|---|
spatie/laravel-db-snapshots |
db:snapshot:* commands |
sentry/sentry-laravel |
SentryExceptionHandler |
lab404/laravel-impersonate |
Impersonator tracking in audit records |
composer install
composer test
composer analyse:php
composer format:php
composer rector
composer allThe MIT License (MIT). See LICENSE.