# Architecture Decision: Layer-Based vs Module-Based Organization **Decision Date**: 2025-01-28 **Status**: Recommended **Deciders**: Development Team **Related Documents**: - `SRC-ARCHITECTURE-ANALYSIS.md` - Current architecture analysis - `DOCUMENTATION-ANALYSIS.md` - Documentation structure analysis --- ## Executive Summary **Decision**: Maintain 4-layer Clean Architecture with enhanced modular organization within each layer (Hybrid Approach) **Rationale**: - Framework layer constitutes 85.3% of codebase (3,883 files) - Pure module-based approach would duplicate this massive framework across modules - Hybrid approach provides modular benefits while preserving shared framework infrastructure - Estimated effort: 2-3 months (vs 6-12 months for pure module approach) **Impact**: - ✅ Maintains Clean Architecture compliance - ✅ Achieves Domain-Driven Design benefits - ✅ Avoids massive code duplication - ✅ Minimizes refactoring effort - ✅ Preserves existing framework investments --- ## Context & Problem Statement ### Current Architecture State **Analyzed Structure** (from `SRC-ARCHITECTURE-ANALYSIS.md`): ``` Total Files: 4,551 PHP files Total Directories: 1,052 Layer Distribution: ├── Framework: 3,883 files (85.3%) - TOO LARGE ├── Application: 420 files (9.2%) - Below target ├── Domain: 184 files (4.0%) - TOO THIN └── Infrastructure: 64 files (1.5%) - Below target ``` **Current Grade**: C+ (75%) - "Good foundation with critical architectural flaws" ### Identified Problems **3 Critical Architectural Violations**: 1. **HTTP Layer in Domain** (`src/Domain/Meta/Http/`) - Controllers with `#[Route]` attributes in Domain layer - 406 lines of HTTP-specific code misplaced 2. **DI Container Setup in Domain** (5 domains affected) - Framework-specific dependency injection in Domain - Violates Dependency Rule (Domain depends on Framework) 3. **Infrastructure Nested in Application** (`src/Application/Website/Infrastructure/GeoIp/`) - Wrong dependency direction - Confusing architecture ### Strategic Question **"Should we maintain 4-layer architecture or switch to pure module-based organization?"** This decision has fundamental implications: - Code organization strategy - Framework reusability - Refactoring effort (months vs years) - Team cognitive load - Maintainability long-term --- ## Decision Drivers ### Key Factors Influencing Decision 1. **Framework Size**: 85.3% of codebase is framework infrastructure 2. **Code Duplication Risk**: Pure modules would replicate framework per module 3. **Clean Architecture Benefits**: Dependency inversion, testability, maintainability 4. **Domain-Driven Design Goals**: Bounded contexts, domain focus 5. **Refactoring Effort**: Time and risk considerations 6. **Team Familiarity**: Existing knowledge of current structure 7. **Framework Reusability**: Shared infrastructure across all modules ### Stakeholder Concerns - **Development Team**: Minimize disruption, preserve framework investments - **Architecture**: Maintain Clean Architecture principles - **Business**: Minimize refactoring time, maintain velocity - **Quality**: Improve testability, reduce coupling --- ## Considered Options ### Option 1: Pure Module-Based (Vertical Slicing) **Structure**: ``` src/ ├── User/ # Self-contained module │ ├── Domain/ │ ├── Application/ │ ├── Infrastructure/ │ └── Framework/ # Duplicated framework code! ├── Order/ # Self-contained module │ ├── Domain/ │ ├── Application/ │ ├── Infrastructure/ │ └── Framework/ # Duplicated framework code! └── Product/ # Self-contained module ├── Domain/ ├── Application/ ├── Infrastructure/ └── Framework/ # Duplicated framework code! ``` **Advantages**: - ✅ True bounded contexts - modules are completely independent - ✅ Team autonomy - each module owned by dedicated team - ✅ Deploy modules independently (microservices-ready) - ✅ Pure Domain-Driven Design implementation - ✅ No cross-module dependencies **Disadvantages**: - ❌ **CRITICAL**: Framework duplication (85.3% × modules = massive overhead) - ❌ Framework updates must propagate to ALL modules - ❌ Code duplication: HTTP layer, Database, Cache, Queue, Events - ❌ Increased maintenance burden (N frameworks to update) - ❌ Inconsistency risk across modules - ❌ Massive refactoring effort (6-12 months) - ❌ Loss of framework investment (3,883 files built over time) **Estimated Effort**: 6-12 months **Risk Level**: HIGH --- ### Option 2: Hybrid Approach (Layers + Modules) **Recommended Structure**: ``` src/ ├── Domain/ (20-30% - business logic) │ ├── User/ (Module - bounded context) │ │ ├── Entity/ │ │ ├── ValueObject/ │ │ ├── Event/ │ │ ├── Repository/ (Interfaces only!) │ │ └── Service/ │ ├── Order/ (Module - bounded context) │ │ ├── Entity/ │ │ ├── ValueObject/ │ │ ├── Event/ │ │ ├── Repository/ │ │ └── Service/ │ └── Product/ (Module - bounded context) │ ├── Application/ (25-35% - use cases) │ ├── User/ (Module - aligned with domain) │ │ ├── Controller/ │ │ ├── Command/ │ │ └── Query/ │ ├── Order/ (Module - aligned with domain) │ │ ├── Controller/ │ │ ├── Command/ │ │ └── Query/ │ └── Admin/ (Feature module - cross-cutting) │ ├── Analytics/ │ ├── Content/ │ └── System/ │ ├── Framework/ (40-50% - SHARED infrastructure) │ ├── Core/ # Shared by ALL modules │ ├── Database/ # Shared by ALL modules │ ├── Http/ # Shared by ALL modules │ ├── Cache/ # Shared by ALL modules │ ├── Queue/ # Shared by ALL modules │ ├── Events/ # Shared by ALL modules │ └── [32 more shared components] │ └── Infrastructure/ (5-10% - external integrations) └── ServiceProviders/ # Module-specific DI setup ├── UserServiceProvider.php ├── OrderServiceProvider.php └── ProductServiceProvider.php ``` **Advantages**: - ✅ Clean Architecture compliance maintained - ✅ **Framework shared across all modules** (no duplication!) - ✅ Modular organization where beneficial (Domain, Application) - ✅ Domain-Driven Design benefits (bounded contexts) - ✅ Reduced refactoring effort (2-3 months) - ✅ Framework investment preserved - ✅ Single framework to maintain and update - ✅ Consistency across modules (shared patterns) - ✅ Testability (clear boundaries, mocking framework components) **Disadvantages**: - ⚠️ Framework is shared dependency (not pure bounded contexts) - ⚠️ Module deployment still coupled via framework - ⚠️ Requires discipline to avoid cross-domain dependencies **Estimated Effort**: 2-3 months **Risk Level**: LOW-MEDIUM --- ### Option 3: Keep Current Structure (Do Nothing) **Structure**: Current 4-layer architecture without modular organization **Advantages**: - ✅ Zero refactoring effort - ✅ No disruption to development **Disadvantages**: - ❌ Architectural violations remain (HTTP in Domain, DI in Domain) - ❌ Poor domain organization (Domain layer too thin at 4%) - ❌ Framework bloat (85.3% - too large) - ❌ Technical debt accumulation - ❌ Reduced maintainability over time **Estimated Effort**: 0 months (no change) **Risk Level**: HIGH (accumulating technical debt) --- ## Decision Outcome ### Chosen Option: **Option 2 - Hybrid Approach (Layers + Modules)** **Rationale**: 1. **Framework Reusability**: 85.3% of codebase is framework infrastructure that SHOULD be shared - Database layer (387 files) - shared across all modules - HTTP layer (156 files) - shared routing, middleware - Queue system (89 files) - shared background processing - Cache layer (67 files) - shared caching infrastructure - 40 more framework components - all reusable 2. **Clean Architecture Preserved**: Maintains dependency rule while adding modularity - Domain depends on nothing - Application depends on Domain - Framework provides infrastructure - Infrastructure implements interfaces 3. **Domain-Driven Design Benefits**: Modules represent bounded contexts - `Domain/User/` - user bounded context - `Domain/Order/` - order bounded context - `Domain/Product/` - product bounded context - Clear boundaries, no cross-domain dependencies 4. **Realistic Refactoring Timeline**: 2-3 months vs 6-12 months - Phase 1: Priority 1 Fixes (2-3 days) - Phase 2: Domain Layer Modularization (1-2 weeks) - Phase 3: Application Layer Modularization (1-2 weeks) - Phase 4: Infrastructure Consolidation (1-2 weeks) 5. **Risk Mitigation**: Incremental changes, testable at each phase --- ## Implementation Strategy ### Phase 1: Priority 1 Fixes (2-3 days) - CRITICAL **Objective**: Fix architectural violations **Tasks**: 1. **Move HTTP out of Domain** ```bash # Before: src/Domain/Meta/Http/Controller/MetaAdminController.php # After: src/Application/Admin/Controllers/Meta/MetaAdminController.php mv src/Domain/Meta/Http/Controller/ src/Application/Admin/Controllers/Meta/ mv src/Domain/Meta/Http/Middleware/ src/Framework/Http/Middlewares/ ``` 2. **Move DI to Infrastructure** ```bash mkdir -p src/Infrastructure/ServiceProviders # Transform Initializers to ServiceProviders mv src/Domain/Asset/DI/AssetServiceInitializer.php \ src/Infrastructure/ServiceProviders/AssetServiceProvider.php mv src/Domain/Cms/DI/CmsServiceInitializer.php \ src/Infrastructure/ServiceProviders/CmsServiceProvider.php # Repeat for User, Order, Console domains ``` 3. **Fix Infrastructure Nesting** ```bash mv src/Application/Website/Infrastructure/GeoIp/ \ src/Infrastructure/GeoIp/ ``` 4. **Update Namespaces and Imports** - Run PSR-4 compliance check - Update all references to moved files - Test all affected functionality **Success Criteria**: - ✅ Zero architectural violations - ✅ All tests pass - ✅ PSR-4 compliance: 100% **Code Example - ServiceProvider Transformation**: ```php // Before: src/Domain/Asset/DI/AssetServiceInitializer.php namespace App\Domain\Asset\DI; use App\Framework\DI\Container; use App\Framework\DI\Initializer; final readonly class AssetServiceInitializer { #[Initializer] public function __invoke(Container $container): void { $container->singleton(AssetRepository::class, ...); $container->singleton(AssetService::class, ...); } } // After: src/Infrastructure/ServiceProviders/AssetServiceProvider.php namespace App\Infrastructure\ServiceProviders; use App\Framework\DI\Container; use App\Framework\DI\ServiceProvider; final readonly class AssetServiceProvider implements ServiceProvider { public function register(Container $container): void { $container->singleton(AssetRepository::class, ...); $container->singleton(AssetService::class, ...); } } ``` --- ### Phase 2: Domain Layer Modularization (1-2 weeks) **Objective**: Organize Domain layer by bounded contexts **Current State**: ``` src/Domain/ ├── User/ (23 files) - mixed structure ├── Asset/ (18 files) - mixed structure ├── Cms/ (15 files) - mixed structure ├── Order/ (29 files) - mixed structure └── Product/ (12 files) - mixed structure ``` **Target State**: ``` src/Domain/ ├── User/ # User bounded context │ ├── Entity/ │ │ └── User.php │ ├── ValueObject/ │ │ ├── UserId.php │ │ ├── Email.php │ │ └── UserName.php │ ├── Event/ │ │ ├── UserRegisteredEvent.php │ │ └── UserUpdatedEvent.php │ ├── Repository/ │ │ └── UserRepositoryInterface.php # Interface only! │ └── Service/ │ └── UserService.php │ ├── Order/ # Order bounded context │ ├── Entity/ │ │ ├── Order.php │ │ └── OrderItem.php │ ├── ValueObject/ │ │ ├── OrderId.php │ │ ├── OrderStatus.php │ │ └── Money.php │ ├── Event/ │ │ ├── OrderCreatedEvent.php │ │ └── OrderCompletedEvent.php │ ├── Repository/ │ │ └── OrderRepositoryInterface.php │ └── Service/ │ └── OrderService.php │ └── Product/ # Product bounded context ├── Entity/ ├── ValueObject/ ├── Event/ ├── Repository/ └── Service/ ``` **Benefits**: - Clear bounded contexts - Self-documenting structure - Easy to locate domain logic - No cross-domain dependencies - Repository interfaces (implementations in Infrastructure) --- ### Phase 3: Application Layer Modularization (1-2 weeks) **Objective**: Align Application layer with Domain modules **Current State**: ``` src/Application/ ├── Website/ (89 files) - feature-based ├── Admin/ (234 files) - feature-based ├── Api/ (67 files) - feature-based ├── Contact/ (8 files) - feature-based └── Console/ (22 files) - feature-based ``` **Target State**: ``` src/Application/ ├── User/ # Aligned with Domain/User │ ├── Controller/ │ │ └── UserController.php │ ├── Command/ │ │ ├── CreateUserCommand.php │ │ └── CreateUserHandler.php │ └── Query/ │ ├── GetUserQuery.php │ └── GetUserHandler.php │ ├── Order/ # Aligned with Domain/Order │ ├── Controller/ │ ├── Command/ │ └── Query/ │ ├── Product/ # Aligned with Domain/Product │ ├── Controller/ │ ├── Command/ │ └── Query/ │ └── Admin/ # Cross-cutting feature module ├── Analytics/ ├── Content/ ├── Infrastructure/ ├── Notifications/ └── System/ ``` **Benefits**: - Clear mapping: Application/User → Domain/User - CQRS patterns (Command/Query separation) - Feature-based organization where appropriate (Admin) - Reduced cognitive load --- ### Phase 4: Infrastructure Consolidation (1-2 weeks) **Objective**: Centralize infrastructure implementations **Target State**: ``` src/Infrastructure/ ├── ServiceProviders/ # DI setup per module │ ├── UserServiceProvider.php │ ├── OrderServiceProvider.php │ └── ProductServiceProvider.php │ ├── Persistence/ # Database implementations │ ├── User/ │ │ └── DatabaseUserRepository.php # Implements Domain/User/Repository/UserRepositoryInterface │ ├── Order/ │ │ └── DatabaseOrderRepository.php │ └── Product/ │ └── DatabaseProductRepository.php │ ├── GeoIp/ # External service integrations │ ├── GeoIpService.php │ └── MaxMindProvider.php │ └── Email/ # External service integrations ├── EmailService.php └── SmtpProvider.php ``` **Benefits**: - Infrastructure implementations separated from Domain interfaces - Clear dependency inversion (Domain → Interface ← Infrastructure) - Easy to swap implementations (testing, different databases) - ServiceProviders wire up dependencies --- ## Consequences ### Positive Consequences 1. **Clean Architecture Compliance** - All layers respect Dependency Rule - Domain layer pure (no framework dependencies) - Testability improved (mock infrastructure easily) 2. **Domain-Driven Design Benefits** - Clear bounded contexts (User, Order, Product) - Domain logic focused and cohesive - Business rules visible and maintainable 3. **Framework Preservation** - No code duplication (Framework shared) - Single framework to maintain - Consistency across all modules - Framework investment preserved (3,883 files) 4. **Maintainability** - Clear structure reduces cognitive load - Easy to locate code (Domain/User/Entity/User.php) - Self-documenting architecture - Onboarding new developers easier 5. **Realistic Timeline** - 2-3 months total effort - Incremental changes (low risk) - Testable at each phase ### Negative Consequences (Mitigated) 1. **Framework is Shared Dependency** - **Mitigation**: Framework is stable, well-tested infrastructure - **Trade-off**: Accepting this trade-off for massive code reuse benefit 2. **Module Deployment Coupling** - **Mitigation**: Not pursuing microservices architecture (monolith is appropriate) - **Trade-off**: Deployment simplicity vs independent module deployment 3. **Discipline Required** - **Mitigation**: Code review process, automated PSR-4 checks, architectural tests - **Trade-off**: Team training vs long-term maintainability --- ## Comparison Matrix | Aspect | Pure Modules | Hybrid (Recommended) | Keep Current | |--------|-------------|---------------------|--------------| | **Clean Architecture** | ✅ Yes | ✅ Yes | ❌ Violations exist | | **DDD Bounded Contexts** | ✅ Pure | ✅ Practical | ❌ Weak | | **Framework Duplication** | ❌ Massive (85.3% × N) | ✅ None (shared) | ✅ None | | **Code Reuse** | ❌ Low (per-module) | ✅ High (shared) | ✅ High | | **Refactoring Effort** | ❌ 6-12 months | ✅ 2-3 months | ✅ 0 months | | **Risk Level** | ❌ HIGH | ✅ LOW-MEDIUM | ❌ HIGH (debt) | | **Team Autonomy** | ✅ Full (per module) | ⚠️ Partial | ❌ None | | **Deploy Independence** | ✅ Yes (microservices) | ❌ No (monolith) | ❌ No | | **Maintenance Burden** | ❌ High (N frameworks) | ✅ Low (1 framework) | ⚠️ Medium | | **Architectural Quality** | ✅ A+ (pure DDD) | ✅ A (pragmatic) | ❌ C+ (violations) | **Scoring**: - Pure Modules: 5/10 (ideal theory, impractical for this project) - **Hybrid: 9/10 (recommended - pragmatic and effective)** - Keep Current: 3/10 (accumulating technical debt) --- ## Migration Risks & Mitigation ### Risk 1: Breaking Changes During Refactoring **Probability**: MEDIUM **Impact**: HIGH **Mitigation**: - Comprehensive test suite BEFORE starting - Feature flags for gradual rollout - Incremental changes with continuous testing - Rollback plan for each phase ### Risk 2: Team Resistance to Change **Probability**: LOW **Impact**: MEDIUM **Mitigation**: - Document rationale (this document) - Training sessions on new structure - Gradual transition (4 phases over 2-3 months) - Team involvement in decision-making ### Risk 3: Overlooked Dependencies **Probability**: MEDIUM **Impact**: MEDIUM **Mitigation**: - Automated dependency analysis - PSR-4 compliance checks - Static analysis tools (PHPStan) - Code review process for all moves ### Risk 4: Timeline Overrun **Probability**: LOW **Impact**: MEDIUM **Mitigation**: - Conservative time estimates (2-3 months) - Phase-based approach (can pause between phases) - Automated tooling for bulk operations - Dedicated refactoring time (not mixed with feature work) --- ## Success Metrics ### Phase 1 Completion (Priority 1 Fixes) - ✅ Zero architectural violations - ✅ All tests pass (100%) - ✅ PSR-4 compliance: 100% - ✅ No HTTP code in Domain layer - ✅ No DI code in Domain layer - ✅ Infrastructure at top level (not nested) ### Phase 2-4 Completion (Full Migration) - ✅ Domain layer: 15-20% of codebase (from 4%) - ✅ Framework layer: 40-50% of codebase (from 85.3%) - ✅ Clear bounded contexts in Domain layer - ✅ Application layer aligned with Domain modules - ✅ Infrastructure ServiceProviders per module - ✅ Overall Architecture Grade: A- (90%) (from C+ 75%) ### Long-Term Success - ✅ Reduced time to locate code (faster development) - ✅ Easier onboarding (clear structure) - ✅ Fewer architectural violations (ongoing) - ✅ Higher test coverage (better boundaries) - ✅ Improved maintainability (team feedback) --- ## Code Examples ### Example 1: Domain Module (User Bounded Context) **Before Migration**: ``` src/Domain/User/ ├── User.php # Mixed: Entity + logic ├── UserRepository.php # Confusion: Interface or implementation? ├── UserService.php # Service └── DI/ └── UserServiceInitializer.php # WRONG: DI in Domain! ``` **After Migration**: ``` src/Domain/User/ ├── Entity/ │ └── User.php # Pure entity ├── ValueObject/ │ ├── UserId.php # Type-safe ID │ ├── Email.php # Validated email │ └── UserName.php # Validated name ├── Event/ │ └── UserRegisteredEvent.php # Domain event ├── Repository/ │ └── UserRepositoryInterface.php # Interface only! └── Service/ └── UserService.php # Domain service ``` **Domain Entity** (Pure business logic): ```php // src/Domain/User/Entity/User.php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\{UserId, Email, UserName}; use App\Domain\User\Event\UserRegisteredEvent; final readonly class User { public function __construct( public UserId $id, public Email $email, public UserName $name, public bool $active = true ) {} public static function register(Email $email, UserName $name): self { $user = new self( id: UserId::generate(), email: $email, name: $name ); // Domain event - no framework dependency! DomainEvents::raise(new UserRegisteredEvent($user)); return $user; } public function deactivate(): self { return new self( id: $this->id, email: $this->email, name: $this->name, active: false ); } } ``` **Repository Interface** (Domain layer): ```php // src/Domain/User/Repository/UserRepositoryInterface.php namespace App\Domain\User\Repository; use App\Domain\User\Entity\User; use App\Domain\User\ValueObject\{UserId, Email}; interface UserRepositoryInterface { public function find(UserId $id): ?User; public function findByEmail(Email $email): ?User; public function save(User $user): void; public function delete(User $user): void; } ``` **Repository Implementation** (Infrastructure layer): ```php // src/Infrastructure/Persistence/User/DatabaseUserRepository.php namespace App\Infrastructure\Persistence\User; use App\Domain\User\Repository\UserRepositoryInterface; use App\Domain\User\Entity\User; use App\Framework\Database\EntityManager; final readonly class DatabaseUserRepository implements UserRepositoryInterface { public function __construct( private EntityManager $entityManager ) {} public function find(UserId $id): ?User { return $this->entityManager->find(User::class, $id->value); } public function save(User $user): void { $this->entityManager->save($user); } } ``` **ServiceProvider** (Infrastructure layer - wires dependencies): ```php // src/Infrastructure/ServiceProviders/UserServiceProvider.php namespace App\Infrastructure\ServiceProviders; use App\Framework\DI\Container; use App\Domain\User\Repository\UserRepositoryInterface; use App\Infrastructure\Persistence\User\DatabaseUserRepository; final readonly class UserServiceProvider { public function register(Container $container): void { // Wire Domain interface → Infrastructure implementation $container->singleton( UserRepositoryInterface::class, fn() => new DatabaseUserRepository( $container->get(EntityManager::class) ) ); } } ``` --- ### Example 2: Application Layer (CQRS Pattern) **Structure**: ``` src/Application/User/ ├── Controller/ │ └── UserController.php ├── Command/ # Write operations │ ├── CreateUserCommand.php │ └── CreateUserHandler.php └── Query/ # Read operations ├── GetUserQuery.php └── GetUserHandler.php ``` **Controller** (Thin - delegates to Command/Query handlers): ```php // src/Application/User/Controller/UserController.php namespace App\Application\User\Controller; use App\Framework\Attributes\Route; use App\Framework\Http\{Method, JsonResult, Status}; use App\Application\User\Command\{CreateUserCommand, CreateUserHandler}; use App\Application\User\Query\{GetUserQuery, GetUserHandler}; final readonly class UserController { public function __construct( private CreateUserHandler $createHandler, private GetUserHandler $getHandler ) {} #[Route(path: '/api/users', method: Method::POST)] public function create(CreateUserRequest $request): JsonResult { $command = new CreateUserCommand( $request->email, $request->name ); $user = $this->createHandler->handle($command); return new JsonResult( ['id' => $user->id->value], status: Status::CREATED ); } #[Route(path: '/api/users/{id}', method: Method::GET)] public function get(string $id): JsonResult { $query = new GetUserQuery(new UserId($id)); $user = $this->getHandler->handle($query); return new JsonResult($user->toArray()); } } ``` **Command Handler** (Business logic): ```php // src/Application/User/Command/CreateUserHandler.php namespace App\Application\User\Command; use App\Domain\User\Entity\User; use App\Domain\User\Repository\UserRepositoryInterface; final readonly class CreateUserHandler { public function __construct( private UserRepositoryInterface $repository ) {} public function handle(CreateUserCommand $command): User { // Domain logic $user = User::register($command->email, $command->name); // Persistence via Domain interface $this->repository->save($user); return $user; } } ``` --- ## Alternative Approaches Considered ### Alternative 1: Microservices Architecture **Why Rejected**: - Premature optimization for current scale - Operational complexity (deployment, monitoring, debugging) - Network latency overhead - Distributed transaction challenges - Team not structured for microservices (no dedicated platform team) ### Alternative 2: Event Sourcing + CQRS (Full) **Why Rejected**: - Significant complexity increase - Learning curve for team - Infrastructure requirements (event store) - Eventual consistency challenges - Overkill for current business requirements ### Alternative 3: Module-per-Repository (Monorepo) **Why Rejected**: - Still duplicates Framework code per repository - Tooling complexity (cross-repo dependencies) - Versioning challenges - Overhead not justified for current team size --- ## Related Decisions - **ADR-001**: Use Custom PHP Framework (already decided) - **ADR-002**: Adopt Clean Architecture principles (already decided) - **ADR-003**: Use Composition over Inheritance (already decided) - **ADR-004**: Value Objects over Primitives (already decided) - **ADR-005**: Attribute-based Discovery (already decided) **This Decision**: **ADR-006 - Hybrid Layer-Module Architecture** --- ## References ### Internal Documents - `docs/SRC-ARCHITECTURE-ANALYSIS.md` - Current architecture analysis - `docs/DOCUMENTATION-ANALYSIS.md` - Documentation structure - `docs/claude/architecture.md` - Framework architecture guide - `docs/claude/guidelines.md` - Development guidelines ### Clean Architecture - "Clean Architecture" by Robert C. Martin - Dependency Rule: Dependencies point inward (Domain → Application → Framework) - Testability: Inner layers testable without outer layers ### Domain-Driven Design - "Domain-Driven Design" by Eric Evans - Bounded Contexts: Clear boundaries between domains - Ubiquitous Language: Domain-specific terminology - Aggregates: Consistency boundaries ### Framework Patterns - Martin Fowler's Enterprise Application Patterns - Repository Pattern: Data access abstraction - CQRS: Command-Query Responsibility Segregation - Event-Driven Architecture: Loose coupling via events --- ## Timeline & Next Steps ### Immediate Next Steps (Week 1) **Day 1-2**: Phase 1 - Priority 1 Fixes - Move HTTP out of Domain (2 hours) - Move DI to Infrastructure (4 hours) - Fix Infrastructure nesting (1 hour) - Update namespaces (3 hours) - **Total**: 10 hours **Day 3**: Testing & Validation - Run full test suite - PSR-4 compliance check - Architectural violation check - **Total**: 4 hours ### Short-Term (Weeks 2-4): Phase 2 - Domain Modularization - Organize User domain (1 week) - Organize Order domain (1 week) - Organize Product, Asset, Cms domains (1 week) ### Mid-Term (Weeks 5-8): Phase 3 - Application Modularization - Restructure User application layer (1 week) - Restructure Order application layer (1 week) - Restructure Admin feature module (2 weeks) ### Long-Term (Weeks 9-12): Phase 4 - Infrastructure Consolidation - Create ServiceProviders (1 week) - Organize Persistence layer (1 week) - Migrate external service integrations (1 week) - Final testing & documentation (1 week) **Total Timeline**: 12 weeks (3 months) - conservative estimate --- ## Approval & Sign-Off **Decision Maker**: Development Team Lead **Date**: 2025-01-28 **Status**: Recommended for Approval **Review Required By**: - [ ] Technical Architect - [ ] Development Team - [ ] Product Owner - [ ] CTO **Implementation Start**: After approval **Estimated Completion**: 3 months from start --- ## Appendix A: Framework Layer Breakdown **Why Framework Must Be Shared** (3,883 files - 85.3%): ``` src/Framework/ ├── Core/ (245 files) - Application bootstrap, routing, DI ├── Database/ (387 files) - EntityManager, Schema Builder, Migrations ├── Http/ (156 files) - Request/Response, Middleware, Routing ├── Queue/ (89 files) - Job processing, Workers, Queue drivers ├── Cache/ (67 files) - Cache abstraction, Drivers (Redis, File) ├── ExceptionHandling/ (124 files) - Error handling, Exception types ├── Discovery/ (78 files) - Attribute discovery, Convention scanning ├── View/ (201 files) - Template engine, Components ├── Events/ (95 files) - Event dispatcher, Domain events ├── Console/ (167 files) - CLI commands, TUI components ├── Validation/ (54 files) - Input validation, Rules ├── Security/ (89 files) - Authentication, Authorization, WAF ├── Logging/ (48 files) - Logger, Handlers ├── MCP/ (123 files) - Model Context Protocol (AI integration) └── [28 more components] (1,960 files) Total: 3,883 files ``` **Duplication Impact**: If pure module approach chosen, each module would duplicate most of these 3,883 files, resulting in: - 5 modules × 3,883 files = **19,415 files** (vs current 3,883) - Maintenance nightmare: Update framework → update 5 copies - Consistency issues: Framework versions drift across modules - Lost investment: Years of framework development duplicated **Conclusion**: Framework MUST be shared infrastructure, not duplicated per module. --- ## Appendix B: PSR-4 Mapping **After Migration**: ```json { "autoload": { "psr-4": { "App\\Domain\\": "src/Domain/", "App\\Application\\": "src/Application/", "App\\Framework\\": "src/Framework/", "App\\Infrastructure\\": "src/Infrastructure/" } } } ``` **Example Mappings**: ``` Namespace → File App\Domain\User\Entity\User → src/Domain/User/Entity/User.php App\Domain\User\Repository\UserRepositoryInterface → src/Domain/User/Repository/UserRepositoryInterface.php App\Application\User\Command\CreateUserCommand → src/Application/User/Command/CreateUserCommand.php App\Infrastructure\Persistence\User\DatabaseUserRepository → src/Infrastructure/Persistence/User/DatabaseUserRepository.php App\Framework\Database\EntityManager → src/Framework/Database/EntityManager.php ``` **Validation**: ```bash # Verify PSR-4 compliance composer dump-autoload --optimize composer validate --strict # Check for PSR-4 violations ./vendor/bin/phpstan analyze --level=8 ``` --- **End of Document** **Version**: 1.0 **Last Updated**: 2025-01-28 **Authors**: Architecture Team **Reviewers**: Development Team