Skip to main content

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).

ModuleHouses
FoundationShared kernel: base Http\Controllers\Controller, VerifyTurnstile, Password/Profile validation Concerns, and the app-wide defaults (Carbon immutable, Password::defaults, prohibitDestructiveCommands) in FoundationServiceProvider.
TenancyTenant + factory, TenancyServiceProvider (events, RLS scopeByDefault, middleware priority — no route mapping), the tenant.member guard. Depended on by others.
IdentityUser + ClientUser (+ factories), Fortify backend (actions + rate limiters), Sanctum client-auth controllers, and the auth + email-first-discovery routes (routes/identity-routes.php).
BackofficeOperator 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).


← Decision log index