provisioning/docs/src/architecture/adr/ADR-001-project-structure.md
2026-01-12 04:42:18 +00:00

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:

  1. Provider-specific code scattered: Cloud provider implementations were mixed with core logic
  2. Task services fragmented: Infrastructure services lacked consistent structure
  3. Domain boundaries unclear: No clear separation between core, providers, and services
  4. Development artifacts mixed with distribution: User-facing tools mixed with development utilities
  5. Deep call stack limitations: Nushell's runtime limitations required architectural solutions
  6. 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

  1. Domain Separation: Each major component has clear boundaries and responsibilities
  2. Hybrid Architecture: Rust for performance-critical coordination, Nushell for business logic
  3. Provider Abstraction: Standardized interfaces across cloud providers
  4. Service Modularity: Reusable task services with consistent structure
  5. Clean Distribution: Development tools separated from user-facing components
  6. 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