refactor(yahweh): Fase 1 — nakui-ui-schema → yahweh-meta-schema

Primer paso del refactor yahweh. El schema de UI declarativa no
tiene acoplamiento real con Nakui (sólo dep en serde/thiserror) —
movemos a yahweh para que cualquier app metadata-driven lo use sin
pasar por nakui.

Mecánico:
- git mv crates/modules/nakui/ui-schema → crates/modules/ui_engine/libs/meta-schema.
- Crate name: nakui-ui-schema → yahweh-meta-schema.
- Workspace members[] actualizado (sección yahweh, no nakui).
- Consumers actualizados: brahman-cards (Cargo.toml + lib.rs +
  readers.rs), nakui-ui (Cargo.toml + main.rs).
- Self-test (example_modules.rs): import + path rebase (5 niveles
  arriba ahora).

Documental:
- Doc del crate ahora dice "metainterfaz (yahweh meta-schema)" +
  "backend-agnostic" en filosofía.
- Module.nakui_module_dir documentado como "path opaco al backend";
  se conserva el nombre por compat con módulos ya escritos +
  serde alias "backend_module_dir" para futuro rename suave.

Tests: 13 yahweh-meta-schema + 26 brahman-cards + 48 nakui-ui
verdes. Workspace build verde.

NO hace Fase 1: mover widgets a yahweh (Fase 2), trait MetaBackend
(Fase 3), renombrar nakui_module_dir.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-09 23:38:25 +00:00
parent f6361bbdca
commit f5987d9cfc
12 changed files with 149 additions and 65 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ description = "Nakui — runtime GPUI de la metainterfaz: carga module.json desd
[dependencies]
nakui-core = { path = "../../modules/nakui/core" }
nakui-ui-schema = { path = "../../modules/nakui/ui-schema" }
yahweh-meta-schema = { path = "../../modules/ui_engine/libs/meta-schema" }
brahman-cards = { path = "../../core/brahman-cards" }
yahweh-widget-text-input = { path = "../../modules/ui_engine/widgets/text_input" }
yahweh-theme = { path = "../../modules/ui_engine/libs/theme" }
+1 -1
View File
@@ -37,7 +37,7 @@ use nakui_core::event_log::{
use brahman_cards::CardBody;
use nakui_core::executor::Executor;
use nakui_core::store::{MemoryStore, Store};
use nakui_ui_schema::{
use yahweh_meta_schema::{
Action, FieldKind, FieldSpec, FormView, ListView, Module, View,
};
use serde_json::{json, Value};
+1 -1
View File
@@ -15,7 +15,7 @@ thiserror = { workspace = true }
ulid = { workspace = true }
brahman-card = { path = "../brahman-card" }
nouser-card = { path = "../../modules/nouser/card" }
nakui-ui-schema = { path = "../../modules/nakui/ui-schema" }
yahweh-meta-schema = { path = "../../modules/ui_engine/libs/meta-schema" }
nickel-lang = "2.0.0"
[dev-dependencies]
+2 -2
View File
@@ -48,8 +48,8 @@ use serde_json::Value;
use thiserror::Error;
pub use brahman_card::Card as EnteCard;
pub use nakui_ui_schema::Module as UiModuleSpec;
pub use nouser_card::MonadManifest;
pub use yahweh_meta_schema::Module as UiModuleSpec;
/// Estructura canónica única que consumen los downstream del sistema
/// (UI runtime, storage, DHT, wire). Cada formato input se proyecta
@@ -59,7 +59,7 @@ pub use nouser_card::MonadManifest;
/// (identidad legible + extensiones forward-compat); el body preserva
/// el typing rico de cada dominio sin colapsarlos.
// PartialEq se omite porque algunos body variants vienen de crates
// que no lo implementan (MonadManifest, nakui_ui_schema::Module).
// que no lo implementan (MonadManifest, yahweh_meta_schema::Module).
// Si downstream necesita igualdad, comparar via JSON round-trip o
// agregar PartialEq en los crates origen.
#[derive(Debug, Clone, Serialize, Deserialize)]
+3 -3
View File
@@ -114,11 +114,11 @@ impl CardReader for MonadJsonReader {
}
// ============================================================================
// UiModule (nakui-ui-schema)
// UiModule (yahweh-meta-schema)
// ============================================================================
/// Reader para el shape JSON de los `module.json` de la UI Nakui
/// ([`nakui_ui_schema::Module`]).
/// Reader para el shape JSON de los `module.json` de la metainterfaz
/// ([`yahweh_meta_schema::Module`]).
///
/// Heurística: tiene `entities` Y `views` Y `menu`. Es el shape más
/// específico del repo, así que va primero en el orden default — si
-14
View File
@@ -1,14 +0,0 @@
[package]
name = "nakui-ui-schema"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Nakui UI metainterface schema: módulos declaran menús, listas y formularios como datos (JSON); el runtime los carga y renderiza sin código compilado por módulo."
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
[dev-dependencies]
tempfile = { workspace = true }
@@ -0,0 +1,14 @@
[package]
name = "yahweh-meta-schema"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Yahweh — meta-schema: descriptores declarativos de UI (entities, menús, listas, formularios, acciones) consumidos por widgets metainterfaz reusables. Independiente del backend: cualquier app que monte una UI dirigida por datos puede usarlo."
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
[dev-dependencies]
tempfile = { workspace = true }
@@ -1,22 +1,22 @@
//! Schema declarativo de la metainterfaz Nakui.
//! Schema declarativo de la metainterfaz (yahweh meta-schema).
//!
//! Cada **módulo** Nakui (customers, products, sales, ...) declara
//! aquí qué menús, vistas, listas y formularios expone, sin escribir
//! código GPUI ni Rust. El runtime ([`nakui-ui` crate]) lee estos
//! `module.json` desde un directorio y monta automáticamente la UI
//! correspondiente.
//! Cada **módulo** declara aquí qué menús, vistas, listas y
//! formularios expone, sin escribir código GPUI ni Rust. Cualquier
//! runtime de UI dirigida por datos (Nakui hoy, otros mañana) lo
//! carga y monta la UI correspondiente.
//!
//! ## Filosofía
//!
//! - **UI como datos**: agregar un módulo = escribir un JSON. Ningún
//! recompile, ningún acoplamiento con el binario del runtime.
//! - **Persistencia universal**: el runtime conecta cada vista al
//! `nakui_core::store::Store` actual; los formularios escriben
//! ops por la pipeline normal de Nakui (executor + event log).
//! - **Schema primero, semántica después**: este crate sólo define
//! la *forma* de los manifests. Validación semántica
//! (referencias rotas a entities, campos faltantes, etc.) vive en
//! el runtime que lo carga, no acá.
//! - **UI como datos**: agregar un módulo = escribir un JSON o un
//! `.ncl`. Ningún recompile, ningún acoplamiento con el binario
//! del runtime.
//! - **Backend-agnostic**: este crate sólo describe la *forma* de
//! la UI. La conexión a un store/log/executor concretos vive en
//! el runtime que lo consume (ej: el meta-runtime de Nakui que
//! wirea esto a `nakui_core` + KCL post-checks).
//! - **Schema primero, semántica después**: validación semántica
//! (referencias rotas a entities, campos faltantes, etc.) vive
//! en el runtime que lo carga, no acá.
//!
//! ## Anatomía de un módulo
//!
@@ -47,7 +47,7 @@ use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use thiserror::Error;
/// Manifiesto de un módulo de la metainterfaz Nakui.
/// Manifiesto de un módulo declarativo de UI.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Module {
/// Identificador estable. Único dentro del directorio cargado.
@@ -66,20 +66,28 @@ pub struct Module {
#[serde(default)]
pub entities: Vec<EntitySpec>,
/// Path a un módulo nakui-core (directorio con `nsmc.json` +
/// schemas KCL + scripts Rhai). Cuando está set, el runtime
/// carga un `Executor` para ese path y permite que las acciones
/// `Morphism { name }` despachen al pipeline real
/// (compute → log → apply).
/// Path opaco al backend que va a manejar este módulo. Lo
/// interpreta el runtime concreto (no este schema).
///
/// Convención actual de Nakui: directorio con `nsmc.json` +
/// schemas KCL + scripts Rhai. Cuando está set, el runtime
/// Nakui carga un `Executor` para ese path y permite que las
/// acciones `Morphism { name }` despachen al pipeline real
/// (compute → log → apply). Otro backend puede ignorar este
/// campo o darle un significado distinto.
///
/// Path resuelto relativo al directorio del `module.json`
/// o absoluto.
///
/// Si es `None`, las acciones `Morphism` quedan deshabilitadas
/// (toast informativo al usuario). Las acciones `SeedEntity`
/// siguen funcionando sin esto — son altas administrativas que
/// no necesitan validación de manifest.
#[serde(default)]
/// Si es `None`, los backends que requieren manifest deberían
/// degradar (toast informativo, deshabilitar morphisms, etc.);
/// los `SeedEntity` siguen funcionando — son altas
/// administrativas que no necesitan validación de manifest.
///
/// Nombre conservado por compat con módulos ya escritos.
/// Renombrar a `backend_module_dir` o similar si emerge un
/// segundo backend que también lo use.
#[serde(default, alias = "backend_module_dir")]
pub nakui_module_dir: Option<String>,
/// Items del menú. Cada uno apunta a una key de `views`. Orden
@@ -4,13 +4,16 @@
//! corra `NAKUI_MODULES_DIR=examples/nakui-modules cargo run -p nakui-ui`
//! va a obtener los 6 módulos cargados sin tocar nada.
use nakui_ui_schema::{load_modules_from_dir, FieldKind, View};
use yahweh_meta_schema::{load_modules_from_dir, FieldKind, View};
fn examples_dir() -> std::path::PathBuf {
// Tests corren desde el dir del crate; el repo root está dos
// niveles arriba: crates/modules/nakui/ui-schema → repo.
// Tras el lift a yahweh, el crate vive en
// `crates/modules/ui_engine/libs/meta-schema`, así que el repo
// root queda 5 niveles arriba.
let here = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
here.join("../../../..").join("examples/nakui-modules")
here.join("../../../../..").join("examples/nakui-modules")
}
#[test]
@@ -50,8 +53,8 @@ fn sales_engine_declares_nakui_module_dir_and_morphism() {
"sales_engine debería declarar nakui_module_dir"
);
let has_morphism_view = sales.views.values().any(|v| match v {
nakui_ui_schema::View::Form(form) => {
matches!(form.on_submit, nakui_ui_schema::Action::Morphism { .. })
yahweh_meta_schema::View::Form(form) => {
matches!(form.on_submit, yahweh_meta_schema::Action::Morphism { .. })
}
_ => false,
});