sprint-0: fundaciones VMS-Sailor
Sprint 0 completo del producto VMS-Sailor (Vessel Management System integrado para buques 30-40m). Brief de referencia en VMS_Sailor_v2_Parte_*.md (intacto). Core (vmssailor.core, 95.17% coverage, 99 tests verde): - ShipCoord: sistema naval x_pp/y_cl/z_bl frozen - Vessel, Deck, Bulkhead - Equipment, EquipmentModel, Sensor, EquipmentSpec - Tag, AlarmConfig, TagBinding, Scaling - CardInstance, Bus, Topology con validacion 21 puntos I/O AR-NMEA-IO-v1.0 - Alarm, PermissiveRule, Condition - Project agregado raiz con validacion cross-entity - Persistencia portable .vmsproj (SQLite) con roundtrip verificable Biblioteca curada seed (vmssailor.library): - systems_catalog.json completo (catalogo maestro Parte 1 sec 7) - 2 vessels: Sunseeker 76, Ferretti 850 - 2 motores: MTU 12V 2000 M96, Volvo D13-900 - 1 genset: Northern Lights M65C13 - yacht_motor_planeo.yaml (reglas heuristicas) - TODO marcado data_source=seed_estimate - requiere validacion datasheets Tools: - vms-validate-library: CLI valida biblioteca completa - vms-generate-test-project: CLI demo + verificacion roundtrip persistencia Design System + 8 mockups HTML estaticos: - docs/design_system.md (paleta Deep Ocean, gradientes, typography, motion) - docs/brand/ (logo + variantes SVG) - docs/mockups/splash, studio_main, runtime_overview, runtime_mimic_fuel (P&ID animado), runtime_alarms, runtime_trim (panel estrella con horizonte artificial), mobile_overview, mobile_trim - docs/mockups/index.html (galeria) Firmware (Sprint 12+ implementacion): - firmware/ar_nmea_io_v1/src/config/pinout.h con macros GPIO Decisiones autonomas documentadas en docs/decisions_sprint0.md. Stack: Python 3.11 + uv + Pydantic v2 + SQLite stdlib + hatchling + pytest 9 + ruff + mypy. Sin PySide6, FastAPI, Flutter ni firmware funcional (entran en sprints siguientes). Criterio de aceptacion Sprint 0: cumplido. - uv sync: OK - pytest: 99/99 verde - cov vmssailor.core: 95.17% (objetivo >=80%) - ruff: clean - vms-validate-library: OK - vms-generate-test-project: INTEGRIDAD OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
# VMS-Sailor · Brief para Claude Code · Parte 3 de 6
|
||||
|
||||
## VMS-Sailor Runtime (a bordo del buque)
|
||||
|
||||
> Esta parte detalla el Runtime. Asume que ya leíste Partes 1 y 2.
|
||||
|
||||
---
|
||||
|
||||
## 1. Propósito
|
||||
|
||||
El Runtime es lo que se instala en el PC industrial del buque del cliente. Opera 24/7. Es lo que el armador, capitán, jefe de máquinas y tripulación usan día a día.
|
||||
|
||||
Dos componentes principales:
|
||||
- **Servidor**: servicio Windows con motor de tiempo real, drivers, alarm engine, etc.
|
||||
- **Cliente desktop**: aplicación PySide6 en cada estación de operación (puente, máquinas, eventualmente camarote del owner)
|
||||
|
||||
---
|
||||
|
||||
## 2. Estructura de carpetas del Runtime
|
||||
|
||||
```
|
||||
vmssailor/runtime/
|
||||
├── __init__.py
|
||||
│
|
||||
├── server/ # SERVIDOR (servicio Windows)
|
||||
│ ├── __init__.py
|
||||
│ ├── service.py # Servicio Windows (pywin32)
|
||||
│ ├── main_loop.py # Loop asíncrono principal
|
||||
│ │
|
||||
│ ├── drivers/ # Drivers de protocolo
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base_driver.py
|
||||
│ │ ├── modbus_tcp.py
|
||||
│ │ ├── modbus_rtu.py # Bus principal AR-NMEA-IO
|
||||
│ │ ├── nmea2000.py # CAN/NMEA 2000 (publicar y suscribir)
|
||||
│ │ ├── j1939.py # Para motores que hablan J1939 nativo
|
||||
│ │ └── card_discovery.py # Auto-descubrimiento plug-and-produce
|
||||
│ │
|
||||
│ ├── tag_db/ # Base de tags
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── tag_store.py # En memoria + persistencia periódica
|
||||
│ │ ├── tag_resolver.py # Resuelve id → valor, calidad, timestamp
|
||||
│ │ └── historian.py # DuckDB con series temporales
|
||||
│ │
|
||||
│ ├── alarm_engine/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── alarm_evaluator.py # Evalúa límites contra tags
|
||||
│ │ ├── alarm_priorities.py # Emergency / High / Low / Info
|
||||
│ │ ├── alarm_state.py # Active / Ack / Cleared
|
||||
│ │ ├── acknowledgement.py
|
||||
│ │ ├── escalation.py # Escala si no se ack en X tiempo
|
||||
│ │ └── notification_dispatcher.py # A clientes desktop y móvil
|
||||
│ │
|
||||
│ ├── permissive_engine/ # Pre-condiciones para acciones
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── permissive_evaluator.py
|
||||
│ │ ├── condition_parser.py # Lee reglas YAML del paquete
|
||||
│ │ └── override_handler.py # Override consciente del Admin del buque
|
||||
│ │
|
||||
│ ├── authority/ # Command Authority
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── authority_manager.py
|
||||
│ │ ├── transfer.py # Bilateral handshake puente↔máquinas
|
||||
│ │ └── override.py # Override de emergencia
|
||||
│ │
|
||||
│ ├── stability/ # Protección de escora (Parte 1 sec 8)
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── attitude_reader.py # Lee PGN 127257 del backbone NMEA 2000
|
||||
│ │ ├── roll_monitor.py # Filtros + detección sostenida
|
||||
│ │ ├── safety_levels.py # Lógica niveles 1/2/3
|
||||
│ │ ├── envelope_predictor.py # Predice efecto de comando antes de ejecutar
|
||||
│ │ ├── auto_corrector.py # Corrección suave hacia neutral
|
||||
│ │ ├── emergency_reset.py # Reset físico + virtual
|
||||
│ │ └── owner_override.py # Modo manual con safety envelope
|
||||
│ │
|
||||
│ ├── config/ # Layer Config Engine (capas)
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── layer_loader.py # Carga capas en orden
|
||||
│ │ ├── delta_applier.py # Aplica deltas firmados
|
||||
│ │ ├── snapshot_manager.py # Snapshots automáticos
|
||||
│ │ ├── rollback_engine.py # Rollback granular
|
||||
│ │ ├── schema_validator.py
|
||||
│ │ └── signature_verifier.py # Verifica firma de Álvaro
|
||||
│ │
|
||||
│ ├── logbook/ # Log Book naval (Parte 1 sec 6)
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── engine_log_writer.py # Auto-detección arranque/parada motores
|
||||
│ │ ├── alarm_log_writer.py
|
||||
│ │ ├── manual_entry_handler.py
|
||||
│ │ ├── snapshot_periodic.py # Snapshots cada 15 min con motor corriendo
|
||||
│ │ ├── log_signer.py # Firma digital inmutable
|
||||
│ │ └── log_exporter.py # Exporta a PDF formato oficial
|
||||
│ │
|
||||
│ ├── licensing/ # Activación HWID
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── hwid_generator.py # MAC + Disk Serial + UUID
|
||||
│ │ ├── activator.py # Activación online inicial
|
||||
│ │ ├── verifier.py # Verifica firma del paquete vs HWID
|
||||
│ │ └── license_file.py
|
||||
│ │
|
||||
│ ├── vpn/ # Soporte VPN administrativa
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── wg_helper.py # Helpers para WireGuard externo
|
||||
│ │
|
||||
│ ├── audit/ # Auditoría
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── audit_log.py # Eventos auditados inmutables
|
||||
│ │ └── vpn_session_tracker.py # Registra cada sesión VPN de Álvaro
|
||||
│ │
|
||||
│ ├── telemetry/ # Telemetría de salud técnica
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── health_reporter.py
|
||||
│ │ └── client_transparency.py # Lo que se envía es visible al owner
|
||||
│ │
|
||||
│ └── api/
|
||||
│ ├── __init__.py
|
||||
│ ├── fastapi_app.py
|
||||
│ ├── ws_endpoints.py # WebSockets tiempo real
|
||||
│ ├── rest_endpoints.py # REST configuración + históricos
|
||||
│ ├── auth.py # JWT local + TOTP para móvil
|
||||
│ └── mobile_endpoints.py # Endpoints específicos Mobile
|
||||
│
|
||||
├── client/ # CLIENTE DESKTOP (PySide6)
|
||||
│ ├── __init__.py
|
||||
│ ├── app.py
|
||||
│ ├── login.py # Login Operador/Técnico/Admin
|
||||
│ ├── main_window.py
|
||||
│ ├── ws_client.py # Cliente WebSocket
|
||||
│ │
|
||||
│ ├── views/ # Vistas principales
|
||||
│ │ ├── overview.py # Panel general del buque
|
||||
│ │ ├── mimic_view.py # Mímico de un sistema
|
||||
│ │ ├── alarm_panel.py # Lista alarmas viva con ack
|
||||
│ │ ├── trends_panel.py # Gráficas tiempo real
|
||||
│ │ ├── logbook_view.py # Log book
|
||||
│ │ ├── audit_view.py # Auditoría (Admin solo)
|
||||
│ │ ├── support_view.py # Pestaña "Soporte y Auditoría" del Admin
|
||||
│ │ ├── trim_panel.py # Control trim y maniobra
|
||||
│ │ └── settings.py # Settings limitados del cliente
|
||||
│ │
|
||||
│ └── widgets/ # Widgets reutilizables
|
||||
│ ├── system_sidebar.py # Menú lateral dinámico
|
||||
│ ├── tag_widget.py # Display individual con color/alarma
|
||||
│ ├── gauge.py
|
||||
│ ├── lamp.py # Indicador on/off
|
||||
│ ├── bargraph.py
|
||||
│ ├── valve.py # Símbolo válvula con estado
|
||||
│ ├── motor.py # Símbolo motor
|
||||
│ ├── pump.py
|
||||
│ ├── tank.py
|
||||
│ └── alarm_badge.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Motor de tiempo real (Server)
|
||||
|
||||
### Loop principal
|
||||
|
||||
Servicio Windows arranca al boot. Main loop asíncrono con `asyncio`. Múltiples tareas concurrentes:
|
||||
|
||||
- **Driver Modbus RTU** poolea las tarjetas AR-NMEA-IO en el bus (cada 100ms por defecto, configurable por tag)
|
||||
- **Driver NMEA 2000** suscribe a PGNs configurados, lee del bus CAN
|
||||
- **Tag store** recibe updates de drivers, mantiene en memoria valores actuales con timestamp y calidad
|
||||
- **Historian** guarda en DuckDB cada N segundos (configurable por tag, default 1s para críticos, 60s para no-críticos)
|
||||
- **Alarm engine** evalúa cambios de tags contra límites
|
||||
- **Permissive engine** evalúa cuando se solicita acción
|
||||
- **Stability monitor** lee PGN 127257 cada 100ms, monitorea roll/pitch
|
||||
- **API server** atiende WebSockets de clientes desktop y Mobile, REST para configuración
|
||||
- **VPN listener** atiende endpoints administrativos solo desde IP del túnel
|
||||
- **Health reporter** envía telemetría técnica si está habilitada
|
||||
|
||||
### Tag store
|
||||
|
||||
Estructura en memoria optimizada:
|
||||
- Dict por `tag_id` → objeto `Tag` con: valor, calidad, timestamp, unidad SI, rango normal, alarmas configuradas, `controllable`, `control_mode`, `authority_required`, protocolo, dirección, escalado
|
||||
- Pub/Sub interno: cuando un valor cambia, se notifica a suscriptores (alarm engine, historian, API clients)
|
||||
- Calidad: GOOD, BAD, UNCERTAIN. Si un sensor da timeout 3 veces seguidas → calidad BAD, valor último conocido marcado como stale.
|
||||
|
||||
### Historian (DuckDB)
|
||||
|
||||
DuckDB embebido en archivo `%PROGRAMDATA%/VMS-Sailor/historian.duckdb`. Esquema simple:
|
||||
```
|
||||
tag_id (string), timestamp (datetime), value (double), quality (enum)
|
||||
```
|
||||
|
||||
Retención configurable por tipo de tag:
|
||||
- Tags críticos: alta resolución (1 muestra/s) durante 30 días, downsampled a 1/min después de 30 días, retenidos 5 años
|
||||
- Tags no críticos: 1 muestra/min durante 90 días, downsampled a 1/hora después
|
||||
- Eventos discretos (alarmas, comandos): retención completa, todos guardados
|
||||
|
||||
### Alarm engine
|
||||
|
||||
Cada tag con alarmas configuradas se evalúa cuando cambia su valor:
|
||||
- Compara contra límites: `low_low`, `low`, `high`, `high_high`
|
||||
- Cada límite tiene prioridad: Emergency, High, Low, Info
|
||||
- Histéresis: tag no sale de alarma hasta cruzar el límite +/- N (configurable)
|
||||
- Retraso: tag no entra en alarma hasta que la condición persiste X segundos (anti-flicker)
|
||||
- Mensaje configurable por alarma
|
||||
- Estados: ACTIVE (no ack), ACK (ack pero condición persiste), CLEARED (condición resuelta)
|
||||
- Escalación: si una alarma Emergency lleva X minutos sin ack, escala (sonido más fuerte, notificación móvil push)
|
||||
|
||||
### Authority Manager (puente ↔ máquinas)
|
||||
|
||||
Estado: cuál estación tiene autoridad actualmente (BRIDGE, ENGINE, NONE en blackout).
|
||||
|
||||
Transferencia bilateral:
|
||||
1. Estación A solicita autoridad
|
||||
2. Estación B recibe notificación, debe confirmar o rechazar
|
||||
3. Si confirma, autoridad cambia
|
||||
4. Timeout: si B no responde en 30s, autoridad permanece en A
|
||||
|
||||
Override de emergencia: botón E-stop físico cablea directo a tarjeta cerca del motor (permissive local). Anula cualquier autoridad. Detiene equipo críticamente. Registra evento crítico en logbook.
|
||||
|
||||
### Stability Monitor (detalle Parte 1 sec 8)
|
||||
|
||||
Suscribe a PGN 127257 del backbone NMEA 2000 (que publica el AR-ECDIS). Lee roll/pitch cada 100ms. Aplica filtros (mediana 5 muestras + promedio 1s). Evalúa tres niveles:
|
||||
|
||||
```python
|
||||
async def stability_loop():
|
||||
while running:
|
||||
attitude = await read_pgn_127257() # del backbone
|
||||
roll = filter(attitude.roll)
|
||||
pitch = filter(attitude.pitch)
|
||||
|
||||
await level_1_check(roll, pitch) # WARNING
|
||||
await level_2_check(roll, pitch) # AUTO-OFFER
|
||||
await level_3_check(roll, pitch) # AUTO-RESET FORZADO
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Cliente desktop (PySide6)
|
||||
|
||||
### Login
|
||||
|
||||
Tres perfiles fijos. Login con usuario + password (gestionados por el Admin del buque). En sprint posterior se puede agregar SSO o LDAP.
|
||||
|
||||
### Layout principal
|
||||
|
||||
- Barra superior: nombre del buque, estado conexión servidor, alarmas activas (badge), autoridad actual, usuario logueado
|
||||
- Barra lateral: menú dinámico de sistemas (generado a partir del `.vmspack` activo). Solo aparecen los sistemas marcados en el wizard del Studio
|
||||
- Vista central: mímico del sistema seleccionado, o vista de overview por defecto
|
||||
- Barra inferior: ticker de alarmas, hora del sistema, estado VPN
|
||||
|
||||
### Vistas por sistema
|
||||
|
||||
Cada sistema marcado tiene su propio mímico (SVG/JSON empaquetado en `.vmspack`). El mímico se renderiza con PySide6 + QGraphicsView. Los símbolos (motor, válvula, bomba, etc.) muestran:
|
||||
- Estado en color (verde = OK, amarillo = warning, rojo = alarma, gris = offline)
|
||||
- Valores en displays digitales sobre el símbolo
|
||||
- Click → menú contextual con acciones disponibles según permissives + autoridad
|
||||
|
||||
### Panel de alarmas
|
||||
|
||||
Lista cronológica de alarmas activas y recientes:
|
||||
- Color por prioridad
|
||||
- Botón ACK por alarma
|
||||
- Filtros por sistema, prioridad, estado
|
||||
- Histórico completo accesible (DuckDB)
|
||||
|
||||
### Panel de trends
|
||||
|
||||
Gráficas tiempo real (último 1 hora, 24 horas, 7 días). Hasta 8 tags simultáneos en mismo eje. Zoom y pan. Exportable a CSV.
|
||||
|
||||
### Panel de Trim y maniobra (caso de uso destacado)
|
||||
|
||||
- Sliders visuales para cada actuador de trim (2 motores + 2 trim tabs típicamente)
|
||||
- Indicador en tiempo real de roll y pitch (desde PGN 127257)
|
||||
- Botón "Reset Emergencia" muy visible
|
||||
- Toggle "Modo Manual del Owner" (con PIN/biométrico)
|
||||
- Indicador visual del envelope de seguridad activo
|
||||
|
||||
### Vista de Soporte y Auditoría (solo Admin del buque)
|
||||
|
||||
- Log de mis conexiones VPN: fecha, duración, endpoints accedidos, mensaje mío sobre qué hice
|
||||
- Configuración de telemetría: qué se envía, pausar/desactivar
|
||||
- Gestión de usuarios del Runtime
|
||||
- Gestión de dispositivos móviles enrolados (revocar si se pierde)
|
||||
- Historial de snapshots con botón rollback
|
||||
|
||||
---
|
||||
|
||||
## 5. API del servidor
|
||||
|
||||
### WebSockets (tiempo real)
|
||||
|
||||
`ws://localhost:8765/realtime` — todos los clientes desktop y Mobile conectan aquí.
|
||||
|
||||
Mensajes que envía el servidor:
|
||||
- `tag_update`: id, value, quality, timestamp
|
||||
- `alarm_event`: alarm_id, state, priority
|
||||
- `authority_change`: new_authority
|
||||
- `stability_event`: level, roll, pitch
|
||||
- `permissive_check_result`: action_id, status, reasons
|
||||
|
||||
Mensajes que recibe del cliente:
|
||||
- `subscribe_tags`: lista de IDs para suscribirse
|
||||
- `request_action`: solicita ejecutar acción de control (genera permissive check)
|
||||
- `ack_alarm`: ack de alarma
|
||||
- `request_authority`: solicita autoridad
|
||||
- `commit_logbook_entry`: entrada manual al logbook
|
||||
|
||||
### REST (configuración y consultas)
|
||||
|
||||
- `GET /tags` — lista de tags con configuración
|
||||
- `GET /tags/{id}/history?from=X&to=Y` — históricos
|
||||
- `GET /alarms?state=active|all` — alarmas
|
||||
- `GET /logbook?from=X&to=Y` — entradas logbook
|
||||
- `POST /logbook` — entrada manual (Técnico/Admin)
|
||||
- `GET /audit/vpn_sessions` — sesiones VPN históricas (Admin solo)
|
||||
- `POST /telemetry/pause` — owner pausa telemetría
|
||||
|
||||
### Endpoints administrativos VPN (acceso solo desde IP del túnel)
|
||||
|
||||
- `POST /admin/upload_delta` — Álvaro sube un .vmsdelta firmado
|
||||
- `POST /admin/apply_delta/{id}` — aplica delta (owner debe haber aprobado en su UI antes)
|
||||
- `GET /admin/diagnostics` — diagnóstico del sistema
|
||||
- `POST /admin/rollback/{snapshot_id}` — rollback (registrado en auditoría)
|
||||
|
||||
---
|
||||
|
||||
## 6. Layer Config Engine
|
||||
|
||||
Detalle de cómo se cargan y aplican las capas (Parte 1 sec 5):
|
||||
|
||||
```python
|
||||
async def boot_runtime():
|
||||
config = empty_config()
|
||||
|
||||
# Capa 1
|
||||
base = load_vmspack(path_base)
|
||||
verify_signature(base, alvaro_pubkey)
|
||||
verify_hwid(base, current_hwid)
|
||||
config.apply(base)
|
||||
|
||||
# Capa 2
|
||||
if exists(commissioning_delta):
|
||||
config.apply(load_vmsdelta(commissioning_delta))
|
||||
|
||||
# Capa 3
|
||||
if exists(owner_prefs_delta):
|
||||
config.apply(load_vmsdelta(owner_prefs_delta))
|
||||
|
||||
# Capa 4 — expansiones en orden cronológico
|
||||
for delta in sorted(list_expansion_deltas()):
|
||||
verify_signature(delta, alvaro_pubkey)
|
||||
config.apply(delta)
|
||||
|
||||
# Configuración efectiva lista
|
||||
start_services(config)
|
||||
```
|
||||
|
||||
Snapshots automáticos ANTES de aplicar cualquier delta. Rollback granular permite volver a cualquier snapshot (visible al Admin del buque).
|
||||
|
||||
---
|
||||
|
||||
## 7. Telemetría de salud (transparente al cliente)
|
||||
|
||||
Solo se envía estado técnico, NO contenido operativo:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2027-03-15T14:32:00Z",
|
||||
"runtime_version": "1.4.2",
|
||||
"package_version": "v2.0",
|
||||
"cpu_pct": 23,
|
||||
"ram_mb": 458,
|
||||
"disk_free_gb": 145,
|
||||
"uptime_hours": 1284,
|
||||
"drivers": {
|
||||
"modbus_rtu": {"status": "ok", "errors_24h": 12},
|
||||
"nmea2000": {"status": "ok", "errors_24h": 0}
|
||||
},
|
||||
"tags_offline": ["TANK_FUEL_2.LEVEL"],
|
||||
"alarms_unack_critical": 0,
|
||||
"vpn_status": "available"
|
||||
}
|
||||
```
|
||||
|
||||
El owner ve en su UI **exactamente** lo que se está enviando en tiempo real, puede pausar o desactivar. Si desactiva, yo solo doy soporte reactivo cuando él me llame.
|
||||
|
||||
---
|
||||
|
||||
## 8. Log Book naval (módulo básico para Sprint 5/6)
|
||||
|
||||
Por decisión del Sprint, arrancamos con módulo básico — regulatorio completo viene después.
|
||||
|
||||
**Lo que SÍ implementamos en Sprint 5/6:**
|
||||
- Auto-detección arranque/parada motores: cuando `Card_02.DO1` se energiza y luego `Card_02.RPM1 > 600` por 10s → entrada automática
|
||||
- Snapshots periódicos cada 15 min con motor corriendo: RPM, temp aceite, temp agua, presión aceite, voltaje batería, horas acumuladas
|
||||
- Auto-registro de alarmas con timestamp + ack
|
||||
- Auto-registro de eventos de seguridad (autoridad, override, escora, trim reset)
|
||||
- Entradas manuales del Técnico/Admin
|
||||
- Firma digital inmutable
|
||||
- Export CSV básico
|
||||
|
||||
**Lo que dejamos para Sprint 13+:**
|
||||
- Formato PDF oficial según regulación IMO MARPOL
|
||||
- Oil Record Book separado
|
||||
- Garbage Record Book
|
||||
- Cumplimiento estricto MARPOL Annex I/V
|
||||
- Firma con certificado X.509 del capitán
|
||||
|
||||
---
|
||||
|
||||
## 9. Sprints relacionados con Runtime
|
||||
|
||||
- **Sprint 4**: drivers Modbus RTU/TCP + tag_db + historian + alarm engine básico + API base
|
||||
- **Sprint 5**: driver NMEA 2000 + log book básico + simulador para test bench
|
||||
- **Sprint 6**: cliente desktop completo (estaciones puente y máquinas) + panel alarmas + trends
|
||||
- **Sprint 8**: Permissive engine + Authority transfer + Stability monitor (protección escora)
|
||||
- **Sprint 9-10**: Layer Config Engine + deltas + rollback + activación HWID + telemetría
|
||||
- **Sprint 11** (parte): endpoints específicos para Mobile
|
||||
|
||||
Detalle completo en Parte 6.
|
||||
|
||||
---
|
||||
|
||||
**Fin de Parte 3 de 6.** Próxima: Parte 4 — Hardware AR-NMEA-IO + Firmware ESP32.
|
||||
Reference in New Issue
Block a user