Clean Architecture plan for GridPilot (NestJS-focused) This document defines the target architecture and rules for GridPilot. It is written as a developer-facing contract: what goes where, what is allowed, and what is forbidden. ⸻ 1. Architectural goals • Strict Clean Architecture (dependency rule enforced) • Domain-first design (DDD-inspired) • Frameworks are delivery mechanisms, not architecture • Business logic is isolated from persistence, UI, and infrastructure • Explicit composition roots • High testability without mocking the domain ⸻ 2. High-level structure /apps /api # NestJS API (delivery mechanism) /website # Next.js website (delivery mechanism) /electron # Electron app (delivery mechanism) /core # Business rules (framework-agnostic) /analytics /automation /identity /media /notifications /racing /social /shared /adapters # Technical implementations (details) /persistence /typeorm /inmemory /auth /media /notifications /logging /testing # Test-only code (never shipped) /contexts /factories /builders /fakes /fixtures ⸻ 3. Dependency rule (non-negotiable) Dependencies must only point inward: apps → adapters → core Forbidden: • core importing from adapters • core importing from apps • domain entities importing ORM, NestJS, or framework code ⸻ 4. Core rules The Core contains only business rules. Core MAY contain: • Domain entities • Value objects • Domain services • Domain events • Repository interfaces • Application use cases • Application-level ports Core MUST NOT contain: • ORM entities • Persistence implementations • In-memory repositories • NestJS decorators • TypeORM decorators • HTTP / GraphQL / IPC concerns • Faker, demo data, seeds ⸻ 5. Domain entities Domain entities: • Represent business concepts • Enforce invariants • Contain behavior • Are immutable or controlled via methods Example characteristics: • Private constructors • Static factory methods • Explicit validation • Value objects for identity Domain entities must never: • Be decorated with @Entity, @Column, etc. • Be reused as persistence models • Know how they are stored ⸻ 6. Persistence entities (ORM) Persistence entities live in adapters and are data-only. /adapters/persistence/typeorm/ - PageViewOrmEntity.ts Rules: • No business logic • No validation • No behavior • Flat data structures ORM entities are not domain entities. ⸻ 7. Mapping (anti-corruption layer) Mapping between domain and persistence is explicit and isolated. /adapters/persistence/typeorm/ - PageViewMapper.ts Rules: • Domain ↔ ORM mapping only happens in adapters • Mappers are pure functions • Boilerplate is acceptable and expected ⸻ 8. Repositories Core /core//domain/repositories - IPageViewRepository.ts Only interfaces. Adapters /adapters/persistence/typeorm/ - PageViewTypeOrmRepository.ts /adapters/persistence/inmemory/ - InMemoryPageViewRepository.ts Rules: • Repositories translate between domain entities and storage models • Repositories implement core interfaces • Repositories hide all persistence details from the core ⸻ 9. In-memory repositories In-memory repositories are test adapters, not core infrastructure. Rules: • Never placed in /core • Allowed only in /adapters/persistence/inmemory • Used for unit tests and integration tests • Must behave like real repositories ⸻ 10. NestJS API (/apps/api) The NestJS API is a delivery mechanism. Responsibilities: • Controllers • DTOs • Request validation • Dependency injection • Adapter selection (prod vs test) Forbidden: • Business logic • Domain rules • Persistence logic NestJS modules are composition roots. ⸻ 11. Dependency injection DI is configured only in apps. Example: provide: IPageViewRepository useClass: PageViewTypeOrmRepository Switching implementations (e.g. InMemory vs TypeORM) happens outside the core. ⸻ 12. Testing strategy Domain tests • Test entities and value objects directly • No adapters • No frameworks Use case tests • Core + in-memory adapters • No NestJS API tests • NestJS TestingModule • Explicit adapter overrides ⸻ 13. Testing helpers Testing helpers live in /testing. Contexts • One context per bounded context • Provide repositories + use cases Factories • Create valid domain objects • Express intent, not randomness Builders • Build complex aggregates fluently Fakes • Replace external systems (payments, email, etc.) ⸻ 14. Read models and projections Not every query needs a domain entity. Rules: • Reports, analytics, dashboards may use DTOs or projections • No forced mapping into domain entities • Domain entities are for behavior, not reporting ⸻ 15. Golden rules • Domain entities never depend on infrastructure • ORM entities never contain behavior • Repositories are anti-corruption layers • Adapters are replaceable • Apps wire everything together • Tests never leak into production code ⸻ 16. Summary This architecture ensures: • Long-term maintainability • Framework independence • Safe refactoring • Clear ownership of responsibilities If a class violates a rule, it is in the wrong layer.