syntaxis/docs/provision/architectural-analysis.md
Jesús Pérez 9cef9b8d57 refactor: consolidate configuration directories
Merge _configs/ into config/ for single configuration directory.
Update all path references.

Changes:
- Move _configs/* to config/
- Update .gitignore for new patterns
- No code references to _configs/ found

Impact: -1 root directory (layout_conventions.md compliance)
2025-12-26 18:36:23 +00:00

26 KiB

🏗️ Análisis Arquitectónico: Gestión de Abstracciones y KCL

Fecha: 2025-11-20 Clasificación: Análisis estratégico de arquitectura Audiencia: Arquitectos, Tech Leads, Decisores


📋 Índice Ejecutivo

Este documento responde tres preguntas críticas:

  1. ¿Cómo se gestiona esto? - Estrategia de gestión y orquestación
  2. ¿Cómo abstraerlo para otros proyectos? - Patrón de abstracción reutilizable
  3. ¿Por qué no KCL directamente? - Análisis de decisión arquitectónica

🔍 PREGUNTA 1: ¿CÓMO SE GESTIONA ESTO?

Arquitectura Actual de Gestión

┌─────────────────────────────────────────────────────────────┐
│                 CAPA DE GESTIÓN (Orquestación)              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  NuShell Scripts (Provisioning Layer)                      │
│  ├─ provctl.nu (Main Orchestrator)                         │
│  ├─ service-catalog.nu (Service Discovery)                │
│  ├─ pack.nu (Bundle Management)                           │
│  ├─ install.nu (Binary Installation)                      │
│  ├─ deploy.nu (Config Deployment)                         │
│  └─ validate.nu (Integrity Checking)                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────┐
│              CAPA DE DEFINICIÓN (Service Registry)          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Configuration Files (Single Source of Truth)              │
│  ├─ services-catalog.toml (6 servicios definidos)          │
│  ├─ installation.toml (Presets: minimal, dev, prod)        │
│  ├─ provisioning.toml (Binary distribution)                │
│  └─ provisioning/services/*.toml (Service configs)         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────┐
│         CAPA DE INTEGRACIÓN (Code Generation)               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  provctl-bridge (Rust Module)                              │
│  ├─ catalog.rs (Service discovery & validation)           │
│  ├─ Code generators (Docker/K8s/Terraform)                │
│  └─ CLI tool (User interface)                             │
│                                                             │
│  provisioning.rs (Rust Module)                             │
│  ├─ ProvisioningManager (Orchestration)                    │
│  ├─ KCL schema generation                                  │
│  └─ Workspace initialization                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────┐
│       CAPA DE EJECUCIÓN (Deployment & Runtime)              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Infrastructure Targets                                    │
│  ├─ Docker Compose (Local development)                     │
│  ├─ Kubernetes (Team/Production)                           │
│  ├─ Terraform (IaC management)                             │
│  └─ KCL Schemas (Cluster definition)                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Flujo de Datos de Gestión

1. DEFINICIÓN (Human Edited)
   services-catalog.toml ← Actualizar servicio
   ↓
2. REGISTRO (Auto Discovered)
   service-catalog.nu [list|ports|groups|patterns]
   ↓
3. VALIDACIÓN (Automated)
   validate.nu checks:
   - Schema integrity
   - No circular dependencies
   - All services exist
   - Port conflicts detection
   ↓
4. GENERACIÓN (Code Gen)
   catalog-cli generates:
   - Docker Compose
   - Kubernetes manifests
   - Terraform code
   - KCL schemas
   ↓
5. EMPAQUETAMIENTO (Distribution)
   pack.nu creates:
   - Binary bundles
   - Configuration bundles
   - Manifest files
   ↓
6. INSTALACIÓN (Deployment)
   install.nu deploys:
   - Binaries to system
   - Configs to ~/.local/share
   - Manifests to /provisioning
   ↓
7. ORQUESTACIÓN (Runtime)
   provctl.nu manages:
   - Service startup order
   - Health check monitoring
   - Scaling decisions
   - Failure recovery

Puntos de Gestión Críticos

A. Validación en Múltiples Niveles

Nivel 1: Sintaxis TOML
└─ cargo check (Rust compilation)

Nivel 2: Esquema Semántico
└─ validate.nu (custom validation rules)

Nivel 3: Integridad de Dependencias
└─ catalog.validate() (dependency graph analysis)

Nivel 4: Viabilidad de Despliegue
└─ deployment tests (actual K8s/Docker validation)

Nivel 5: Compatibilidad de Plataforma
└─ platform detection (OS-specific configuration)

B. Versionado y Control de Cambios

# services-catalog.toml con control de versiones
[metadata]
version = "2025-11-20"
schema_version = "1.0"
last_modified = "2025-11-20T10:00:00Z"
modified_by = "developer@team"

[service.syntaxis-api]
# Changes tracked via git
# - Added health_check endpoint: 2025-11-19
# - Updated memory requirement: 256MB (was 128MB)
# - Added dependency on surrealdb: 2025-11-15

C. Auditoria de Cambios

# Ver historia de cambios
git log --oneline configs/services-catalog.toml

# Ver cambios específicos
git diff HEAD~1 configs/services-catalog.toml

# Ver por autor
git log --format="%an %ae" configs/services-catalog.toml

🎯 PREGUNTA 2: ¿CÓMO ABSTRAERLO PARA OTROS PROYECTOS?

Patrón de Abstracción Reutilizable: "ServiceRegistry"

GENÉRICO (Aplicable a cualquier proyecto)
├── Service Definition Language
│   └── TOML-based schema (not KCL-specific)
│
├── Service Discovery Interface
│   ├── list_services() → Vec<Service>
│   ├── get_service(id) → Service
│   ├── query_by_tag(tag) → Vec<Service>
│   └── validate() → Result<(), Vec<Error>>
│
├── Code Generation Pipeline
│   ├── Docker generator
│   ├── Kubernetes generator
│   ├── Terraform generator
│   └── Custom generators (pluggable)
│
├── Configuration Management
│   ├── Load from TOML/YAML
│   ├── Merge presets/profiles
│   ├── Variable substitution
│   └── Platform-specific overrides
│
└── Orchestration Interface
    ├── Validate workspace
    ├── Generate manifests
    ├── Deploy services
    └── Monitor health

Implementación del Patrón para Otros Proyectos

Estructura Base Recomendada

my-project/
├── services/                    # Service registry
│   ├── catalog.toml            # Service definitions (MASTER)
│   ├── patterns/
│   │   ├── dev.toml           # Development pattern
│   │   ├── staging.toml       # Staging pattern
│   │   └── production.toml    # Production pattern
│   └── presets/
│       ├── minimal.toml       # Minimal setup
│       ├── standard.toml      # Standard setup
│       └── enterprise.toml    # Enterprise setup
│
├── provisioning/               # Code generation & deployment
│   ├── src/
│   │   ├── registry.rs        # Service registry abstraction
│   │   ├── generators/
│   │   │   ├── docker.rs
│   │   │   ├── kubernetes.rs
│   │   │   ├── terraform.rs
│   │   │   └── custom.rs      # Custom generators
│   │   ├── validators/
│   │   │   ├── schema.rs
│   │   │   ├── dependencies.rs
│   │   │   └── conflicts.rs
│   │   └── cli/
│   │       └── main.rs        # CLI interface
│   │
│   └── Cargo.toml
│
└── scripts/                    # Orchestration
    ├── provision.nu          # Main orchestrator
    ├── validate.nu           # Validation
    ├── generate.nu           # Code generation
    ├── deploy.nu             # Deployment
    └── monitor.nu            # Health monitoring

Módulo Reutilizable: ServiceRegistry

// Crate: service-registry (publicable en crates.io)

pub trait ServiceRegistry: Send + Sync {
    /// Load services from configuration
    async fn load(&mut self, config_path: &Path) -> Result<()>;

    /// Query operations
    fn list_services(&self) -> Vec<&Service>;
    fn get_service(&self, id: &str) -> Option<&Service>;
    fn get_by_tag(&self, tag: &str) -> Vec<&Service>;

    /// Validation
    fn validate(&self) -> Result<(), Vec<ValidationError>>;
    fn check_dependencies(&self) -> Result<(), Vec<DependencyError>>;
    fn detect_conflicts(&self) -> Result<(), Vec<ConflictError>>;

    /// Metrics & Analysis
    fn service_count(&self) -> usize;
    fn total_memory_requirement(&self) -> u64;
    fn port_assignments(&self) -> HashMap<u16, String>;
}

pub trait CodeGenerator: Send + Sync {
    fn name(&self) -> &str;
    fn generate(&self, registry: &dyn ServiceRegistry, pattern: &str) -> Result<String>;
}

pub trait Validator: Send + Sync {
    fn validate(&self, registry: &dyn ServiceRegistry) -> Result<(), Vec<String>>;
}

// Implementación default para Docker, Kubernetes, Terraform
pub struct DockerComposeGenerator;
pub struct KubernetesGenerator;
pub struct TerraformGenerator;

impl ServiceRegistry for DefaultRegistry {
    // ... implementations
}

Patrón de Integración para Nuevos Proyectos

// En tu proyecto nuevo:

use service_registry::{ServiceRegistry, DefaultRegistry};
use service_registry::generators::{DockerComposeGenerator, KubernetesGenerator};

#[tokio::main]
async fn main() -> Result<()> {
    // 1. Cargar registry
    let mut registry = DefaultRegistry::new();
    registry.load("./services/catalog.toml").await?;

    // 2. Validar
    registry.validate()?;
    registry.check_dependencies()?;

    // 3. Generar
    let docker_gen = DockerComposeGenerator;
    let docker_code = docker_gen.generate(&registry, "production")?;

    let k8s_gen = KubernetesGenerator;
    let k8s_code = k8s_gen.generate(&registry, "production")?;

    // 4. Implementar generadores custom si necesario
    let custom_gen = MyCustomGenerator;
    let custom_code = custom_gen.generate(&registry, "production")?;

    Ok(())
}

Ejemplo: Adaptación para Proyecto de E-Commerce

# services/catalog.toml para e-commerce

[service.web-frontend]
name = "web-frontend"
type = "web"
description = "React SPA frontend"
language = "typescript"

[service.web-frontend.ports]
http = 3000
https = 3443

[service.web-frontend.dependencies]
requires = ["api-gateway"]

[service.api-gateway]
name = "api-gateway"
type = "gateway"
description = "Kong API Gateway"

[service.api-gateway.ports]
http = 8000
admin = 8001

[service.api-gateway.dependencies]
requires = ["auth-service", "product-service"]

[service.auth-service]
name = "auth-service"
type = "microservice"
language = "rust"
port = 5001

[service.product-service]
name = "product-service"
type = "microservice"
language = "go"
port = 5002

[service.product-service.dependencies]
requires = ["postgres", "redis"]

[service.postgres]
name = "postgres"
type = "database"
port = 5432

[service.redis]
name = "redis"
type = "cache"
port = 6379

# Patterns específicas para e-commerce
[pattern.mvp]
name = "MVP Deployment"
services = ["web-frontend", "api-gateway", "auth-service", "product-service", "postgres"]

[pattern.production]
name = "Production Deployment"
services = ["web-frontend", "api-gateway", "auth-service", "product-service", "postgres", "redis"]

[pattern.dev]
name = "Local Development"
services = ["web-frontend", "api-gateway", "auth-service", "product-service", "postgres"]

⚠️ PREGUNTA 3: ¿POR QUÉ NO KCL DIRECTAMENTE?

Análisis Comparativo: TOML vs KCL

Opción A: KCL Directo (Lo que project-provisioning usa)

#!/usr/bin/env kcl
# KCL Schema para definición de servicios

service = {
    name: "syntaxis-api",
    type: "server",
    ports: {
        http: 3000
    },
    resources: {
        memory: "256Mi",
        cpu: "100m"
    },
    health_check: {
        endpoint: "/health",
        interval: "10s",
        timeout: "5s"
    }
}

Ventajas de KCL:

  • Lenguaje completo (variables, condicionales, loops)
  • Type-safe configuration
  • Reutilización de código via funciones
  • Powerful para Kubernetes/cluster definitions

Desventajas de KCL:

  • Curva de aprendizaje pronunciada
  • Requiere runtime KCL (dependencia externa)
  • Menos portable (no es universal)
  • Overkill para service registry simple
  • Debugging más complejo
  • IDE support limitado

Opción B: TOML (Lo que usamos actualmente)

# TOML Schema para definición de servicios

[service.syntaxis-api]
name = "syntaxis-api"
type = "server"
description = "REST API server"

[service.syntaxis-api.ports]
http = 3000

[service.syntaxis-api.resources]
memory_mb = 256
cpu_millicores = 100

[service.syntaxis-api.health_check]
endpoint = "/health"
interval_seconds = 10
timeout_seconds = 5

Ventajas de TOML:

  • Simple, intuitivo, universal
  • Soporte nativo en Rust/Python/Go
  • Fácil de editar manualmente
  • Bajo overhead cognitivo
  • Mejor IDE support
  • Fácil de parsear y validar
  • Portable (funciona en cualquier lado)

Desventajas de TOML:

  • Sin lógica condicional
  • Sin reutilización de código
  • Puede tener repetición
  • Sin validación en tiempo de definición

Análisis de Decisión: Por qué NO KCL Directo

1. Principio de Responsabilidad Única

project-provisioning:
  - Define INFRAESTRUCTURA (clusters, networking, storage)
  - USA KCL ✓ (Apropiado para cluster definitions)

syntaxis:
  - Define SERVICIOS (qué aplicaciones tenemos)
  - USA TOML ✓ (Service registry, no infraestructura)

KCL está diseñado para infrastructure-as-code (clusters, networking). Nosotros necesitamos un service registry (qué servicios, cómo se ejecutan).

2. Separación de Concerns

┌─────────────────────────────────────────┐
│   project-provisioning (Infrastructure)  │
│   - KCL para cluster definitions         │
│   - Terraform para IaC                   │
│   - Kubernetes para orchestration        │
└─────────────────────────────────────────┘
            ↑ Lee definiciones de servicios
            │
┌─────────────────────────────────────────┐
│     syntaxis (Application Services)      │
│     - TOML para service registry         │
│     - Rust para code generation          │
│     - Docker/K8s/Terraform para output   │
└─────────────────────────────────────────┘

3. Portabilidad y Bajo Acoplamiento

Escenario A: syntaxis usara KCL
├─ Dependencia: kcl-lang runtime
├─ Usuarios deben tener KCL instalado
├─ Coupling ALTO con project-provisioning
└─ Difícil usar syntaxis sin provisioning

Escenario B: syntaxis usa TOML (actual)
├─ Dependencia: ninguna especial
├─ TOML es universal (Rust, Python, Go, etc.)
├─ Coupling BAJO, módular, independiente
└─ Fácil usar syntaxis sin provisioning

4. Casos de Uso y Abstracciones

Caso de Uso Herramienta Por qué
"¿Qué servicios tenemos?" TOML registry Simple, directo, sin lógica
"¿Cuáles son las dependencias?" TOML + Rust validation Schema simple, lógica en código
"Generar Docker/K8s/Terraform" TOML input + Rust generator Entrada simple, transformación compleja
"¿Cómo defino un cluster?" KCL Lógica compleja, tipo-seguro necesario
"¿Cómo hago provisioning?" KCL + Terraform Full infrastructure definition

5. Peso y Complejidad

KCL approach:
├─ Aprender KCL (2-3 horas)
├─ Instalar kcl-lang (overhead)
├─ Entender type system de KCL
├─ Debug de KCL schemas
└─ Integración con provisioning

TOML approach (actual):
├─ Aprender TOML (30 minutos)
├─ Editar archivo de texto
├─ Validación automática via Rust
├─ Debug trivial
└─ Cero dependencias externas

Arquitectura Híbrida RECOMENDADA

┌──────────────────────────────────────────────────────┐
│                  CAPA DE APLICACIÓN                   │
│                  (syntaxis services)                  │
├──────────────────────────────────────────────────────┤
│  services-catalog.toml (Service definitions)         │
│  ├─ Services (what we have)                          │
│  ├─ Patterns (deployment topologies)                 │
│  └─ Dependencies (relationships)                     │
└──────────────────────────────────────────────────────┘
                       ↓ (Input)
┌──────────────────────────────────────────────────────┐
│              CAPA DE GENERACIÓN                       │
│          (provctl-bridge in Rust)                    │
├──────────────────────────────────────────────────────┤
│  Generator Pipeline:                                 │
│  ├─ Docker Compose generator                        │
│  ├─ Kubernetes generator                            │
│  ├─ Terraform generator                             │
│  └─ KCL generator (new!)                            │
└──────────────────────────────────────────────────────┘
                       ↓ (Output)
┌──────────────────────────────────────────────────────┐
│              CAPA DE INFRAESTRUCTURA                  │
│            (project-provisioning)                    │
├──────────────────────────────────────────────────────┤
│  Generated KCL schemas (cluster definitions)         │
│  ├─ cluster.k (Generated from catalog)              │
│  ├─ networking.k (Additional KCL)                   │
│  └─ storage.k (Infrastructure patterns)             │
│                                                      │
│  Then apply via KCL runtime:                        │
│  └─ kcl cluster.k | terraform apply                 │
└──────────────────────────────────────────────────────┘

Por qué este enfoque HÍBRIDO es mejor

✅ Separación de responsabilidades clara
   - Application layer: TOML (simple)
   - Infrastructure layer: KCL (powerful)

✅ Bajo acoplamiento
   - syntaxis no depende de project-provisioning
   - project-provisioning puede leer TOML directamente

✅ Reutilización
   - Service definitions in TOML can be used by:
     * Docker Compose generators
     * Kubernetes generators
     * Terraform generators
     * KCL generators
     * Documentation generators
     * Monitoring systems

✅ Escalabilidad
   - Agregar nuevo generador = agregar 1 nuevo módulo
   - No requiere cambiar TOML schema
   - Máxima flexibilidad

✅ Mantenibilidad
   - TOML es fácil de editar
   - Cambios en servicios = editar TOML
   - Cambios en infraestructura = editar KCL
   - Cambios en code gen = editar Rust

🎯 RECOMENDACIONES ESTRATÉGICAS

1. Mantener Status Quo (TOML para Servicios)

Razonamiento:
├─ Ya está implementado y funcionando
├─ 34/34 tests pasando
├─ Bajo overhead cognitivo
├─ Fácil mantenimiento
└─ Genera salida en 3 formatos

2. Agregar KCL Generator (Nuevo!)

// Agregar a catalog.rs

pub fn generate_kcl(&self, pattern_name: &str) -> Result<String> {
    let services = self.get_pattern_services(pattern_name)?;

    let mut kcl = String::from("#!/usr/bin/env kcl\n");
    kcl.push_str("# Generated from service catalog\n\n");

    for service in services {
        kcl.push_str(&format!(
            r#"service_{} = {{
    name: "{}",
    type: "{}",
    ports: {{}}"#,
            service.name, service.display_name, service.service_type
        ));

        // ... agregar puertos, recursos, etc.
    }

    Ok(kcl)
}

3. Crear Abstracción para Otros Proyectos

// Crear crate reutilizable: service-registry

pub trait ServiceRegistry {
    fn list_services(&self) -> Vec<&Service>;
    fn validate(&self) -> Result<()>;
    // ... standard operations
}

// Publicar en crates.io
// Usado por: syntaxis, otros proyectos, herramientas internas

4. Patrón de Extensión para Nuevos Proyectos

Estructura base recomendada para nuevo proyecto X:

x-project/
├── services/
│   └── catalog.toml          ← Define tus servicios
├── provisioning/
│   └── src/
│       └── main.rs           ← Usa service-registry crate
└── scripts/
    └── provision.nu          ← Orquestación

📊 Comparativa Final: Decisiones Arquitectónicas

Aspecto TOML (Servicios) KCL (Cluster) Decisión
Complejidad Baja Alta TOML para servicios
Portabilidad Alta Media TOML es universal
Type-Safety Validación Rust Type-safe KCL Depende de caso
Lógica Limitada Completa KCL para infraestructura
Reutilización Código Rust Funciones KCL Ambos en su contexto
Learning Curve Muy baja Media-Alta TOML para adopción rápida
Coupling Bajo Alto TOML desacoplado

🚀 Roadmap Recomendado

Fase 1: Ahora (Status Quo Mejorado)

  • TOML service registry ( Done)
  • Docker/K8s/Terraform generators ( Done)
  • CLI tool ( Done)
  • TODO: KCL generator (Low priority)

Fase 2: Próximos 2 meses

  • Extraer abstracción service-registry crate
  • Publicar en crates.io
  • Crear documentación de extensión

Fase 3: Próximos 4 meses

  • Template para nuevos proyectos
  • Integración con project-provisioning (KCL generation)
  • Métricas y monitoreo

Fase 4: Próximos 6 meses

  • Multi-cloud support (AWS, GCP, Azure)
  • Gitops integration
  • Advanced patterns (canary, blue-green)

📚 Referencias y Documentación Relacionada

  • INTEGRATION_FINAL.md - Estado actual de integración
  • ADVANCED_FEATURES.md - Patrones avanzados
  • SESSION_SUMMARY.md - Detalles de implementación

Conclusión: El enfoque híbrido (TOML + Rust generators + KCL opcional) es superior a usar KCL directamente porque:

  1. Mantiene separación de concerns (servicios vs infraestructura)
  2. Reduce coupling entre componentes
  3. Facilita reutilización y extensión
  4. Baja barrera de entrada para usuarios finales
  5. Máxima flexibilidad en salidas generadas