- Status: Superseded
- Date: 2026-04-04
- Superseded By:
docs/adr/ADR-003-root-domain-structure.md
Course Manager is a Laravel application that has grown across multiple business areas including identity and access, course catalog, curriculum, enrollment, and tenancy.
Without an explicit structure decision, Laravel-default folders encourage feature code, tests, UI assets, and database artifacts to drift into framework-oriented locations. That makes domain ownership harder to see, increases the chance of generic shared buckets appearing, and weakens consistency across application layers.
We need a repository structure that:
- keeps Laravel as the framework shell
- makes domain ownership explicit first
- mirrors domain boundaries across backend code, tests, UI, and database artifacts
- allows framework composition concerns to exist without becoming a business-logic catch-all
All business code lives under domains/<Domain>/....
Current domains:
IdentityAccessCourseCatalogEnrollmentCurriculumTenancy
app/Foundation/... is the only non-domain location under app/.
It may contain framework composition concerns such as:
- service providers
- route registrars
- view registrars
Business logic does not belong in app/Foundation.
The repository mirrors domain boundaries outside app/:
- tests live under
tests/Domain/<Domain>/... - UI lives under
resources/domains/<domain>/... - factories live under
database/factories/<Domain>/... - seeders live under
database/seeders/<Domain>/... - migrations live under
database/migrations/<Domain>/...
Foundation-owned composition artifacts may also live in mirrored Foundation folders where Laravel needs them:
tests/Domain/Foundation/...domains/Foundation/resources/...database/*/Foundation/...
Laravel-required entrypoints may remain as thin framework wrappers when necessary, for example database/seeders/DatabaseSeeder.php.
routes/web.php remains composition-only.
Domain route definitions live in domains/<Domain>/Routes/web.php and are composed from the framework shell.
Names must reflect domain ownership consistently:
- PHP namespaces mirror the filesystem, for example
App\Domain\CourseCatalog\Http\Controllers\... - views use namespaced references such as
course-catalog::admin.courses.index - Blade components use namespaced tags such as
<x-course-catalog::app-layout> - route names are domain-qualified such as
identity-access.auth.loginandtenancy.admin.org-nodes.index
The repository does not use Shared or similar catch-all domains.
Generic business folders outside domains/* are forbidden. Generic UI component folders outside domain folders are forbidden. When presentation primitives are needed in more than one domain, duplication is preferred over introducing vague cross-domain abstractions.
- Domain ownership is visible across code, tests, UI, and persistence.
- Laravel composition remains isolated from business logic.
- Structural drift is easier to detect and test.
- New features have a clear placement rule.
- Some framework-owned files still require thin root entrypoints or registration layers.
- Reuse by duplication can increase maintenance overhead for UI primitives.
- Engineers must make an explicit domain decision before adding new files.
- Laravel-default framework-first layout
- Rejected: hides business boundaries and encourages generic shared folders.
- Shared or common cross-domain buckets
- Rejected: weakens ownership and becomes a dumping ground for unrelated concepts.
- Pure domain folders with no Foundation exception
- Rejected: Laravel still benefits from a small framework-composition layer.