provisioning/assets/web/_index.html
2026-05-12 02:53:57 +01:00

1394 lines
59 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title
data-en="Provisioning - Infrastructure Orchestration Platform"
data-es="Provisioning - Plataforma de Orquestación de Infraestructura"
>
Provisioning
</title>
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700;800&display=swap"
rel="stylesheet"
/>
<style>
:root {
--bg-primary: #0a0118;
--bg-secondary: rgba(255, 255, 255, 0.03);
--text-primary: #ffffff;
--text-secondary: #cbd5e1;
--text-muted: #94a3b8;
--border-color: rgba(16, 185, 129, 0.3);
--border-color-light: rgba(59, 130, 246, 0.3);
--accent-green: #10b981;
--accent-blue: #3b82f6;
--accent-purple: #8b5cf6;
--card-bg: rgba(255, 255, 255, 0.03);
--card-border: rgba(59, 130, 246, 0.3);
--highlight-color: #10b981;
--footer-text: #64748b;
}
html.light-mode {
--bg-primary: #f3f4f6;
--bg-secondary: rgba(0, 0, 0, 0.02);
--text-primary: #111827;
--text-secondary: #374151;
--text-muted: #6b7280;
--border-color: rgba(16, 185, 129, 0.4);
--border-color-light: rgba(59, 130, 246, 0.4);
--accent-green: #059669;
--accent-blue: #2563eb;
--accent-purple: #7c3aed;
--card-bg: rgba(0, 0, 0, 0.02);
--card-border: rgba(59, 130, 246, 0.3);
--highlight-color: #059669;
--footer-text: #4b5563;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "JetBrains Mono", monospace;
background: var(--bg-primary);
color: var(--text-primary);
overflow-x: hidden;
transition:
background-color 0.3s ease,
color 0.3s ease;
}
.gradient-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
background:
radial-gradient(
circle at 20% 50%,
var(--accent-blue) 0%,
transparent 50%
),
radial-gradient(
circle at 80% 80%,
var(--accent-green) 0%,
transparent 50%
),
radial-gradient(
circle at 40% 90%,
var(--accent-purple) 0%,
transparent 50%
);
opacity: 0.15;
}
.language-toggle {
position: fixed;
top: 2rem;
right: 2rem;
z-index: 100;
display: flex;
gap: 0.5rem;
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 20px;
padding: 0.3rem 0.3rem;
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
.lang-btn {
background: transparent;
border: none;
color: var(--text-muted);
padding: 0.5rem 1rem;
border-radius: 18px;
cursor: pointer;
font-weight: 700;
font-size: 0.85rem;
text-transform: uppercase;
transition: all 0.3s ease;
font-family: "JetBrains Mono", monospace;
}
.lang-btn.active {
background: linear-gradient(135deg, #10b981 0%, #3b82f6 100%);
color: #fff;
}
.lang-btn:hover {
color: var(--highlight-color);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
position: relative;
}
header {
text-align: center;
padding: 5rem 0 2rem;
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.status-badge {
display: inline-block;
background: rgba(16, 185, 129, 0.2);
border: 1px solid #10b981;
color: #10b981;
padding: 0.5rem 1.5rem;
border-radius: 50px;
font-size: 0.85rem;
font-weight: 700;
margin-bottom: 1.5rem;
}
.logo-container {
margin-bottom: 2rem;
}
.logo-container img {
max-width: 440px;
width: 100%;
height: auto;
filter: drop-shadow(0 0 30px rgba(16, 185, 129, 0.4));
}
.tagline {
font-size: 0.95rem;
color: #10b981;
font-weight: 400;
letter-spacing: 0.1em;
text-transform: uppercase;
margin-bottom: 1rem;
}
h1 {
font-size: 2.8rem;
font-weight: 800;
line-height: 1.2;
margin-bottom: 1.5rem;
background: linear-gradient(
135deg,
#10b981 0%,
#3b82f6 50%,
#8b5cf6 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.15rem;
color: var(--text-secondary);
max-width: 800px;
margin: 0 auto 2rem;
line-height: 1.8;
}
.highlight {
color: var(--highlight-color);
font-weight: 700;
}
.section {
margin: 4rem 0;
animation: fadeInUp 0.8s ease-out;
}
.section-0 {
margin: 0.2rem 0;
}
.section-title {
font-size: 2rem;
font-weight: 800;
margin-bottom: 2rem;
color: #10b981;
text-align: center;
}
.section-title span {
background: linear-gradient(135deg, #8b5cf6 0%, #3b82f6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.problems-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.problem-card {
background: var(--card-bg);
border: 1px solid var(--border-color-light);
border-radius: 12px;
padding: 2rem;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.problem-card:hover {
transform: translateY(-5px);
background: rgba(255, 255, 255, 0.05);
border-color: rgba(16, 185, 129, 0.5);
}
.problem-number {
font-size: 2rem;
font-weight: 800;
background: linear-gradient(135deg, #10b981 0%, #3b82f6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 0.5rem;
}
.problem-card h3 {
color: #8b5cf6;
font-size: 1.05rem;
margin-bottom: 0.7rem;
font-weight: 700;
}
.problem-card p {
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.6;
}
.tech-stack {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 2rem;
justify-content: center;
}
.tech-badge {
background: rgba(16, 185, 129, 0.15);
border: 1px solid #10b981;
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.8rem;
color: #10b981;
font-weight: 700;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-top: 2rem;
}
.feature-box {
background: linear-gradient(
135deg,
rgba(16, 185, 129, 0.1) 0%,
rgba(59, 130, 246, 0.1) 100%
);
border-radius: 12px;
padding: 2rem;
border-left: 4px solid #10b981;
transition: all 0.3s ease;
}
.feature-box:hover {
background: linear-gradient(
135deg,
rgba(16, 185, 129, 0.15) 0%,
rgba(59, 130, 246, 0.15) 100%
);
transform: translateY(-3px);
}
.feature-icon {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.feature-title {
font-size: 1.15rem;
font-weight: 700;
color: #10b981;
margin-bottom: 0.7rem;
}
.feature-text {
color: var(--text-secondary);
font-size: 0.95rem;
line-height: 1.7;
}
.components-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
margin-top: 2rem;
}
.component-item {
background: rgba(139, 92, 246, 0.1);
padding: 1.2rem;
border-radius: 8px;
font-size: 0.9rem;
border: 1px solid rgba(139, 92, 246, 0.3);
transition: all 0.2s ease;
text-align: center;
}
.component-item:hover {
background: rgba(139, 92, 246, 0.15);
transform: translateY(-2px);
}
.component-name {
color: #8b5cf6;
font-weight: 700;
display: block;
margin-bottom: 0.3rem;
}
.component-role {
color: var(--text-muted);
font-size: 0.85rem;
}
.cta-section {
text-align: center;
margin: 5rem 0 3rem;
padding: 4rem 2rem;
background: linear-gradient(
135deg,
rgba(16, 185, 129, 0.1) 0%,
rgba(139, 92, 246, 0.1) 100%
);
border-radius: 20px;
border: 1px solid rgba(59, 130, 246, 0.3);
}
.cta-title {
font-size: 2rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #10b981 0%, #8b5cf6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.cta-button {
display: inline-block;
background: linear-gradient(
135deg,
#10b981 0%,
#3b82f6 50%,
#8b5cf6 100%
);
color: #fff;
padding: 1.1rem 2.8rem;
border-radius: 50px;
text-decoration: none;
font-weight: 800;
font-size: 1rem;
transition: all 0.3s ease;
box-shadow: 0 10px 30px rgba(16, 185, 129, 0.3);
text-transform: uppercase;
letter-spacing: 0.05em;
border: none;
cursor: pointer;
}
.cta-button:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 20px 50px rgba(16, 185, 129, 0.5);
}
footer {
text-align: center;
padding: 3rem 0 2rem;
color: var(--footer-text);
border-top: 1px solid var(--border-color);
margin-top: 4rem;
font-size: 0.9rem;
}
footer p:first-child {
font-weight: 700;
color: #94a3b8;
}
footer p:last-child {
margin-top: 0.5rem;
font-size: 0.85rem;
}
.hidden {
display: none;
}
.theme-toggle {
background: transparent;
border: none;
color: var(--text-muted);
padding: 0.5rem 1rem;
border-radius: 18px;
cursor: pointer;
font-weight: 700;
font-size: 1.2rem;
transition: all 0.3s ease;
}
.theme-toggle:hover {
color: var(--accent-green);
}
.repo-link {
display: inline-block;
margin-top: 0.6rem;
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
font-weight: 700;
color: var(--accent-green);
text-decoration: none;
opacity: 0.75;
letter-spacing: 0.03em;
transition: opacity 0.2s ease;
}
.repo-link:hover {
opacity: 1;
}
.component-link {
color: inherit;
text-decoration: none;
}
.component-link:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
.arch-preview {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
}
.arch-img-link {
display: block;
width: 100%;
max-width: 820px;
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border-color);
transition: all 0.3s ease;
cursor: pointer;
}
.arch-img-link:hover {
border-color: rgba(16, 185, 129, 0.6);
box-shadow: 0 8px 32px rgba(16, 185, 129, 0.15);
transform: translateY(-2px);
}
.arch-img {
display: block;
width: 100%;
height: auto;
}
html.light-mode .arch-dark { display: none; }
html:not(.light-mode) .arch-light { display: none; }
.arch-btn {
display: inline-block;
border: 2px solid #10b981;
color: #10b981;
padding: 0.9rem 2.4rem;
border-radius: 50px;
text-decoration: none;
font-weight: 800;
font-size: 0.95rem;
font-family: "JetBrains Mono", monospace;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.arch-btn:hover {
background: #10b981;
color: #fff;
box-shadow: 0 10px 30px rgba(16, 185, 129, 0.3);
transform: translateY(-2px);
}
@media (max-width: 768px) {
h1 {
font-size: 2rem;
}
.hero-subtitle {
font-size: 1rem;
}
.logo-container img {
max-width: 352px;
}
.section-title {
font-size: 1.6rem;
}
.cta-title {
font-size: 1.6rem;
}
.language-toggle {
top: 1rem;
right: 1rem;
}
}
</style>
</head>
<body>
<div class="gradient-bg"></div>
<div class="language-toggle">
<button
class="lang-btn active"
data-lang="en"
onclick="switchLanguage('en')"
>
EN
</button>
<button
class="lang-btn"
data-lang="es"
onclick="switchLanguage('es')"
>
ES
</button>
<button
class="theme-toggle"
onclick="toggleTheme()"
title="Toggle light/dark mode"
>
<span id="theme-icon">🌙</span>
</button>
<a
href="architecture-diagram.html"
class="lang-btn"
style="
text-decoration: none;
background: rgba(16, 185, 129, 0.2);
border: 1px solid rgba(16, 185, 129, 0.5);
cursor: pointer;
"
>
🏗️ ARCHITECTURE
</a>
</div>
<div class="container">
<header>
<span
class="status-badge"
style="display: none"
data-en="✅ v3.0.11 | Production Ready"
data-es="✅ v3.0.11 | Listo para Producción"
>✅ v3.0.11 | Production Ready</span
>
<div class="logo-container">
<img
src="provisioning.svg"
alt="Provisioning Logo"
width="300"
/>
</div>
<div class="logo-container">
<img src="logo-text.svg" alt="Provisioning" width="500" />
</div>
<p class="tagline">Provision at Scale</p>
<h1
data-en="Infrastructure Orchestration<br>With Configuration as Code"
data-es="Orquestación de Infraestructura<br>Con Configuración como Código"
>
Infrastructure Orchestration
</h1>
<p class="hero-subtitle">
<span
class="highlight"
data-en="Declarative infrastructure"
data-es="Infraestructura declarativa"
>Declarative infrastructure
</span>
<span
data-en=" management with Nickel schemas, Nushell orchestration, and Rust executables. Type-safe configuration, automated validation, and cloud-native deployment across Kubernetes, Docker, and custom platforms."
data-es=" management con esquemas Nickel, orquestación Nushell y ejecutables Rust. Configuración type-safe, validación automática y despliegue cloud-native en Kubernetes, Docker y plataformas personalizadas."
>management with Nickel schemas, Nushell orchestration,
and Rust executables. Type-safe configuration, automated
validation, and cloud-native deployment across
Kubernetes, Docker, and custom platforms.
</span>
<br /><span
><strong
data-en="100% infrastructure as code."
data-es="100% infraestructura como código."
>100% infrastructure as code.</strong
>
</span>
</p>
</header>
<section class="section-0">
<h2 class="section-title">
<span
data-en="Core Capabilities"
data-es="Capacidades Principales"
>Core Capabilities</span
>
</h2>
<div class="problems-grid">
<div class="problem-card">
<div class="problem-number">01</div>
<h3
data-en="Type-Safe Configuration"
data-es="Configuración Type-Safe"
>
Type-Safe Configuration
</h3>
<p
data-en="Nickel provides formal type checking, automated validation, and recursive merging for infrastructure definitions. Eliminate configuration drift and parsing errors."
data-es="Nickel proporciona verificación formal de tipos, validación automática y fusión recursiva para definiciones de infraestructura. Elimina desviación de configuración y errores de análisis."
>
Nickel provides formal type checking, automated
validation, and recursive merging for infrastructure
definitions. Eliminate configuration drift and
parsing errors.
</p>
</div>
<div class="problem-card">
<div class="problem-number">02</div>
<h3
data-en="Intelligent Orchestration"
data-es="Orquestación Inteligente"
>
Intelligent Orchestration
</h3>
<p
data-en="Nushell scripts orchestrate complex deployment workflows with structured data pipelines, state management, and error recovery. Built-in type system prevents runtime failures."
data-es="Los scripts Nushell orquestan flujos de despliegue complejos con canales de datos estructurados, gestión de estado y recuperación de errores. Sistema de tipos incorporado previene fallos en tiempo de ejecución."
>
Nushell scripts orchestrate complex deployment
workflows with structured data pipelines, state
management, and error recovery. Built-in type system
prevents runtime failures.
</p>
</div>
<div class="problem-card">
<div class="problem-number">03</div>
<h3
data-en="Multi-Platform Support"
data-es="Soporte Multi-Plataforma"
>
Multi-Platform Support
</h3>
<p
data-en="Deploy to Kubernetes, Docker Compose, local VMs, and custom infrastructure. Unified interface with platform-specific overrides and workspace isolation."
data-es="Despliegua en Kubernetes, Docker Compose, máquinas virtuales locales e infraestructura personalizada. Interfaz unificada con sobrescrituras específicas de plataforma y aislamiento de espacios de trabajo."
>
Deploy to Kubernetes, Docker Compose, local VMs, and
custom infrastructure. Unified interface with
platform-specific overrides and workspace isolation.
</p>
</div>
<div class="problem-card">
<div class="problem-number">04</div>
<h3
data-en="Version Control Ready"
data-es="Listo para Control de Versiones"
>
Version Control Ready
</h3>
<p
data-en="All infrastructure lives in Git. Configuration schemas, Nickel modules, and Nushell scripts are versionable, reviewable, and rollbackable."
data-es="Toda la infraestructura vive en Git. Los esquemas de configuración, módulos Nickel y scripts Nushell son versionables, revisables y reversibles."
>
All infrastructure lives in Git. Configuration
schemas, Nickel modules, and Nushell scripts are
versionable, reviewable, and rollbackable.
</p>
</div>
</div>
</section>
<section class="section">
<h2 class="section-title">
<span data-en="How It Works" data-es="Cómo Funciona"
>How It Works</span
>
</h2>
<div class="features-grid">
<div class="feature-box">
<div class="feature-icon">📝</div>
<h3
class="feature-title"
data-en="Define with Nickel"
data-es="Definir con Nickel"
>
Define with Nickel
</h3>
<p
class="feature-text"
data-en="Write declarative infrastructure schemas with full type safety. Nickel's lazy evaluation and recursive merging enable powerful abstractions and configuration composition."
data-es="Escriba esquemas de infraestructura declarativos con seguridad de tipos completa. La evaluación perezosa de Nickel y la fusión recursiva permiten abstracciones poderosas y composición de configuración."
>
Write declarative infrastructure schemas with full
type safety. Nickel's lazy evaluation and recursive
merging enable powerful abstractions and
configuration composition.
</p>
<a
href="https://repo.jesusperez.pro/jesus/TypeDialog"
target="_blank"
class="repo-link"
>→ Easy config via TypeDialog</a
>
</div>
<div class="feature-box" style="border-left-color: #3b82f6">
<div class="feature-icon">🔄</div>
<h3
class="feature-title"
style="color: #3b82f6"
data-en="Orchestrate with Nushell"
data-es="Orquestar con Nushell"
>
Orchestrate with Nushell
</h3>
<p
class="feature-text"
data-en="Structured data pipelines, type-safe operations, and stateful workflows. Nushell eliminates shell script fragility while maintaining scripting simplicity."
data-es="Canales de datos estructurados, operaciones type-safe y flujos de trabajo con estado. Nushell elimina la fragilidad de los scripts de shell manteniendo la simplicidad de los scripts."
>
Structured data pipelines, type-safe operations, and
stateful workflows. Nushell eliminates shell script
fragility while maintaining scripting simplicity.
</p>
<a
href="https://repo.jesusperez.pro/jesus/nushell-plugins"
target="_blank"
class="repo-link"
style="color: #3b82f6"
>→ Nushell plugins added</a
>
</div>
<div class="feature-box" style="border-left-color: #8b5cf6">
<div class="feature-icon"></div>
<h3
class="feature-title"
style="color: #8b5cf6"
data-en="Execute with Rust"
data-es="Ejecutar con Rust"
>
Execute with Rust
</h3>
<p
class="feature-text"
data-en="Performance-critical operations backed by Rust. Zero-cost abstractions, memory safety, and fearless concurrency for infrastructure tooling."
data-es="Operaciones críticas de rendimiento respaldadas por Rust. Abstracciones de costo cero, seguridad de memoria y concurrencia sin miedo para herramientas de infraestructura."
>
Performance-critical operations backed by Rust.
Zero-cost abstractions, memory safety, and fearless
concurrency for infrastructure tooling.
</p>
</div>
<div class="feature-box" style="border-left-color: #f59e0b">
<div class="feature-icon">📡</div>
<h3
class="feature-title"
style="color: #f59e0b"
data-en="Coordinate via NATS JetStream"
data-es="Coordinar via NATS JetStream"
>
Coordinate via NATS JetStream
</h3>
<p
class="feature-text"
data-en="Persistent event bus for decoupled service coordination. Services exchange lease_id, task_id, and status events — credentials never traverse the bus. Auditable, replay-capable, at-least-once delivery."
data-es="Bus de eventos persistente para coordinación desacoplada. Los servicios intercambian lease_id, task_id y eventos de estado — las credenciales nunca atraviesan el bus. Auditable, con capacidad de replay y entrega at-least-once."
>
Persistent event bus for decoupled service
coordination. Services exchange lease_id, task_id,
and status events — credentials never traverse the
bus. Auditable, replay-capable, at-least-once
delivery.
</p>
</div>
<div class="feature-box" style="border-left-color: #a78bfa">
<div class="feature-icon">🔐</div>
<h3
class="feature-title"
style="color: #a78bfa"
data-en="Secure end-to-end"
data-es="Seguridad extremo a extremo"
>
Secure end-to-end
</h3>
<p
class="feature-text"
data-en="Cedar policy-as-code for authorization, JWT sessions managed exclusively by ControlCenter, and post-quantum cryptography via SecretumVault. Credentials never leave the vault — services operate on lease references only."
data-es="Cedar como código de autorización, sesiones JWT gestionadas exclusivamente por ControlCenter y criptografía post-cuántica via SecretumVault. Las credenciales nunca salen del vault — los servicios operan solo con referencias de lease."
>
Cedar policy-as-code for authorization, JWT sessions
managed exclusively by ControlCenter, and
post-quantum cryptography via SecretumVault.
Credentials never leave the vault — services operate
on lease references only.
</p>
<a
href="https://repo.jesusperez.pro/jesus/secretumvault"
target="_blank"
class="repo-link"
style="color: #a78bfa"
>→ SecretumVault repo</a
>
</div>
<div class="feature-box" style="border-left-color: #ec4899">
<div class="feature-icon">🧩</div>
<h3
class="feature-title"
style="color: #ec4899"
data-en="Extend via OCI Registry"
data-es="Extender via OCI Registry"
>
Extend via OCI Registry
</h3>
<p
class="feature-text"
data-en="Distribute custom providers, task services, and cluster definitions as OCI artifacts. The Extension Registry catalogs and versions capabilities independently — swap or compose providers without touching core platform code."
data-es="Distribuye proveedores, task services y definiciones de clúster personalizados como artefactos OCI. El Extension Registry cataloga y versiona capacidades de forma independiente — intercambia o compone proveedores sin tocar el código del núcleo."
>
Distribute custom providers, task services, and
cluster definitions as OCI artifacts. The Extension
Registry catalogs and versions capabilities
independently — swap or compose providers without
touching core platform code.
</p>
<a
href="https://repo.jesusperez.pro/jesus/prvng_extensions"
target="_blank"
class="repo-link"
style="color: #ec4899"
>→ Provisioning Extensions</a
>
</div>
<div class="feature-box" style="border-left-color: #06b6d4">
<div class="feature-icon">🎛️</div>
<h3
class="feature-title"
style="color: #06b6d4"
data-en="Platform CLI &amp; External Services"
data-es="CLI de Plataforma y Servicios Externos"
>
Platform CLI &amp; External Services
</h3>
<p
class="feature-text"
data-en="8 platform subcommands (list, status, health, check, config, connections, init, start) with declarative external service management. Validates SurrealDB, OCI registries (Zot/Harbor), Git sources (Forgejo/Gitea), and cache before startup."
data-es="8 subcomandos de plataforma (list, status, health, check, config, connections, init, start) con gestión declarativa de servicios externos. Valida SurrealDB, registros OCI (Zot/Harbor), fuentes Git (Forgejo/Gitea) y caché antes del arranque."
>
8 platform subcommands (list, status, health, check,
config, connections, init, start) with declarative
external service management. Validates SurrealDB, OCI
registries (Zot/Harbor), Git sources (Forgejo/Gitea),
and cache before startup.
</p>
</div>
<div class="feature-box" style="border-left-color: #14b8a6">
<div class="feature-icon">📌</div>
<h3
class="feature-title"
style="color: #14b8a6"
data-en="Centralized Version Management"
data-es="Gestión Centralizada de Versiones"
>
Centralized Version Management
</h3>
<p
class="feature-text"
data-en="All tool and provider versions defined in Nickel schemas. Generates bash-compatible exports via 'provisioning setup versions'. Automatic provider discovery, shell script integration, and single source of truth for Nushell, Nickel, SOPS, Age, AWS CLI, and all providers."
data-es="Todas las versiones de herramientas y proveedores definidas en esquemas Nickel. Genera exportaciones compatibles con bash via 'provisioning setup versions'. Descubrimiento automático de proveedores, integración con scripts shell y fuente única de verdad para Nushell, Nickel, SOPS, Age, AWS CLI y todos los proveedores."
>
All tool and provider versions defined in Nickel
schemas. Generates bash-compatible exports via
&lsquo;provisioning setup versions&rsquo;. Automatic
provider discovery, shell script integration, and
single source of truth for Nushell, Nickel, SOPS,
Age, AWS CLI, and all providers.
</p>
</div>
</div>
</section>
<section class="section">
<h2 class="section-title">
<span
data-en="SOLID Architecture Boundaries"
data-es="Límites de Arquitectura SOLID"
>SOLID Architecture Boundaries</span
>
</h2>
<div class="features-grid">
<div class="feature-box" style="border-left-color: #ef4444">
<div class="feature-icon">🎯</div>
<h3
class="feature-title"
style="color: #ef4444"
data-en="Provider APIs — Orchestrator only"
data-es="APIs de Proveedor — solo Orchestrator"
>
Provider APIs — Orchestrator only
</h3>
<p
class="feature-text"
data-en="All hcloud, AWS, and provider SDK calls are isolated to the Orchestrator crate. Every other service routes through the Orchestrator HTTP API. SSH operations share this same boundary."
data-es="Todas las llamadas a hcloud, AWS y SDKs de proveedor están aisladas en el crate Orchestrator. Todos los demás servicios enrutan a través de la API HTTP del Orchestrator. Las operaciones SSH comparten este mismo límite."
>
All hcloud, AWS, and provider SDK calls are isolated
to the Orchestrator crate. Every other service routes
through the Orchestrator HTTP API. SSH operations
share this same boundary.
</p>
</div>
<div class="feature-box" style="border-left-color: #ec4899">
<div class="feature-icon">🔐</div>
<h3
class="feature-title"
style="color: #ec4899"
data-en="Auth decisions — ControlCenter only"
data-es="Decisiones de Auth — solo ControlCenter"
>
Auth decisions — ControlCenter only
</h3>
<p
class="feature-text"
data-en="JWT validation and Cedar policy evaluation happen exclusively in ControlCenter. Other services receive a UserContext via middleware — no service re-validates tokens or evaluates policies directly."
data-es="La validación JWT y la evaluación de políticas Cedar ocurren exclusivamente en ControlCenter. Los demás servicios reciben un UserContext via middleware — ningún servicio re-valida tokens ni evalúa políticas directamente."
>
JWT validation and Cedar policy evaluation happen
exclusively in ControlCenter. Other services receive
a UserContext via middleware — no service re-validates
tokens or evaluates policies directly.
</p>
</div>
<div class="feature-box" style="border-left-color: #f59e0b">
<div class="feature-icon">🔑</div>
<h3
class="feature-title"
style="color: #f59e0b"
data-en="Secrets — Vault Service API only"
data-es="Secretos — solo API del Vault Service"
>
Secrets — Vault Service API only
</h3>
<p
class="feature-text"
data-en="Credentials are never stored in NATS messages or environment variables. Services hold a lease_id and retrieve actual secrets via HTTPS to the Vault Service. The bus carries references, not values."
data-es="Las credenciales nunca se almacenan en mensajes NATS ni variables de entorno. Los servicios mantienen un lease_id y recuperan los secretos reales vía HTTPS al Vault Service. El bus transporta referencias, no valores."
>
Credentials are never stored in NATS messages or
environment variables. Services hold a lease_id and
retrieve actual secrets via HTTPS to the Vault
Service. The bus carries references, not values.
</p>
</div>
</div>
</section>
<section class="section">
<h2 class="section-title">
<span
data-en="System Architecture"
data-es="Arquitectura del Sistema"
>System Architecture</span
>
</h2>
<div class="arch-preview">
<a href="architecture-diagram.html" class="arch-img-link">
<img
class="arch-img arch-dark"
src="arch-diag-v2.svg"
alt="Architecture Diagram"
/>
<img
class="arch-img arch-light"
src="w-arch-diag-v2.svg"
alt="Architecture Diagram"
/>
</a>
<a
href="architecture-diagram.html"
class="arch-btn"
data-en="Explore Architecture →"
data-es="Explorar Arquitectura →"
>Explore Architecture →</a
>
</div>
</section>
<section class="section">
<h2 class="section-title">
<span data-en="Technology Stack" data-es="Stack Tecnológico"
>Technology Stack</span
>
</h2>
<div class="tech-stack">
<span class="tech-badge">Nickel</span>
<span class="tech-badge">Nushell 0.110</span>
<span class="tech-badge">Rust</span>
<span class="tech-badge">NATS JetStream</span>
<span class="tech-badge">SurrealDB</span>
<span class="tech-badge">Cedar</span>
<span class="tech-badge">Leptos WASM</span>
<span class="tech-badge">Kubernetes</span>
<span class="tech-badge">Docker Compose</span>
<span class="tech-badge">SOPS 3.10</span>
<span class="tech-badge">Age 1.2</span>
<span class="tech-badge">Git</span>
</div>
</section>
<section class="section">
<h2 class="section-title">
<span
data-en="Platform Services (13)"
data-es="Servicios de Plataforma (13)"
>Platform Services (13)</span
>
</h2>
<div class="components-grid">
<div class="component-item">
<span
class="component-name"
data-en="Orchestrator"
data-es="Orchestrator"
>Orchestrator</span
><span
class="component-role"
data-en="Provider APIs + SSH boundary"
data-es="APIs de proveedor + límite SSH"
>Provider APIs + SSH boundary</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="ControlCenter"
data-es="ControlCenter"
>ControlCenter</span
><span
class="component-role"
data-en="Cedar auth boundary"
data-es="Límite auth Cedar"
>Cedar auth boundary</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="ControlCenter-UI"
data-es="ControlCenter-UI"
>ControlCenter-UI</span
><span
class="component-role"
data-en="Leptos WASM dashboard"
data-es="Dashboard Leptos WASM"
>Leptos WASM dashboard</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="MCP-Server"
data-es="MCP-Server"
>MCP-Server</span
><span
class="component-role"
data-en="RAG + AI tools"
data-es="RAG + Herramientas IA"
>RAG + AI tools</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="AI-Service"
data-es="AI-Service"
>AI-Service</span
><span
class="component-role"
data-en="LLM inference layer"
data-es="Capa inferencia LLM"
>LLM inference layer</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Extension-Registry"
data-es="Extension-Registry"
>Extension-Registry</span
><span
class="component-role"
data-en="Extension catalog"
data-es="Catálogo de extensiones"
>Extension catalog</span
>
</div>
<div class="component-item">
<span class="component-name"
><a
href="https://repo.jesusperez.pro/jesus/secretumvault"
target="_blank"
class="component-link"
>SecretumVault</a
></span
><span
class="component-role"
data-en="PQC secrets API"
data-es="API de secretos PQC"
>PQC secrets API</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Detector"
data-es="Detector"
>Detector</span
><span
class="component-role"
data-en="Event detection"
data-es="Detección de eventos"
>Event detection</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Daemon-CLI"
data-es="Daemon-CLI"
>Daemon-CLI</span
><span
class="component-role"
data-en="Service lifecycle"
data-es="Ciclo de vida de servicios"
>Service lifecycle</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Machines"
data-es="Machines"
>Machines</span
><span
class="component-role"
data-en="Machine management"
data-es="Gestión de máquinas"
>Machine management</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Observability"
data-es="Observability"
>Observability</span
><span
class="component-role"
data-en="Prometheus metrics"
data-es="Métricas Prometheus"
>Prometheus metrics</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Backup"
data-es="Backup"
>Backup</span
><span
class="component-role"
data-en="State backup"
data-es="Backup de estado"
>State backup</span
>
</div>
<div class="component-item">
<span
class="component-name"
data-en="Encrypt"
data-es="Encrypt"
>Encrypt</span
><span
class="component-role"
data-en="Key operations"
data-es="Operaciones de clave"
>Key operations</span
>
</div>
</div>
</section>
<div class="cta-section">
<h2
class="cta-title"
data-en="Ready for infrastructure automation?"
data-es="¿Listo para la automatización de infraestructura?"
>
Ready for infrastructure automation?
</h2>
<p
style="
color: #94a3b8;
margin-bottom: 2rem;
font-size: 1.05rem;
"
data-en="Built with Nickel & Nushell | Rust | Type-Safe | Open Source"
data-es="Construido con Nickel y Nushell | Rust | Type-Safe | Open Source"
>
Built with Nickel & Nushell | Type-Safe | Open Source
</p>
<a
href="https://repo.jesusperez.pro/jesus/provisioning"
class="cta-button"
data-en="Explore Git Repo →"
data-es="Explorar Repo Git →"
>Explore Git Repo →</a
>
</div>
<footer>
<p
data-en="Provisioning v3.0.11"
data-es="Provisioning v3.0.11"
>
Provisioning v3.0.11
</p>
<p
data-en="Infrastructure orchestration made elegant and type-safe ✨"
data-es="Orquestación de infraestructura hecha elegante y type-safe ✨"
>
Infrastructure orchestration made elegant and type-safe ✨
</p>
<p
style="margin-top: 1rem; font-size: 0.8rem"
data-en="Configuration as Code | Multi-Platform | Cloud-Native"
data-es="Configuración como Código | Multi-Plataforma | Cloud-Native"
>
Configuration as Code | Multi-Platform | Cloud-Native
</p>
</footer>
</div>
<script>
// Language management
const LANG_KEY = "provisioning-lang";
function getCurrentLanguage() {
return localStorage.getItem(LANG_KEY) || "en";
}
function switchLanguage(lang) {
localStorage.setItem(LANG_KEY, lang);
// Update language buttons
document.querySelectorAll(".lang-btn").forEach((btn) => {
btn.classList.remove("active");
if (btn.dataset.lang === lang) {
btn.classList.add("active");
}
});
// Update all translatable elements
document
.querySelectorAll("[data-en][data-es]")
.forEach((el) => {
const content = el.dataset[lang];
// Use innerHTML for headings that might contain <br>, textContent for others
if (
el.tagName === "H1" ||
el.tagName === "H2" ||
el.tagName === "H3"
) {
el.innerHTML = content;
} else {
el.textContent = content;
}
});
document.documentElement.lang = lang;
}
// Initialize language on page load
document.addEventListener("DOMContentLoaded", () => {
const currentLang = getCurrentLanguage();
switchLanguage(currentLang);
const currentTheme = getTheme();
setTheme(currentTheme);
});
// Theme management
const THEME_KEY = "provisioning-theme";
function getTheme() {
return localStorage.getItem(THEME_KEY) || "dark";
}
function setTheme(theme) {
localStorage.setItem(THEME_KEY, theme);
const html = document.documentElement;
const icon = document.getElementById("theme-icon");
if (theme === "light") {
html.classList.add("light-mode");
icon.textContent = "☀️";
} else {
html.classList.remove("light-mode");
icon.textContent = "🌙";
}
}
function toggleTheme() {
const currentTheme = getTheme();
const newTheme = currentTheme === "dark" ? "light" : "dark";
setTheme(newTheme);
}
</script>
</body>
</html>