Files
Mastermind/docs/adr/0005-strict-clean-capability-architecture.md
T

47 lines
2.2 KiB
Markdown

# 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.