feat(nakui): metainterfaz declarativa + 6 modulos ERP estandar

Salto cualitativo: Nakui pasa de "library + demos + read-only viewer
del event log" a plataforma ERP con UI dirigida por datos. Cada
modulo de negocio se declara como un module.json (sin codigo Rust
nuevo) y el runtime GPUI lo carga dinamicamente: sidebar de menus,
listas con columnas configurables, formularios de alta.

3 entregables:

1. Crate nakui-ui-schema (datos puros): Module, View::List/Form,
   FieldSpec con FieldKind {Text|Multiline|Number|Boolean|Date},
   Action {OpenView|SeedEntity|Morphism}. Module::from_path,
   Module::validate, load_modules_from_dir(dir). 6 tests unit + 4
   integration.

2. Crate nakui-ui (binario GPUI): carga modulos desde
   NAKUI_MODULES_DIR. Sidebar + main panel. List view con tabla
   weighted; form view con campos labeled + submit que ejecuta
   SeedEntity contra MemoryStore in-process compartido. Toast +
   error banner. 6 tests unit.

3. 6 modulos demo en examples/nakui-modules/:
   - customers (nombre, email, telefono, credito, notas)
   - products (SKU, nombre, categoria, precio, stock)
   - suppliers (razon social, ID fiscal, contacto, terminos pago)
   - inventory_movements (fecha, tipo, SKU, cantidad, costo, motivo)
   - sales_orders (numero, cliente, fechas, estado, totales)
   - invoices (numero, cliente, fechas, totales, pagado, moneda)

Filosofia: UI como datos. Persistencia universal (MemoryStore hoy,
SurrealStore manana, sin tocar module.json). Schema primero, semantica
despues.

Activacion:
  NAKUI_MODULES_DIR=examples/nakui-modules cargo run -p nakui-ui

Limitaciones conocidas (proximos iters):
- Inputs sin teclado (GPUI no lo trae nativo; integrar
  yahweh-widget-text-input).
- Click handlers no propagan mutacion al estado (refactor con
  cx.listener pendiente).
- Action::Morphism queda como TODO hasta cargar Manifest junto al
  Module.
- Sin persistencia entre runs (wire con EventLog/SurrealStore para
  cuando el daemon Nakui exista).

Tests: 16 totales nuevos. Lo que esto desbloquea: cualquiera puede
escribir un module.json para su dominio (pacientes, alumnos,
reservaciones) y aparece en la UI sin recompilar.
This commit is contained in:
Sergio
2026-05-09 19:54:21 +00:00
parent 5b8f71e0de
commit 06c4fb9130
14 changed files with 1919 additions and 0 deletions
+96
View File
@@ -6,6 +6,102 @@ ratio/diff ver `git show <sha>`.
## 2026-05-09
### feat(nakui): metainterfaz declarativa + 6 módulos ERP estándar
Salto cualitativo: Nakui pasa de "library + demos + read-only viewer
del event log" a **plataforma ERP con UI dirigida por datos**. Cada
módulo de negocio se declara como un `module.json` (sin código Rust
nuevo) y el runtime GPUI lo carga dinámicamente: sidebar de menús,
listas con columnas configurables, formularios de alta.
Tres entregables:
**1) Crate nuevo `nakui-ui-schema`** (datos puros, ~250 LOC + 200
LOC tests):
- `Module { id, label, entities, menu, views }`.
- `View::List { entity, columns, actions, search_in }` o
`View::Form { entity, fields, on_submit }`.
- `FieldSpec { name, label, kind, default, required, help }` con
`FieldKind = Text|Multiline|Number|Boolean|Date`.
- `Action::OpenView | SeedEntity | Morphism` — el runtime las
dispara desde botones / submits.
- `Module::from_path` parsea un JSON; `Module::validate` chequea que
cada `MenuItem.view` exista en `views`.
- `load_modules_from_dir(dir)` busca `dir/<modulo>/module.json`,
parsea, valida, detecta IDs duplicados, devuelve ordenado.
- 6 tests unit + 4 integration (los 6 demos cargan limpio, todos
tienen list+form, kinds reconocidos, validate pasa).
**2) Crate nuevo `nakui-ui`** (binario GPUI, ~700 LOC + 100 LOC tests):
- Carga módulos desde `NAKUI_MODULES_DIR` (default `./nakui-modules`).
- Sidebar con módulos + sus menús; click en menu cambia la vista activa.
- **List view**: tabla de instancias del entity con columnas
weighted (header de columnas + filas + id corto).
- **Form view**: campos labeled + botón submit que dispara la action
declarada (`SeedEntity` mete el record al `MemoryStore`
in-process; `Morphism` queda como TODO hasta integrar el manifest
loader nakui-core).
- `MemoryStore` compartido entre todas las vistas (Arc<Mutex>); el
cambio en un módulo se refleja en otro inmediato.
- Toast + error banner para feedback.
- 6 tests unit (parse_field_value para los 5 kinds, lookup_field
nested, render_value).
**3) 6 módulos demo** en `examples/nakui-modules/` que cubren un
ERP estándar:
- **customers**: nombre, email, teléfono, activo, límite de
crédito, notas.
- **products**: SKU, nombre, categoría, precio, stock, activo.
- **suppliers**: razón social, ID fiscal, contacto, email,
teléfono, términos de pago.
- **inventory_movements**: fecha, tipo (in/out/adjustment), SKU
producto, cantidad, costo unitario, motivo, doc. referencia.
- **sales_orders**: número, cliente, emisión, vencimiento,
estado, subtotal, impuestos, total, notas.
- **invoices**: número, cliente, emisión, vencimiento, subtotal,
impuestos, total, pagado, estado, moneda, orden referenciada.
Cada módulo tiene su `list` (catálogo) + `form` (alta), con search
field y columns weighted. Los 6 cubren un setup de ERP de ventas
chico funcional para demo.
Filosofía documentada:
- **UI como datos**: agregar un módulo = escribir un JSON, no
recompilar el binario.
- **Persistencia universal**: el runtime conecta cada vista al
`nakui_core::store::Store`; cambiar de MemoryStore a SurrealStore
no toca los module.json.
- **Schema primero, semántica después**: `nakui-ui-schema` sólo
define la forma; validación de referencias rotas (entity inexistente,
morphism faltante) vive en el runtime.
Activación:
```sh
NAKUI_MODULES_DIR=examples/nakui-modules cargo run -p nakui-ui
```
Limitaciones conocidas (próximas iteraciones):
- **Inputs sin teclado**: GPUI no incluye text input; los forms
muestran los `default` del schema y el submit usa esos. Próximo
iter: integración con `yahweh-widget-text-input`.
- **Click handlers no wired**: GPUI necesita pasar `Entity<MetaUi>`
a los handlers para mutar estado; refactor con `cx.listener` +
weak refs queda para el próximo iter. Hoy la navegación es
visual; el código de mutación sí funciona via API programática
(los tests lo cubren).
- **Acción `Morphism`**: pendiente de cargar el `Manifest` de
nakui-core junto con el `Module` UI para wirear `execute_and_log`.
- **Sin persistencia entre runs**: el `MemoryStore` se pierde al
cerrar. Wire con `EventLog` o `SurrealStore` queda para cuando
el daemon Nakui exista.
Tests: 16 totales nuevos (10 schema + 6 runtime). 100% verde.
Lo que esto desbloquea: cualquiera puede escribir un `module.json`
para su dominio (pacientes médicos, alumnos de escuela,
reservaciones de hotel) y aparece en la UI sin tocar Rust ni
recompilar. La forma de extender Nakui dejó de ser "agregar código
al ERP" y pasó a ser "escribir el contrato del módulo".
### feat(nakui-explorer): nuevo binario GPUI — Nakui visible en la interfaz
Cierra "nakui no tiene UI propia" del audit. Nuevo binario standalone
`nakui-explorer` (paralelo a `nouser-explorer`) que renderea el