Common conventions
The shared naming, configuration, model-resolution and data conventions that every OI Laravel package follows
Common conventions
Every package is generated from — and audited against — the same standard. This page summarises the parts you'll notice as a consumer of the packages. (The full authoring standard lives in the internal package-creator skill.)
Naming
Names are derived mechanically from the package slug, so once you know one, you can predict the rest:
| Item | Rule | Example (oi-laravel-insee) |
|---|---|---|
| Composer name | oi-lab/oi-laravel-<thing> | oi-lab/oi-laravel-insee |
| Root namespace | OiLab\OiLaravel<Thing> | OiLab\OiLaravelInsee |
| Service provider | OiLaravel<Thing>ServiceProvider | OiLaravelInseeServiceProvider |
| Config file & key | <slug>.php / '<slug>' | oi-laravel-insee |
| Publish tags | <slug>-config, <slug>-migrations, <slug>-skill, <slug>-stubs | oi-laravel-insee-config |
| AI skill dir | <slug> with oi-laravel- → oilab-laravel- | oilab-laravel-insee |
| Command prefix | one namespace per package | doc:, seed:, metadata:, publish: |
Installation & publishing
Because every package mergeConfigFroms its config in the service provider,
sensible defaults exist without publishing anything. Publish only what you
want to customise, using the predictable tags:
# Publish a package's config
php artisan vendor:publish --tag=oi-laravel-insee-config
# Database packages also expose a migrations tag
php artisan vendor:publish --tag=oi-laravel-<slug>-migrationsAll publishable groups are console-only and tagged <slug>-*. Database packages
auto-load their migrations, so publishing them is optional.
Swapping models through config
Packages that ship Eloquent models never hardcode ::class internally — model
class names are configuration strings resolved at runtime through a static
resolver. That means you can point a package at your own subclass:
// config/oi-laravel-notes.php
'models' => [
'note' => App\Models\Note::class, // your implementation
'user_model' => App\Models\User::class,
],Resolve model classes through the package's facade/resolver (for example
OiNotes, OiLaravelAttachments, Insee) rather than referencing the vendor
class directly, so your config overrides always apply.
Typed data with spatie/laravel-data
Structured data never crosses a package boundary as a raw array. As soon as a
package exposes a model or a structured response, it uses
spatie/laravel-data: Data classes,
toData(), prop casts, and API DTOs. So return values are typed value
objects, not associative arrays — expect ->toData() and typed properties
throughout (for example, oi-laravel-umami
returns typed DTOs, oi-laravel-settings
exposes value objects).
Configuration shape
Config files are plain return [ ... ] arrays with env() defaults and
Laravel-style docblock headers. Recurring sections:
models.*— swappable class-name strings (see above);user_modeldefaults toApp\Models\User.route.*—enabled,prefix,name,middleware,gatefor web-facing packages (routes are registered only whenroute.enabledis true).- Feature flags as
<feature>.enabled. - Disk selection cascades:
env('<PREFIX>_DISK', env('FILESYSTEM_DISK', 'local')).
Testing & quality
Every package ships the same quality tooling, so contributions run identically:
- Pest on top of Orchestra Testbench, with an in-memory SQLite
testingconnection andRefreshDatabasefor database packages. - Strict
phpunit.xml(failOnRisky,failOnWarning) with splittests/Unitandtests/Featuresuites. - Laravel Pint (
{"preset": "laravel"}) viacomposer lint. - A GitHub Actions matrix — PHP 8.2/8.3/8.4 × Laravel 11/12/13 — on every push.
composer test # vendor/bin/pest
composer lint # vendor/bin/pint