Migrations
Each module owns the tables that persist its Domain. Migrations typically live with the module’s persistence adapter:
Ordering/Infrastructure/Persistence/Eloquent/Migrations/
Load them from the module ServiceProvider (path may vary by host convention).
Guidelines
| Practice | Rationale |
|---|---|
| Colocate migrations with the owning module | Bounded context owns its data |
| Avoid cross-module foreign keys for business joins | Prevents hidden coupling through the schema |
| Read peer data via ACL / Events | Matches Core replaceability |
| Factories beside Eloquent models | Test data stays in Infrastructure |
| Name tables with a clear module prefix when helpful | Reduces collisions in large hosts |
Ownership checklist
Before adding a column or FK:
- Which module’s Domain Entity owns this fact?
- If another module needs it now → ACL, not a cross-module Eloquent relation in Application.
- If another module reacts later → Domain Event with a rich payload.
- If you are tempted to “join everything in one query for Filament” → prefer a read model / ACL query port still owned by the consumer’s Infrastructure.
Loading migrations (illustrative)
// OrderingServiceProvider::boot
$this->loadMigrationsFrom(
__DIR__ . '/../../Infrastructure/Persistence/Eloquent/Migrations'
);
Anti-patterns
| Anti-pattern | Fix |
|---|---|
| Shared “god” migrations folder with every module’s tables unlabeled | Colocate per module |
| FK from Ordering into Warehouse tables for convenience joins | ACL / Events; duplicate identifiers as values if needed |
| Business enums encoded only as DB check constraints with no Domain Enum | Domain Enum + mapping in Repository |
Schema design is a host concern; ownership and coupling are Core concerns.
Core reference: Ports & persistence · Cross-module ACL.