Architecture Principles
Purpose
This document defines the non-negotiable architectural principles for projects using AI contextFlow.
It exists to prevent architectural drift, uncontrolled coupling, and short-term implementation decisions that degrade long-term maintainability.
These principles are intentionally technology-agnostic.
Scope
These principles apply to:
- System structure and modularization
- Dependency direction and boundaries
- Interface design and contracts
- Evolution and change management
If a project deviates from these principles, the deviation must be explicit and justified.
Core Goals
- Maintain clear boundaries between concerns
- Enable change with low risk and predictable impact
- Support long-term maintainability and testability
- Prevent uncontrolled coupling and implicit dependencies
1. Explicit Boundaries
- Organize the system into modules with clear responsibilities.
- A module must have a clear purpose and a stable public interface.
- Avoid "god" modules that accumulate unrelated responsibilities.
Rule of thumb: If a module cannot be explained in one sentence, it is likely too broad.
2. Dependency Direction
- Dependencies must point from higher-level policy to lower-level details.
- Domain or core logic must not depend on infrastructure or UI concerns.
- Prevent cyclic dependencies.
Enforcement: If dependency direction is unclear, refactor the boundary.
3. Contracts Over Knowledge
- Prefer explicit interfaces/contracts over implicit knowledge of internals.
- Avoid reaching into internals of other modules.
- Treat external integrations as unstable: isolate them behind adapters.
4. Keep the Domain Clean
- Central business rules should be explicit and testable.
- Avoid mixing domain logic with persistence, networking, or UI code.
- Domain logic must be easy to unit test.
5. Composition Over Framework Lock-In
- Frameworks should be treated as tools, not as architecture.
- Keep core logic framework-independent where feasible.
- Avoid coupling business rules directly to framework constructs.
6. Prefer a Modular Monolith by Default
- Start as a modular monolith unless there is a strong, validated reason to split into services.
- Services introduce operational and coordination overhead.
- Split only when boundaries are proven and required.
7. Data Ownership and Consistency
- Each module owns its data and invariants.
- Avoid shared mutable state across modules.
- Define data contracts explicitly.
8. Evolve Through Small, Safe Steps
- Prefer incremental evolution over large rewrites.
- Structural changes must be supported by tests and/or characterization tests.
- Avoid redesigning architecture without concrete pressure.
9. Document Long-Term Decisions
Use Architecture Decision Records (ADRs) when:
- A decision affects system structure long-term
- A decision is hard to reverse
- A decision introduces significant trade-offs
If it matters in six months, it deserves an ADR.
10. Quality as Architecture
Architecture is not just structure — it includes:
- testability
- observability
- operability
- security
If a design cannot be tested or operated, it is not complete.
Quality Gates
A change is architecturally acceptable only if:
- Boundaries remain clear
- Dependency direction is preserved
- Coupling is not increased without explicit justification
- Long-term decisions are documented
Anti-Patterns
- Implicit module coupling ("just call it directly")
- Cyclic dependencies
- Framework-first design (architecture = framework)
- Shared mutable state across modules
- Large rewrites without pressure or test safety
Status
These principles are intentionally conservative.
They are designed to keep a codebase understandable and maintainable under intensive AI-assisted development.