Arquitectura modular de SynVirt
Synced read-only from
/home/synnet/mirrors/synvirt-product/docs/architecture-modules.md. Edit at the source, not here.
Arquitectura modular de SynVirt
Section titled “Arquitectura modular de SynVirt”⚠️ Superseded / aspirational — does NOT match the repo (2026-06). The
module-*crate names below were never built, and there is no Next.jsweb/frontend: the dashboard is Vue 3.5 + Vite + TypeScript incrates/web-ux-v2(canonical) andcrates/web-ux(legacy), built by npm. The real workspace is 48core/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 incore, 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/.
Reglas no negociables
Section titled “Reglas no negociables”- Un módulo Rust NUNCA importa otro módulo directamente
- Un módulo SOLO depende de synvirt-core y crates externos
- El daemon orquesta los módulos via traits definidos en core
- Cada módulo tiene su propio Cargo.toml, tests, y documentación
- La API pública de un módulo está en su lib.rs, lo demás es pub(crate)
- Los traits de cada módulo viven en crates/core/src/traits/
- El frontend Next.js NO está en el workspace Rust (vive en web/)
- El frontend habla con el daemon SOLO via HTTP en /api/v1/* y WS en /ws/*
- TODOS los strings visibles al usuario van por module-i18n (default: en-US)
- NUNCA hardcodear strings en daemon/installer/cli/frontend, siempre via i18n
Estructura del workspace Rust
Section titled “Estructura del workspace Rust”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)
Frontend separado
Section titled “Frontend separado”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
Dependencias permitidas
Section titled “Dependencias permitidas”✓ 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)
Cómo agregar un módulo nuevo
Section titled “Cómo agregar un módulo nuevo”- cargo new –lib crates/module-NOMBRE
- Definir trait en crates/core/src/traits/NOMBRE.rs
- Implementar trait en crates/module-NOMBRE/src/lib.rs
- Agregar al workspace Cargo.toml
- Daemon importa el trait y wire-up de la implementación
- Documentar en docs/modules/NOMBRE.md
- ADR en docs/decisions/ si la decisión es no trivial
- Agregar strings del módulo en crates/module-i18n/locales/en-US/NOMBRE.ftl
Cómo reemplazar un módulo
Section titled “Cómo reemplazar un módulo”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.