2.2 KiB
2.2 KiB
ADR 0005: Strict Clean Architecture and Capability Modules
Context
Mastermind is a complex macOS application with multiple responsibilities: continuous capture, knowledge extraction, local graph management, and AI assistance. To ensure maintainability, testability, and clear ownership of privacy boundaries, we need a robust architectural structure.
Decision
We adopt a Strict Clean Architecture organized around Capability Modules.
1. Capability Modules
The codebase is divided into stable capability boundaries:
- AppShell: Orchestration, lifecycle, and composition root.
- Observation: Collectors and raw evidence acquisition.
- Knowledge: The Context Graph, projection, and retrieval logic.
- Assistant: AI sessions, provider routing, and prompt management.
- Trust: Activity logging, health monitoring, and privacy enforcement.
- Infrastructure: Shared utilities, encryption, and low-level storage.
2. Strict Clean Architecture
Each module follows Clean Architecture principles:
- Entities: Pure domain models and logic (inner-most).
- Use Cases/Services: Application-specific business rules.
- Interface Adapters: Controllers, presenters, and gatekeepers.
- Frameworks & Drivers: External tools like ScreenCaptureKit, SQLite, and sidecar clients (outer-most).
3. Compile-Time Dependency Rule
- Dependencies flow inwards: outer layers depend on inner layers.
- Modules communicate through Application Ports (protocols).
- Protocols are required at module boundaries and for all I/O (adapters).
- Internal module logic does not require protocols for every internal function or value type, avoiding unnecessary boilerplate.
4. Enforcement
- Boundaries are enforced by separate Swift targets/modules where possible.
- The Composition Root (in AppShell) is the only place where concrete adapters are instantiated and injected.
Consequences
- Pros: Clearer boundaries, easier to mock dependencies for testing, better isolation of sensitive data processing, and independent evolution of capabilities.
- Cons: Higher initial setup cost for new modules and mandatory boilerplate for cross-module communication.