D19 — Modular monolith: code lives in modules, App\ is empty (RESOLVED)
Architecture decision record, relocated verbatim from the retired single-file
docs/tenancy/decision log. Status, thematic clusters, and how to record a new ADR: the decision log index.
Per "minimal App namespace + solid modular monolith from the start", all application code moved
out of App\ into app-modules/* (internachi/modular, Modules\ namespace). app/ is now
empty (just .gitkeep for the App\ autoload root); bootstrap/providers.php is empty
(module providers auto-register via package discovery); routes are owned by modules and
auto-loaded by modular's RoutesPlugin (root routes/ keeps only console.php); bootstrap
withRouting no longer loads web/api files (the web/api middleware groups remain framework
defaults).
| Module | Houses |
|---|---|
| Foundation | Shared kernel: base Http\Controllers\Controller, VerifyTurnstile, Password/Profile validation Concerns, and the app-wide defaults (Carbon immutable, Password::defaults, prohibitDestructiveCommands) in FoundationServiceProvider. |
| Tenancy | Tenant + factory, TenancyServiceProvider (events, RLS scopeByDefault, middleware priority — no route mapping), the tenant.member guard. Depended on by others. |
| Identity | User + ClientUser (+ factories), Fortify backend (actions + rate limiters), Sanctum client-auth controllers, and the auth + email-first-discovery routes (routes/identity-routes.php). |
| Backoffice | Operator app: Livewire settings components (registered by name; Blade views stay in resources/views), web/settings routes, Fortify view bindings, Horizon dashboard auth. |
Rationale/boundaries: shared/cross-cutting code → Foundation; Tenant lives in Tenancy and is
depended upon, not duplicated; Blade views + config/* stay global (not App\ code).
Migrations stay in central database/migrations for now (framework multi-table migrations);
new domain modules (Banking, …) will own their own. Verified: 58 tests green + live smoke
(/, /up, /api/v1/tenant-discovery).