Skip to content

Arquitectura modular de SynVirt

Synced read-only from /home/synnet/mirrors/synvirt-product/docs/architecture-modules.md. Edit at the source, not here.

⚠️ Superseded / aspirational — does NOT match the repo (2026-06). The module-* crate names below were never built, and there is no Next.js web/ frontend: the dashboard is Vue 3.5 + Vite + TypeScript in crates/web-ux-v2 (canonical) and crates/web-ux (legacy), built by npm. The real workspace is 48 core / daemon / synvirt-* crates — see CLAUDE.md §2 for the catalog and docs/architecture/refactor-roadmap.md for the data-plane split. The domain-ownership principles here (one crate per domain, traits in core, no cross-module imports) still hold; the specific crate and frontend layout does not.

SynVirt está organizado como un workspace Rust con múltiples crates independientes en crates/, más un proyecto Next.js separado en web/.

  1. Un módulo Rust NUNCA importa otro módulo directamente
  2. Un módulo SOLO depende de synvirt-core y crates externos
  3. El daemon orquesta los módulos via traits definidos en core
  4. Cada módulo tiene su propio Cargo.toml, tests, y documentación
  5. La API pública de un módulo está en su lib.rs, lo demás es pub(crate)
  6. Los traits de cada módulo viven en crates/core/src/traits/
  7. El frontend Next.js NO está en el workspace Rust (vive en web/)
  8. El frontend habla con el daemon SOLO via HTTP en /api/v1/* y WS en /ws/*
  9. TODOS los strings visibles al usuario van por module-i18n (default: en-US)
  10. NUNCA hardcodear strings en daemon/installer/cli/frontend, siempre via i18n

crates/ ├── core/ Tipos, traits, errores compartidos ├── daemon/ API REST/WebSocket, orchestrator principal ├── agent/ Agente por nodo ├── cli/ Línea de comandos synvirt ├── installer/ TUI primer boot ├── module-storage/ ZFS local, LINSTOR (Hito 2 - pendiente) ├── module-network/ Bridges, OVN, firewall (Fase 2 - pendiente) ├── module-virt/ KVM, Cloud Hypervisor, QEMU (Hito 1 - pendiente) ├── module-cluster/ Membership, HA, etcd (Fase 2 - pendiente) ├── module-backup/ Snapshots, replicación, S3 (Fase 1 - pendiente) ├── module-catalog/ Catálogo ISOs y plantillas (Fase 1 - pendiente) ├── module-monitor/ Métricas, eventos, alertas (Fase 1 - pendiente) ├── module-auth/ Usuarios, RBAC, sesiones (Fase 1 - pendiente) ├── module-license/ Validación de licencia (Fase 1 - pendiente) ├── module-migrator/ Importar VMs de otras plataformas (Fase 1 - pendiente) ├── module-ai/ Pool GPU, modelos LLM, API compatible OpenAI (Fase 1 - pendiente) ├── module-update/ Updates kernel, security, módulos, lang packs (Fase 1 - pendiente) └── module-i18n/ Traducciones para todos los componentes (Fase 1 - pendiente)

web/ Proyecto Next.js independiente

Build pipeline frontend:

  • Dev: npm run dev en :3000, proxy a daemon en :8443
  • Prod: npm run build genera web/out/ (static)
  • iso-builder/build.sh copia web/out/* a overlay del daemon
  • Daemon sirve los archivos estáticos en runtime
  • Frontend pide traducciones al daemon en runtime via /api/v1/i18n

✓ daemon → core, module-* ✓ agent → core, module-* ✓ installer → core, module-i18n ✓ cli → core, module-i18n ✓ module-X → core, crates externos ✗ module-X → module-Y (PROHIBIDO, excepción: i18n permitido para textos) ✗ module-X → daemon (PROHIBIDO) ✗ web → cualquier crate Rust (solo HTTP/WebSocket)

  1. cargo new –lib crates/module-NOMBRE
  2. Definir trait en crates/core/src/traits/NOMBRE.rs
  3. Implementar trait en crates/module-NOMBRE/src/lib.rs
  4. Agregar al workspace Cargo.toml
  5. Daemon importa el trait y wire-up de la implementación
  6. Documentar en docs/modules/NOMBRE.md
  7. ADR en docs/decisions/ si la decisión es no trivial
  8. Agregar strings del módulo en crates/module-i18n/locales/en-US/NOMBRE.ftl

Como los módulos no se conocen entre sí, puedes reemplazar module-storage (LINSTOR) por module-storage-ceph en v2.0 sin tocar nada más. Solo cambias en el daemon qué implementación del trait se inyecta.