# πŸ—οΈ DiseΓ±o Detallado: KCL + REST API - Service Registry **Fecha**: 2025-11-20 **ClasificaciΓ³n**: Arquitectura detallada y diseΓ±o tΓ©cnico **Estado**: Design Phase - Ready for Implementation **Siguiendo**: ARCHITECTURE_REVISION.md (Option C: KCL + REST API) --- ## πŸ“‹ Tabla de Contenidos 1. [VisiΓ³n General](#visiΓ³n-general) 2. [Estructura de Definiciones KCL](#estructura-de-definiciones-kcl) 3. [API REST Detallada](#api-rest-detallada) 4. [ImplementaciΓ³n Rust](#implementaciΓ³n-rust) 5. [Clientes Multi-Lenguaje](#clientes-multi-lenguaje) 6. [Flujos de IntegraciΓ³n](#flujos-de-integraciΓ³n) 7. [Estrategia de MigraciΓ³n](#estrategia-de-migraciΓ³n) 8. [Operaciones y Mantenimiento](#operaciones-y-mantenimiento) --- ## 🎯 VisiΓ³n General ### Principios de DiseΓ±o ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PRINCIPIOS CLAVE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ 1. Source of Truth: KCL (en provisioning) β”‚ β”‚ 2. Transport: REST API (agnΓ³stico del lenguaje) β”‚ β”‚ 3. Consumo: Cada lenguaje accede idiomatically β”‚ β”‚ 4. Cambios: Sin recompilaciΓ³n (solo cambiar KCL) β”‚ β”‚ 5. Escalabilidad: Soporta 50+ proyectos β”‚ β”‚ 6. ValidaciΓ³n: Nativa en KCL + API validation β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Capas de Arquitectura ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Layer 0: KCL Definition Layer β”‚ β”‚ (En provisioning, source of truth) β”‚ β”‚ - services.k (definiciones de servicios) β”‚ β”‚ - patterns.k (patrones de despliegue) β”‚ β”‚ - groups.k (agrupaciones de servicios) β”‚ β”‚ - policies.k (validaciones y reglas) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ (cargado y procesado) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Layer 1: KCL Runtime β”‚ β”‚ (En provisioning, valida y compila) β”‚ β”‚ - CompilaciΓ³n de KCL a tipos Rust β”‚ β”‚ - ValidaciΓ³n de esquemas β”‚ β”‚ - CΓ‘lculo de dependencias β”‚ β”‚ - GeneraciΓ³n de cΓ³digo (YAML/JSON/HCL) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ (expone como API) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Layer 2: REST API Gateway β”‚ β”‚ (En provisioning, servidor HTTP) β”‚ β”‚ - /api/v1/services β”‚ β”‚ - /api/v1/patterns β”‚ β”‚ - /api/v1/validate β”‚ β”‚ - /api/v1/generate β”‚ β”‚ - /api/v1/health β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↙ ↓ β†˜ ↙ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ syntaxis β”‚ Node.js β”‚ Python β”‚ Go β”‚ β”‚ (Rust) β”‚ (HTTP) β”‚ (HTTP) β”‚ (HTTP) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ BENEFICIO: Cada consumidor usa su lenguaje, todos consultan la misma verdad ``` --- ## πŸ“¦ Estructura de Definiciones KCL ### 1. OrganizaciΓ³n de Archivos KCL ``` provisioning/ β”œβ”€β”€ services.k # Definiciones core de servicios β”œβ”€β”€ patterns.k # Patrones de despliegue β”œβ”€β”€ groups.k # Agrupaciones lΓ³gicas β”œβ”€β”€ policies.k # Reglas de validaciΓ³n β”œβ”€β”€ schemas/ β”‚ β”œβ”€β”€ service_schema.k # Schema para servicios β”‚ β”œβ”€β”€ pattern_schema.k # Schema para patrones β”‚ └── dependency_schema.k # Schema para dependencias └── examples/ β”œβ”€β”€ api_service.k # Ejemplo: API service β”œβ”€β”€ database_service.k # Ejemplo: Database service └── monitoring_service.k # Ejemplo: Monitoring service ``` ### 2. DefiniciΓ³n de Servicio en KCL ```kcl # services.k # Schema de servicio Service = { id: str # Identificador ΓΊnico name: str # Nombre legible displayName: str # Nombre para mostrar description: str # DescripciΓ³n version: str # VersiΓ³n del servicio image: str # Docker image port: int # Puerto principal protocol: str = "http" # Protocolo: http, grpc, tcp replicas: int = 1 # RΓ©plicas por defecto # ConfiguraciΓ³n env: {str: str} # Variables de entorno resources: { cpu: str # CPU request (e.g., "100m", "0.5") memory: str # Memory request (e.g., "128Mi", "512Mi") cpuLimit: str | None = None # CPU limit (opcional) memoryLimit: str | None = None # Memory limit (opcional) } # Dependencias depends_on: [str] # IDs de servicios dependientes ports: [{ name: str port: int targetPort: int protocol: str = "TCP" }] # Health check healthCheck: { enabled: bool = True type: str = "http" # http, tcp, exec path: str = "/health" # Para HTTP interval: int = 10 # Segundos timeout: int = 5 # Segundos retries: int = 3 } # Metadata labels: {str: str} # Labels adicionales annotations: {str: str} # Anotaciones tags: [str] # Tags para bΓΊsqueda } # Definiciones de servicios individuales services = [ { id: "api-server" name: "api-server" displayName: "API Server" description: "REST API principal" version: "1.0.0" image: "syntaxis:api-latest" port: 3000 protocol: "http" replicas: 2 env: { "RUST_LOG": "info" "DATABASE_URL": "postgresql://postgres:5432/syntaxis" "ENVIRONMENT": "production" } resources: { cpu: "100m" memory: "256Mi" cpuLimit: "500m" memoryLimit: "512Mi" } depends_on: ["database", "cache"] ports: [ { name: "http" port: 3000 targetPort: 3000 protocol: "TCP" } ] healthCheck: { enabled: True type: "http" path: "/health" interval: 10 timeout: 5 retries: 3 } labels: { "app": "syntaxis" "component": "api" "tier": "backend" } tags: ["core", "api", "backend"] }, { id: "database" name: "postgres" displayName: "PostgreSQL Database" description: "Persistencia de datos principal" version: "15.0" image: "postgres:15-alpine" port: 5432 protocol: "tcp" replicas: 1 env: { "POSTGRES_DB": "syntaxis" "POSTGRES_USER": "postgres" } resources: { cpu: "250m" memory: "512Mi" cpuLimit: "1000m" memoryLimit: "2Gi" } depends_on: [] ports: [ { name: "postgresql" port: 5432 targetPort: 5432 protocol: "TCP" } ] healthCheck: { enabled: True type: "tcp" interval: 10 timeout: 5 retries: 3 } labels: { "app": "syntaxis" "component": "database" "tier": "data" } tags: ["data", "persistent", "critical"] } ] ``` ### 3. DefiniciΓ³n de Patrones en KCL ```kcl # patterns.k Pattern = { id: str # Identificador ΓΊnico name: str # Nombre del patrΓ³n displayName: str # Nombre legible description: str # DescripciΓ³n tags: [str] # Tags para bΓΊsqueda services: [str] # IDs de servicios incluidos minReplicas: int = 1 # RΓ©plicas mΓ­nimas maxReplicas: int = 5 # RΓ©plicas mΓ‘ximas environment: str # Entorno: dev, staging, production } patterns = [ { id: "local-dev" name: "local-dev" displayName: "Development Local" description: "Stack completo para desarrollo local con Docker Compose" tags: ["development", "local", "complete"] services: ["api-server", "database", "cache"] minReplicas: 1 maxReplicas: 1 environment: "development" }, { id: "staging" name: "staging" displayName: "Staging Environment" description: "Stack para testing y validaciΓ³n pre-producciΓ³n" tags: ["staging", "testing", "complete"] services: ["api-server", "database", "cache", "monitoring"] minReplicas: 1 maxReplicas: 3 environment: "staging" }, { id: "production" name: "production" displayName: "Production Environment" description: "Stack de producciΓ³n con alta disponibilidad" tags: ["production", "ha", "complete"] services: ["api-server", "database", "cache", "monitoring", "backup"] minReplicas: 2 maxReplicas: 10 environment: "production" } ] ``` ### 4. DefiniciΓ³n de Grupos en KCL ```kcl # groups.k Group = { id: str name: str displayName: str description: str services: [str] # IDs de servicios en el grupo tier: str # Tier: frontend, backend, data, infra } groups = [ { id: "backend-services" name: "backend-services" displayName: "Backend Services" description: "Servicios de backend/API" services: ["api-server", "api-gateway"] tier: "backend" }, { id: "data-layer" name: "data-layer" displayName: "Data Layer" description: "Servicios de persistencia de datos" services: ["database", "cache", "backup"] tier: "data" }, { id: "infrastructure" name: "infrastructure" displayName: "Infrastructure Services" description: "Servicios de infraestructura" services: ["monitoring", "logging", "messaging"] tier: "infra" } ] ``` ### 5. PolΓ­ticas de ValidaciΓ³n en KCL ```kcl # policies.k # Reglas de validaciΓ³n que se aplican automΓ‘ticamente # Validar que todos los servicios tienen health check validate_health_checks = lambda services { for s in services: assert s.healthCheck.enabled, "Service {} must have health check enabled".format(s.id) } # Validar que las dependencias existen validate_dependencies = lambda services { service_ids = [s.id for s in services] for s in services: for dep_id in s.depends_on: assert dep_id in service_ids, "Service {} depends on non-existent service {}".format(s.id, dep_id) } # Validar restricciones de recursos validate_resources = lambda services { for s in services: # CPU debe estar en formato vΓ‘lido assert s.resources.cpu, "Service {} must specify CPU request".format(s.id) assert s.resources.memory, "Service {} must specify memory request".format(s.id) } # Validar que no hay ciclos de dependencias validate_no_cycles = lambda services { # Validar acΓ­clico dirigido def has_cycle(graph, node, visited, rec_stack): visited[node] = True rec_stack[node] = True for neighbor in graph.get(node, []): if not visited.get(neighbor): if has_cycle(graph, neighbor, visited, rec_stack): return True elif rec_stack.get(neighbor): return True rec_stack[node] = False return False graph = {s.id: s.depends_on for s in services} for service_id in graph: if not has_cycle(graph, service_id, {}, {}): continue else: assert False, "Cyclic dependency detected involving {}".format(service_id) } ``` --- ## πŸ”Œ API REST Detallada ### 1. Estructura de Respuesta EstΓ‘ndar ```rust // Todas las respuestas siguen este patrΓ³n // Success response (HTTP 200) { "success": true, "data": { /* contenido especΓ­fico */ }, "meta": { "version": "1.0", "timestamp": "2025-11-20T10:30:00Z", "request_id": "req_uuid_here" } } // Error response (HTTP 4xx/5xx) { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Service dependency cycle detected", "details": { "field": "services[0].depends_on", "value": ["api-server"], "reason": "Creates cycle with service 'database'" } }, "meta": { "version": "1.0", "timestamp": "2025-11-20T10:30:00Z", "request_id": "req_uuid_here" } } ``` ### 2. Endpoints Principales #### 2.1 GET /api/v1/health Status del servicio API ```bash # Request GET /api/v1/health # Response (200 OK) { "success": true, "data": { "status": "healthy", "version": "1.0.0", "uptime_seconds": 3600, "kcl_compiler": "2.3.0", "last_reload": "2025-11-20T09:00:00Z" } } ``` #### 2.2 GET /api/v1/services Listar todos los servicios ```bash # Request GET /api/v1/services?tag=backend&limit=10&offset=0 # Response (200 OK) { "success": true, "data": [ { "id": "api-server", "name": "api-server", "displayName": "API Server", "description": "REST API principal", "version": "1.0.0", "image": "syntaxis:api-latest", "port": 3000, "protocol": "http", "tags": ["core", "api", "backend"], "depends_on": ["database", "cache"] }, { "id": "database", "name": "postgres", "displayName": "PostgreSQL Database", "description": "Persistencia de datos principal", "version": "15.0", "image": "postgres:15-alpine", "port": 5432, "protocol": "tcp", "tags": ["data", "persistent", "critical"], "depends_on": [] } ], "meta": { "version": "1.0", "total": 2, "limit": 10, "offset": 0, "timestamp": "2025-11-20T10:30:00Z" } } ``` #### 2.3 GET /api/v1/services/:id Obtener detalles de un servicio especΓ­fico ```bash # Request GET /api/v1/services/api-server # Response (200 OK) { "success": true, "data": { "id": "api-server", "name": "api-server", "displayName": "API Server", "description": "REST API principal", "version": "1.0.0", "image": "syntaxis:api-latest", "port": 3000, "protocol": "http", "replicas": 2, "env": { "RUST_LOG": "info", "DATABASE_URL": "postgresql://postgres:5432/syntaxis", "ENVIRONMENT": "production" }, "resources": { "cpu": "100m", "memory": "256Mi", "cpuLimit": "500m", "memoryLimit": "512Mi" }, "depends_on": ["database", "cache"], "ports": [ { "name": "http", "port": 3000, "targetPort": 3000, "protocol": "TCP" } ], "healthCheck": { "enabled": true, "type": "http", "path": "/health", "interval": 10, "timeout": 5, "retries": 3 }, "labels": { "app": "syntaxis", "component": "api", "tier": "backend" }, "tags": ["core", "api", "backend"] } } ``` #### 2.4 GET /api/v1/services/:id/dependents Obtener servicios que dependen de uno especΓ­fico ```bash # Request GET /api/v1/services/database/dependents # Response (200 OK) { "success": true, "data": [ { "id": "api-server", "displayName": "API Server", "dependencyType": "required" }, { "id": "backup-service", "displayName": "Backup Service", "dependencyType": "optional" } ], "meta": { "total": 2, "timestamp": "2025-11-20T10:30:00Z" } } ``` #### 2.5 GET /api/v1/patterns Listar patrones de despliegue ```bash # Request GET /api/v1/patterns?environment=production # Response (200 OK) { "success": true, "data": [ { "id": "production", "name": "production", "displayName": "Production Environment", "description": "Stack de producciΓ³n con alta disponibilidad", "environment": "production", "services": ["api-server", "database", "cache", "monitoring", "backup"], "minReplicas": 2, "maxReplicas": 10, "tags": ["production", "ha", "complete"] } ] } ``` #### 2.6 GET /api/v1/patterns/:id/services Obtener servicios de un patrΓ³n especΓ­fico (con detalles) ```bash # Request GET /api/v1/patterns/production/services # Response (200 OK) { "success": true, "data": [ { "id": "api-server", "displayName": "API Server", "version": "1.0.0", "replicas": 2, "image": "syntaxis:api-latest" // ... detalles completos del servicio }, // ... mΓ‘s servicios ] } ``` #### 2.7 GET /api/v1/groups Listar grupos de servicios ```bash # Request GET /api/v1/groups?tier=backend # Response (200 OK) { "success": true, "data": [ { "id": "backend-services", "name": "backend-services", "displayName": "Backend Services", "description": "Servicios de backend/API", "tier": "backend", "services": ["api-server", "api-gateway"] } ] } ``` #### 2.8 POST /api/v1/validate Validar cambios antes de deployment ```bash # Request POST /api/v1/validate Content-Type: application/json { "services": [ { "id": "new-service", "name": "new-service", "displayName": "New Service", "version": "1.0.0", "image": "new-service:latest", "port": 3001, "depends_on": ["database"] } ], "validate_against_pattern": "production" } # Response (200 OK) { "success": true, "data": { "valid": true, "warnings": [], "errors": [], "impact_analysis": { "affected_services": ["api-server"], "breaking_changes": false, "deployment_risk": "low" } } } ``` #### 2.9 POST /api/v1/generate Generar cΓ³digo en mΓΊltiples formatos ```bash # Request POST /api/v1/generate Content-Type: application/json { "pattern_id": "production", "formats": ["kubernetes", "docker-compose", "terraform"], "options": { "namespace": "production", "domain": "app.example.com", "registry": "docker.io" } } # Response (200 OK) { "success": true, "data": { "kubernetes": { "filename": "kubernetes-production.yaml", "content": "apiVersion: v1\nkind: Service\n...", "format": "yaml" }, "docker-compose": { "filename": "docker-compose-production.yml", "content": "version: '3.8'\nservices:\n...", "format": "yaml" }, "terraform": { "filename": "main.tf", "content": "resource \"kubernetes_service\" \"api\" {\n...", "format": "hcl" } } } ``` #### 2.10 POST /api/v1/reload Recargar definiciones KCL (requiere autenticaciΓ³n admin) ```bash # Request POST /api/v1/reload Authorization: Bearer admin_token {} # Response (200 OK) { "success": true, "data": { "reloaded_at": "2025-11-20T10:31:00Z", "services_count": 12, "patterns_count": 4, "validation_passed": true } } ``` ### 3. ParΓ‘metros de Query Comunes ``` ?limit=10 # LΓ­mite de resultados (default: 20, max: 100) ?offset=0 # Offset para paginaciΓ³n (default: 0) ?tag=backend # Filtrar por tags (comma-separated) ?search=api # BΓΊsqueda full-text en nombre/descripciΓ³n ?sort=name # Campo para ordenar (name, version, id) ?order=asc # Orden (asc, desc) ``` --- ## πŸ’» ImplementaciΓ³n Rust ### 1. Estructura del Proyecto ``` provisioning/ β”œβ”€β”€ Cargo.toml β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ main.rs # Entry point β”‚ β”œβ”€β”€ api/ β”‚ β”‚ β”œβ”€β”€ mod.rs # API module β”‚ β”‚ β”œβ”€β”€ handlers.rs # Handler functions β”‚ β”‚ β”œβ”€β”€ extractors.rs # Custom extractors β”‚ β”‚ └── responses.rs # Response types β”‚ β”œβ”€β”€ kcl/ β”‚ β”‚ β”œβ”€β”€ mod.rs # KCL module β”‚ β”‚ β”œβ”€β”€ loader.rs # Carga archivos KCL β”‚ β”‚ └── validator.rs # Validaciones β”‚ β”œβ”€β”€ models/ β”‚ β”‚ β”œβ”€β”€ mod.rs β”‚ β”‚ β”œβ”€β”€ service.rs # Service struct β”‚ β”‚ β”œβ”€β”€ pattern.rs # Pattern struct β”‚ β”‚ └── group.rs # Group struct β”‚ β”œβ”€β”€ generators/ β”‚ β”‚ β”œβ”€β”€ mod.rs β”‚ β”‚ β”œβ”€β”€ kubernetes.rs # K8s generator β”‚ β”‚ β”œβ”€β”€ docker.rs # Docker Compose generator β”‚ β”‚ └── terraform.rs # Terraform generator β”‚ └── config.rs # ConfiguraciΓ³n └── tests/ β”œβ”€β”€ integration/ β”‚ β”œβ”€β”€ health_test.rs β”‚ β”œβ”€β”€ services_test.rs β”‚ β”œβ”€β”€ patterns_test.rs β”‚ └── validation_test.rs └── fixtures/ β”œβ”€β”€ services.k β”œβ”€β”€ patterns.k └── expected_outputs/ ``` ### 2. ImplementaciΓ³n de Main.rs ```rust use axum::{ extract::{Path, Query, State}, http::StatusCode, response::IntoResponse, routing::{get, post}, Json, Router, }; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tokio::sync::RwLock; use tracing::{info, error}; mod api; mod kcl; mod models; mod generators; mod config; use crate::models::{Service, Pattern, Group}; use crate::kcl::KclLoader; #[derive(Clone)] struct AppState { kcl_loader: Arc>, config: config::Config, } #[tokio::main] async fn main() { // Initialize tracing tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .init(); // Load configuration let config = config::Config::from_file("provisioning.toml") .expect("Failed to load config"); info!("Loading KCL definitions from: {}", config.kcl_path); // Load KCL definitions let kcl_loader = KclLoader::new(&config.kcl_path) .await .expect("Failed to load KCL definitions"); let state = AppState { kcl_loader: Arc::new(RwLock::new(kcl_loader)), config, }; // Build router let app = Router::new() // Health check .route("/api/v1/health", get(api::handlers::health)) // Services endpoints .route("/api/v1/services", get(api::handlers::list_services)) .route("/api/v1/services/:id", get(api::handlers::get_service)) .route("/api/v1/services/:id/dependents", get(api::handlers::get_dependents)) // Patterns endpoints .route("/api/v1/patterns", get(api::handlers::list_patterns)) .route("/api/v1/patterns/:id/services", get(api::handlers::get_pattern_services)) // Groups endpoints .route("/api/v1/groups", get(api::handlers::list_groups)) // Validation & Generation .route("/api/v1/validate", post(api::handlers::validate)) .route("/api/v1/generate", post(api::handlers::generate)) // Admin endpoints .route("/api/v1/reload", post(api::handlers::reload_kcl)) .with_state(state); // Start server let listener = tokio::net::TcpListener::bind(&state.config.server_addr) .await .expect("Failed to bind server"); info!("Server listening on {}", state.config.server_addr); axum::serve(listener, app) .await .expect("Server error"); } ``` ### 3. Handler de Servicios ```rust // api/handlers.rs use axum::extract::{Path, Query, State}; use axum::http::StatusCode; use axum::Json; use serde::{Deserialize, Serialize}; #[derive(Serialize)] pub struct ApiResponse { success: bool, data: T, meta: ResponseMeta, } #[derive(Serialize)] pub struct ResponseMeta { version: String, timestamp: String, #[serde(skip_serializing_if = "Option::is_none")] request_id: Option, } pub async fn list_services( State(state): State, Query(params): Query, ) -> Json>> { let loader = state.kcl_loader.read().await; let mut services = loader.get_services().clone(); // Aplicar filtros if let Some(tag) = params.tag { services.retain(|s| s.tags.iter().any(|t| t == &tag)); } if let Some(search) = params.search { services.retain(|s| { s.display_name.contains(&search) || s.description.contains(&search) }); } // Aplicar paginaciΓ³n let offset = params.offset.unwrap_or(0); let limit = params.limit.unwrap_or(20).min(100); let paginated = services .into_iter() .skip(offset) .take(limit) .collect::>(); Json(ApiResponse { success: true, data: paginated, meta: ResponseMeta { version: "1.0".to_string(), timestamp: chrono::Utc::now().to_rfc3339(), request_id: None, }, }) } pub async fn get_service( State(state): State, Path(id): Path, ) -> Result>, (StatusCode, String)> { let loader = state.kcl_loader.read().await; match loader.get_service(&id) { Some(service) => Ok(Json(ApiResponse { success: true, data: service.clone(), meta: ResponseMeta { version: "1.0".to_string(), timestamp: chrono::Utc::now().to_rfc3339(), request_id: None, }, })), None => Err(( StatusCode::NOT_FOUND, format!("Service '{}' not found", id), )), } } pub async fn validate( State(state): State, Json(payload): Json, ) -> Json> { let loader = state.kcl_loader.read().await; let result = loader.validate(&payload.services, payload.validate_against_pattern.as_deref()); Json(ApiResponse { success: true, data: result, meta: ResponseMeta { version: "1.0".to_string(), timestamp: chrono::Utc::now().to_rfc3339(), request_id: None, }, }) } ``` --- ## 🌐 Clientes Multi-Lenguaje ### 1. Cliente Rust (Integrado en syntaxis) ```rust // En syntaxis/core/crates/syntaxis-core/src/service_registry.rs use reqwest::Client; use serde::{Deserialize, Serialize}; #[derive(Clone)] pub struct ServiceRegistryClient { client: Client, base_url: String, } impl ServiceRegistryClient { pub fn new(api_url: impl Into) -> Self { Self { client: Client::new(), base_url: api_url.into(), } } pub async fn get_services(&self) -> Result, Box> { let url = format!("{}/api/v1/services", self.base_url); let response = self.client.get(&url).send().await?; let data: ApiResponse> = response.json().await?; Ok(data.data) } pub async fn get_service(&self, id: &str) -> Result> { let url = format!("{}/api/v1/services/{}", self.base_url, id); let response = self.client.get(&url).send().await?; let data: ApiResponse = response.json().await?; Ok(data.data) } pub async fn get_pattern(&self, id: &str) -> Result> { let url = format!("{}/api/v1/patterns/{}", self.base_url, id); let response = self.client.get(&url).send().await?; let data: ApiResponse = response.json().await?; Ok(data.data) } pub async fn validate_services( &self, services: &[Service], ) -> Result> { let url = format!("{}/api/v1/validate", self.base_url); let payload = ValidatePayload { services: services.to_vec(), validate_against_pattern: None, }; let response = self.client.post(&url).json(&payload).send().await?; let data: ApiResponse = response.json().await?; Ok(data.data) } pub async fn generate( &self, pattern_id: &str, formats: &[&str], ) -> Result> { let url = format!("{}/api/v1/generate", self.base_url); let payload = GeneratePayload { pattern_id: pattern_id.to_string(), formats: formats.iter().map(|s| s.to_string()).collect(), options: Default::default(), }; let response = self.client.post(&url).json(&payload).send().await?; let data: ApiResponse = response.json().await?; Ok(data.data) } } #[derive(Deserialize)] struct ApiResponse { success: bool, data: T, } ``` ### 2. Cliente JavaScript/Node.js ```javascript // clients/javascript/service-registry.js const fetch = require('node-fetch'); class ServiceRegistry { constructor(apiUrl = 'http://127.0.0.1:8080') { this.apiUrl = apiUrl; this.timeout = 5000; } async _request(method, endpoint, body = null) { const url = `${this.apiUrl}${endpoint}`; const options = { method, timeout: this.timeout, headers: { 'Content-Type': 'application/json', }, }; if (body) { options.body = JSON.stringify(body); } const response = await fetch(url, options); if (!response.ok) { const error = await response.json(); throw new Error(`API Error: ${error.error.message}`); } const data = await response.json(); return data.data; } async getServices(filters = {}) { const params = new URLSearchParams(filters); const endpoint = `/api/v1/services?${params.toString()}`; return this._request('GET', endpoint); } async getService(id) { return this._request('GET', `/api/v1/services/${id}`); } async getPatterns(filters = {}) { const params = new URLSearchParams(filters); const endpoint = `/api/v1/patterns?${params.toString()}`; return this._request('GET', endpoint); } async getPatternServices(patternId) { return this._request('GET', `/api/v1/patterns/${patternId}/services`); } async getGroups(filters = {}) { const params = new URLSearchParams(filters); const endpoint = `/api/v1/groups?${params.toString()}`; return this._request('GET', endpoint); } async validate(services, patternId = null) { const payload = { services, validate_against_pattern: patternId, }; return this._request('POST', '/api/v1/validate', payload); } async generate(patternId, formats, options = {}) { const payload = { pattern_id: patternId, formats, options, }; return this._request('POST', '/api/v1/generate', payload); } async health() { return this._request('GET', '/api/v1/health'); } } module.exports = ServiceRegistry; ``` ### 3. Cliente Python ```python # clients/python/service_registry.py import requests from typing import List, Dict, Optional, Any from dataclasses import dataclass @dataclass class ServiceRegistry: api_url: str = "http://127.0.0.1:8080" timeout: int = 5 def _request(self, method: str, endpoint: str, json: Optional[Dict] = None) -> Any: url = f"{self.api_url}{endpoint}" headers = {"Content-Type": "application/json"} response = requests.request( method=method, url=url, json=json, headers=headers, timeout=self.timeout, ) if not response.ok: error = response.json() raise Exception(f"API Error: {error['error']['message']}") data = response.json() return data['data'] def get_services(self, tag: Optional[str] = None, search: Optional[str] = None) -> List[Dict]: params = {} if tag: params['tag'] = tag if search: params['search'] = search endpoint = "/api/v1/services" if params: query_string = "&".join(f"{k}={v}" for k, v in params.items()) endpoint = f"{endpoint}?{query_string}" return self._request("GET", endpoint) def get_service(self, service_id: str) -> Dict: return self._request("GET", f"/api/v1/services/{service_id}") def get_patterns(self, environment: Optional[str] = None) -> List[Dict]: endpoint = "/api/v1/patterns" if environment: endpoint = f"{endpoint}?environment={environment}" return self._request("GET", endpoint) def get_pattern_services(self, pattern_id: str) -> List[Dict]: return self._request("GET", f"/api/v1/patterns/{pattern_id}/services") def get_groups(self) -> List[Dict]: return self._request("GET", "/api/v1/groups") def validate(self, services: List[Dict], pattern_id: Optional[str] = None) -> Dict: payload = { "services": services, "validate_against_pattern": pattern_id, } return self._request("POST", "/api/v1/validate", json=payload) def generate( self, pattern_id: str, formats: List[str], options: Optional[Dict] = None, ) -> Dict: payload = { "pattern_id": pattern_id, "formats": formats, "options": options or {}, } return self._request("POST", "/api/v1/generate", json=payload) def health(self) -> Dict: return self._request("GET", "/api/v1/health") ``` ### 4. Cliente Go ```go // clients/go/service_registry.go package serviceregistry import ( "encoding/json" "fmt" "io/ioutil" "net/http" "time" ) type ServiceRegistry struct { BaseURL string Client *http.Client } func NewServiceRegistry(apiURL string) *ServiceRegistry { return &ServiceRegistry{ BaseURL: apiURL, Client: &http.Client{ Timeout: 5 * time.Second, }, } } func (sr *ServiceRegistry) GetServices() ([]Service, error) { endpoint := fmt.Sprintf("%s/api/v1/services", sr.BaseURL) resp, err := sr.Client.Get(endpoint) if err != nil { return nil, err } defer resp.Body.Close() var result struct { Success bool `json:"success"` Data []Service `json:"data"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result.Data, nil } func (sr *ServiceRegistry) GetService(id string) (*Service, error) { endpoint := fmt.Sprintf("%s/api/v1/services/%s", sr.BaseURL, id) resp, err := sr.Client.Get(endpoint) if err != nil { return nil, err } defer resp.Body.Close() var result struct { Success bool `json:"success"` Data Service `json:"data"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return &result.Data, nil } func (sr *ServiceRegistry) GetPatterns() ([]Pattern, error) { endpoint := fmt.Sprintf("%s/api/v1/patterns", sr.BaseURL) resp, err := sr.Client.Get(endpoint) if err != nil { return nil, err } defer resp.Body.Close() var result struct { Success bool `json:"success"` Data []Pattern `json:"data"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result.Data, nil } ``` --- ## πŸ”— Flujos de IntegraciΓ³n ### 1. Flujo: syntaxis obtiene catΓ‘logo actualizado ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ syntaxis (en cualquier momento, sin recompilaciΓ³n) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ GET /api/v1/services ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ API Gateway (provisioning) β”‚ β”‚ β”œβ”€ Lee KCL definiciones en memoria β”‚ β”‚ β”œβ”€ Valida esquemas β”‚ β”‚ └─ Serializa a JSON β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ JSON response con todos los servicios ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ syntaxis - ServiceRegistryClient β”‚ β”‚ β”œβ”€ Parsea response β”‚ β”‚ β”œβ”€ Valida tipos Rust β”‚ β”‚ └─ Usa servicios (generaciΓ³n, validaciΓ³n, etc) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ BENEFICIO: cambios en KCL reflejados automΓ‘ticamente SIN recompilaciΓ³n de syntaxis ``` ### 2. Flujo: Cambio en catalog KCL ``` 1. DevOps modifica provisioning/services.k └─ Agrega nuevo servicio o actualiza versiΓ³n 2. CI/CD pipeline: β”œβ”€ Carga KCL β”œβ”€ Ejecuta validaciones (policies.k) β”œβ”€ Si valid: commit + push └─ Si invalid: reject + notifica 3. provisioning/API server carga cambios: β”œβ”€ Detecta cambio en services.k β”œβ”€ Recompila KCL β†’ tipos Rust internos β”œβ”€ Valida con policies.k └─ Si valid: actualiza en memoria 4. Todos los consumidores obtienen nuevo catΓ‘logo: β”œβ”€ syntaxis: GET /api/v1/services β”œβ”€ Node.js app: GET /api/v1/services β”œβ”€ Python app: GET /api/v1/services └─ Dashboard: GET /api/v1/services BENEFICIO: cambio ΓΊnico, reflejado a todos SIN recompilaciΓ³n de ningΓΊn consumidor ``` ### 3. Flujo: GeneraciΓ³n de IaC para deployment ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DevOps quiere generar K8s manifest β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ POST /api/v1/generate { "pattern_id": "production", "formats": ["kubernetes"], "options": { "namespace": "prod", "registry": "docker.io" } } ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ API Handler (provisioning) β”‚ β”‚ β”œβ”€ Carga patrΓ³n "production" β”‚ β”‚ β”œβ”€ Obtiene servicios del patrΓ³n β”‚ β”‚ β”œβ”€ Genera K8s manifests con Tera β”‚ β”‚ └─ Valida YAML con esquemas K8s β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ Response con YAML generado ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DevOps β”‚ β”‚ β”œβ”€ Revisa YAML β”‚ β”‚ β”œβ”€ git commit + push β”‚ β”‚ └─ GitOps auto-deploys β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ BENEFICIO: generaciΓ³n basada en KCL SIN cΓ³digo Rust en el deployment ``` --- ## πŸ”„ Estrategia de MigraciΓ³n ### Fase 0: PreparaciΓ³n (1 semana) 1. Documentar estado actual (TOML catalog en syntaxis) 2. Crear KCL equivalente en provisioning 3. Implementar API REST gateway en provisioning 4. Crear clientes multi-lenguaje 5. Escribir tests de equivalencia TOML β†’ KCL ### Fase 1: Dual Mode (2 semanas) ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Ambos sistemas coexisten β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ syntaxis puede usar: β”‚ β”‚ β”œβ”€ TOML directo (legacy) β”‚ β”‚ └─ API REST (nuevo) β”‚ β”‚ β”‚ β”‚ Validar que dan mismo resultado β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Actividades**: - Executar tests comparativos - Validar outputs generados son idΓ©nticos - Medir performance (latencia API vs file read) - Documentar diferencias ### Fase 2: API Primary (1 semana) ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ syntaxis usa API por defecto β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”œβ”€ Fallback a TOML si API no disponible β”‚ └─ Deprecate TOML para prΓ³ximas versiones β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Actividades**: - Switch configuration en syntaxis - Implementar reconnection logic - Health check monitoring - Setup alerting ### Fase 3: Otros Consumidores (2 semanas) ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Otros servicios integrados β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”œβ”€ Node.js dashboard β†’ API REST β”‚ β”‚ β”œβ”€ Python tools β†’ API REST β”‚ β”‚ β”œβ”€ Go services β†’ API REST β”‚ β”‚ └─ External tools β†’ API REST β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Actividades**: - Integrar clientes en cada servicio - Test de carga (concurrent requests) - Implementar caching en clientes - Documentar integraciΓ³n ### Fase 4: DeprecaciΓ³n TOML (1 semana) ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ TOML es legacy, usar KCL β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”œβ”€ Remover cΓ³digo TOML de syntaxis β”‚ β”‚ β”œβ”€ Cleanup de archivos β”‚ β”‚ └─ Actualizar documentaciΓ³n β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## βš™οΈ Operaciones y Mantenimiento ### 1. Monitoreo ```rust // MΓ©tricas a monitorear - API Response Time (p50, p95, p99) - Request Rate (queries/sec) - Error Rate (4xx, 5xx counts) - KCL Compilation Time - Uptime - Cache Hit Ratio (si implementamos) ``` ### 2. Backup y Recovery ``` Daily: β”œβ”€ Backup KCL definitions β”œβ”€ Backup API configuration └─ Backup client libraries Recovery: β”œβ”€ RTO: < 1 hour β”œβ”€ RPO: < 5 minutes └─ Test quarterly ``` ### 3. Versionado ``` API: β”œβ”€ /api/v1/... (current) β”œβ”€ /api/v0/... (deprecated) └─ Supported versions: last 2 KCL: β”œβ”€ services.k (version managed) β”œβ”€ patterns.k (version managed) └─ Backward compatibility: 2 minor versions Clients: β”œβ”€ Semantic versioning β”œβ”€ Compatibility matrix documented └─ Auto-update via package managers ``` --- ## πŸ“Š Resumen de Beneficios | Aspecto | Antes (TOML) | DespuΓ©s (KCL + API) | |---------|--------------|-------------------| | **Source of Truth** | TOML en syntaxis | KCL en provisioning | | **RecompilaciΓ³n** | Requerida para cambios | NO requerida | | **Multi-lenguaje** | Requiere copiar archivos | REST API agnΓ³stica | | **ValidaciΓ³n** | Manual en Rust | AutomΓ‘tica en KCL | | **Cambios** | Lento (recompile + deploy) | RΓ‘pido (solo KCL edit) | | **Escalabilidad** | DifΓ­cil (mΓΊltiples copias) | FΓ‘cil (single source) | | **Observabilidad** | Limitada | Completa (API logs) | --- **Este documento proporciona el diseΓ±o detallado para implementar Option C (KCL + REST API). Los prΓ³ximos pasos serΓ­an:** 1. **Validar con el equipo** que este diseΓ±o responde las 4 preguntas crΓ­ticas 2. **Crear plan de implementaciΓ³n** basado en las 4 fases de migraciΓ³n 3. **Empezar con Fase 0** (preparaciΓ³n del equivalente KCL) 4. **Implementar API REST** en provisioning 5. **Migrar syntaxis** a usar API 6. **Onboard otros consumidores** (Node.js, Python, etc)