5.3 KiB
ADR-001: Project Structure Decision
Status
Accepted
Context
Provisioning had evolved from a monolithic structure into a complex system with mixed organizational patterns. The original structure had multiple issues:
- Provider-specific code scattered: Cloud provider implementations were mixed with core logic
- Task services fragmented: Infrastructure services lacked consistent structure
- Domain boundaries unclear: No clear separation between core, providers, and services
- Development artifacts mixed with distribution: User-facing tools mixed with development utilities
- Deep call stack limitations: Nushell's runtime limitations required architectural solutions
- Configuration complexity: 200+ environment variables across 65+ files needed systematic organization
The system needed a clear, maintainable structure that supports:
- Multi-provider infrastructure provisioning (AWS, UpCloud, local)
- Modular task services (Kubernetes, container runtimes, storage, networking)
- Clear separation of concerns
- Hybrid Rust/Nushell architecture
- Configuration-driven workflows
- Clean distribution without development artifacts
Decision
Adopt a domain-driven hybrid structure organized around functional boundaries:
src/
├── core/ # Core system and CLI entry point
├── platform/ # High-performance coordination layer (Rust orchestrator)
├── orchestrator/ # Legacy orchestrator location (to be consolidated)
├── provisioning/ # Main provisioning with domain modules
├── control-center/ # Web UI management interface
├── tools/ # Development and utility tools
└── extensions/ # Plugin and extension framework
Key Structural Principles
- Domain Separation: Each major component has clear boundaries and responsibilities
- Hybrid Architecture: Rust for performance-critical coordination, Nushell for business logic
- Provider Abstraction: Standardized interfaces across cloud providers
- Service Modularity: Reusable task services with consistent structure
- Clean Distribution: Development tools separated from user-facing components
- Configuration Hierarchy: Systematic config management with interpolation support
Domain Organization
- Core: CLI interface, library modules, and common utilities
- Platform: High-performance Rust orchestrator for workflow coordination
- Provisioning: Main business logic with providers, task services, and clusters
- Control Center: Web-based management interface
- Tools: Development utilities and build systems
- Extensions: Plugin framework and custom extensions
Consequences
Positive
- Clear Boundaries: Each domain has well-defined responsibilities and interfaces
- Scalable Growth: New providers and services can be added without structural changes
- Development Efficiency: Developers can focus on specific domains without system-wide knowledge
- Clean Distribution: Users receive only necessary components without development artifacts
- Maintenance Clarity: Issues can be isolated to specific domains
- Hybrid Benefits: Leverage Rust performance where needed while maintaining Nushell productivity
- Configuration Consistency: Systematic approach to configuration management across all domains
Negative
- Migration Complexity: Required systematic migration of existing components
- Learning Curve: New developers need to understand domain boundaries
- Coordination Overhead: Cross-domain features require careful interface design
- Path Management: More complex path resolution with domain separation
- Build Complexity: Multiple domains require coordinated build processes
Neutral
- Development Patterns: Each domain may develop its own patterns within architectural guidelines
- Testing Strategy: Domain-specific testing strategies while maintaining integration coverage
- Documentation: Domain-specific documentation with clear cross-references
Alternatives Considered
Alternative 1: Monolithic Structure
Keep all code in a single flat structure with minimal organization. Rejected: Would not solve maintainability or scalability issues. Continued technical debt accumulation.
Alternative 2: Microservice Architecture
Split into completely separate services with network communication. Rejected: Overhead too high for single-machine deployment use case. Would complicate installation and configuration.
Alternative 3: Language-Based Organization
Organize by implementation language (rust/, nushell/, kcl/). Rejected: Does not align with functional boundaries. Cross-cutting concerns would be scattered.
Alternative 4: Feature-Based Organization
Organize by user-facing features (servers/, clusters/, networking/). Rejected: Would duplicate cross-cutting infrastructure and provider logic across features.
Alternative 5: Layer-Based Architecture
Organize by architectural layers (presentation/, business/, data/). Rejected: Does not align with domain complexity. Infrastructure provisioning has different layering needs.
References
- Configuration System Migration (ADR-002)
- Hybrid Architecture Decision (ADR-004)
- Extension Framework Design (ADR-005)
- Project Architecture Principles (PAP) Guidelines