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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user