Configuration
Configuration
Externa’s runtime settings live in externa-core/config/*.php and are driven by .env (see Environment variables). This page covers the application defaults you should understand before going to production.
Related pages
Files: Files configuration. AI: AI configuration. Permissions model: Effective permissions.
Application (config/app.php)
| Key / env | Default | Notes |
|---|---|---|
APP_NAME | Laravel | Display name in mail/UI strings that read config('app.name'). Shared to Inertia as name. |
APP_ENV | production in config; .env.example uses local | Environment label. |
APP_DEBUG | false in config; true in .env.example | Disable in production. |
APP_URL | http://localhost | Canonical URL for Artisan, mail links, public disk URLs, and Fortify passkeys RP. Must match how browsers reach the app. App works on HTTP; passkeys need HTTPS / localhost — Passkeys. |
APP_KEY | (required) | Encryption key; generated by composer setup / key:generate. |
APP_LOCALE | en | Default Laravel locale. |
APP_FALLBACK_LOCALE | en | Fallback when a translation key is missing. |
APP_FAKER_LOCALE | en_US | Faker locale for factories/seed demos. |
timezone | UTC | Hard-coded in config (not env-driven). |
| Maintenance | APP_MAINTENANCE_DRIVER=file, store default database | Standard Laravel maintenance mode. |
APP_NAME=Laravel
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
Three locale systems
- Admin UI locale —
config/i18n.php+ user preference / cookie (APP_LOCALEis the default). Controls the shell language (en/it/de). - Content locales — project settings (
content_locales,default_content_locale,fallback_content_locales). Source of truth for translatable collection field values and labels. Seeded fromconfig/collections.phpuntil saved. UI: Project settings. - Laravel
APP_LOCALE/APP_FALLBACK_LOCALE— framework translator defaults; also used as a last-resort content resolve hint when nothing else matches.
Changing the admin UI language does not change which content locales are enabled.
Fortify (config/fortify.php)
Laravel Fortify provides session authentication for the Inertia SPA.
| Setting | Value |
|---|---|
| Guard | web |
| Password broker | users |
| Username / email field | email |
lowercase_usernames | true |
| Home path | /dashboard |
| Route prefix / domain | empty / null |
| Middleware | ['web'] |
| Views | enabled (true) — Inertia auth pages under resources/js/pages/auth/* |
| Login throttle | limiter login (5/min) |
| Two-factor throttle | limiter two-factor (5/min) |
| Passkeys throttle | limiter passkeys |
Enabled features
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
Features::twoFactorAuthentication([
'confirm' => true,
'confirmPassword' => true,
'window' => 1, // ±30s TOTP skew
]),
Features::passkeys([
'confirmPassword' => true,
]),
Passkeys also use the passkeys config block (relying_party_id, allowed_origins, user_handle_secret, timeout) derived from APP_URL / APP_KEY. Operator guide: Passkeys.
To disable a feature, remove it from the features array in config/fortify.php and adjust the UI accordingly.
Authenticated product routes also require the verified middleware (see Routing overview).
Session, cache, and queue defaults
Externa’s .env.example uses database drivers for all three. That keeps local setup simple and matches the queue-backed file zip/duplicate and AI import jobs.
| Concern | Config file | Env | Default |
|---|---|---|---|
| Session driver | config/session.php | SESSION_DRIVER | database |
| Session lifetime | SESSION_LIFETIME | 120 minutes | |
| Session encrypt | SESSION_ENCRYPT | false | |
| Cache store | config/cache.php | CACHE_STORE | database |
| Queue connection | config/queue.php | QUEUE_CONNECTION | database |
| Default filesystem disk | config/filesystems.php | FILESYSTEM_DISK | local |
SESSION_DRIVER=database
SESSION_LIFETIME=120
CACHE_STORE=database
QUEUE_CONNECTION=database
FILESYSTEM_DISK=local
Queue worker required
With QUEUE_CONNECTION=database (or Redis/etc.), you must run a worker. composer run dev starts php artisan queue:listen. Production needs a supervised worker plus the scheduler — see Operations and Deployment.
Optional Redis variables are present in .env.example if you switch drivers later (REDIS_*, MEMCACHED_HOST).
Super-admin seeding (config/super_admin.php)
Used only by CreateSuperAdminSeeder when you run php artisan db:seed (via DatabaseSeeder).
| Config key | Env | Default |
|---|---|---|
first_name | INITIAL_SUPER_ADMIN_FIRST_NAME | Super |
last_name | INITIAL_SUPER_ADMIN_LAST_NAME | Admin |
email | INITIAL_SUPER_ADMIN_EMAIL | superadmin@example.com |
password | INITIAL_SUPER_ADMIN_PASSWORD | password |
DatabaseSeeder order:
PermissionSeeder→php artisan permissions:syncRoleSeeder→ built-in roles (super-admin,admin,reader,public) and permission assignmentsCreateSuperAdminSeeder→ upserts the user by email and assigns the super-admin role
Production
Override INITIAL_SUPER_ADMIN_* before seeding shared or production environments. Never leave the default password outside local development.
Permission configuration overview
| Piece | Location |
|---|---|
| Spatie package config | config/permission.php |
| Canonical permission names | App\Enums\PermissionEnum |
| Sync command | php artisan permissions:sync (--prune removes DB rows no longer in the enum) |
| TS mirror | Regenerated at resources/js/enums/permission-enum.ts |
| Teams | disabled (teams => false) |
| Permission cache | 24 hours, key spatie.permission.cache, store default |
| Effective resolution | App\Services\Authorization\EffectivePermissionResolver |
| Middleware aliases | permission, can.manage.files in bootstrap/app.php |
Key Spatie settings that matter for Externa:
- Models: default Spatie
Permission/Role register_permission_check_method→truedisplay_permission_in_exception/display_role_in_exception→false(avoid leaking names)- Wildcard permissions → disabled
Full authorization walkthrough: Effective permissions.
After deploying enum changes, run:
php artisan permissions:sync
# optional: php artisan permissions:sync --prune
Content locales (project settings)
Source of truth: Project settings → content_locales (ordered, min 1), default_content_locale, optional fallback_content_locales.
config/collections.php (locales / fallback_locales) is only the seed / fallback when settings have not been saved yet (defaults ['en', 'it']).
| Key | Role |
|---|---|
content_locales | Enabled BCP-47 (or language-only) codes for item data translations and field labels |
default_content_locale | Must be ∈ content_locales; used when no ?locale= / Accept-Language match |
fallback_content_locales | Ordered chain when a translation is missing |
Configure under Settings → Project → Content languages (searchable catalog + sortable list). Catalog codes/names/flags live in resources/data/content-locales-catalog.json (ContentLocaleCatalog). Disabling a locale does not delete existing translation rows in the DB (orphans stay until rewritten).
Shared to the frontend as Inertia props collectionLocales, collectionLocaleMeta, and defaultContentLocale (see Routing overview).
Admin UI language remains separate (config/i18n.php).
Mail and logging (brief)
| Area | Default in .env.example |
|---|---|
| Mailer | MAIL_MAILER=log (no SMTP required locally) |
| Log | LOG_CHANNEL=stack, LOG_LEVEL=debug |
Configure real SMTP (or another mailer) before relying on password-reset or verification email in non-local environments.
Checklist after changing config
- Update
.env(and secrets store in production). php artisan config:clearor rebuildconfig:cachein production.- If permissions/enums changed:
permissions:sync(+ seed roles if needed). - If content locales changed: smoke-test item forms and API
?locale=for each enabled locale. - Confirm
APP_URLmatches the public host (affects storage URLs and redirects).