Fecha: 2026-06-17 → 2026-06-18 Estado: Aceptado Bloque: Productos de gestión (Pushes 1-6, 8, 9, 11-13, 16, 17, 21 — 14 commits a main). Refina: ADR-0091 (consume los endpoints), todos los ADRs de motor del bloque Y/Z/X1/X3 (modela las features).

Contexto

Antes de esta sesión los dos productos web tenían cobertura muy limitada vs el motor:

Producto Pre-sesión Lo que el motor ya soportaba
phpgabyadmin Browse / Structure (con índices CRUD) / SQL editor con snippets + Sessions M13 / EXPLAIN ANALYZE bias M6 / Stats / Policies / Routines (trg+prc+fn) / Users+Roles+Grants
gabymodeler ER con 14 reglas Check Model, INT/TEXT/BOOL/FLOAT/DATE/DATETIME/JSON, FKs single-col, PK forzada INT + tipos Y1-Y9 (DECIMAL exacto, BLOB, UUID, TIME, VARCHAR enforcement, INT widths, UNSIGNED) / CHECK / composite PK/UNIQUE/INDEX / Views / RLS Policies / Triggers / Procedures / Functions / Users / Roles / Grants

La distancia entre lo que el motor sabe hacer y lo que el usuario puede operar desde la web se había ampliado mucho durante la sesión maratón del 2026-06-15 (ADRs 0078-0090) y los bloques Y/Z/X1/X3 anteriores. Ningún cliente externo usaría la mitad de las features sin escribir SQL a mano.

Adicionalmente, ambos productos tenían identidad visual desalineada con la landing page (/), lo que rompía la sensación de “un solo producto”.

Decisión

Refresh integral en dos ejes simultáneos:

Eje A — visual unificado

Palette + tipografía + componentes alineados con la landing y entre los dos productos:

Token Valor Uso
--bg-0--bg-4 #0a0e14#1c2128 Backgrounds en escala (deepest a hover)
--accent #58a6ff GitHub blue — primary action
--success #7ee787 PK badge, OK toast
--warning #f0883e FK badge, MILD bias
--danger #ff7b72 Destructive, HIGH bias
Font Inter (UI) + JetBrains Mono (code/data) Google Fonts CDN

Componentes compartidos por convención (no por código — son archivos independientes, no React/Vue):

Eje B — cobertura funcional 1:1 con el motor

gabymodeler v3 → estado del schema

{
  dbName, ifNotExists,
  entities: [{
    id, name, x, y,
    columns: [{ id, name, type, pk, notNull, unique,
                hasDefault, defaultValue,
                hasCheck, checkExpr,
                fk: null | { table, column, onDelete } }],
    constraints: [{ id, kind:'pk'|'unique', name?, columns:[colName] }],
    indexes:     [{ id, name?, unique, columns:[colName] }]
  }],
  views:      [{ id, name, body }],
  policies:   [{ id, name, table, action, role, using, check }],
  triggers:   [{ id, name, table, timing, event, body }],
  procedures: [{ id, name, params:[{name,type}], body }],
  functions:  [{ id, name, params:[{name,type}], returnType, body }],
  users:      [{ id, name, password }],
  roles:      [{ id, name }],
  grants:     [{ id, grantee, object, privs:[...] }]
}

Backward-compat con localStorage antiguo: cada loadState() hace init de las propiedades faltantes a [], así que un usuario que tenía un modelo v2 abre v3 sin perder nada.

Status bar refleja 13 contadores en vivo: N tablas · cols · idx · FKs · composite · views · policies · trg · prc · fn · usr · rol · grants.

phpgabyadmin v2 → 9 tabs

Tab Trigger Bloque motor
Browse ?table=X&tab=browse core SELECT + paginado
Structure ?tab=structure catalog.get_table
SQL editor ?tab=sql exec con CodeMirror
Sessions ?tab=sessions M13 cross-request tx
Explain ?tab=explain M6 EXPLAIN ANALYZE bias
Stats ?tab=stats derivado de /tables + /metrics
Policies ?tab=policies Z3 RLS
Routines ?tab=routines X1 + X3
Security ?tab=security Z1 + Z2

CodeMirror SQL editor

textarea[name="sql"] y los textareas de policies (p_using, p_check) montan CodeMirror 5.65.16 desde cdnjs con:

Canvas del modeler — zoom + pan + minimap

#canvas-wrap pasa a overflow:hidden. Interior #canvas-content (5000×3000 lógicos) recibe transform: translate() scale(). Las entities se appendean a #canvas-content, no al wrap.

Reverse engineering completo (Push 21)

doImport() antes leía sólo /tables. Ahora hace 9 GETs en paralelo vía Promise.all, con un helper fetchList() que tolera 404/error (degrada silenciosamente para apuntar a servers viejos).

Mapeo limitaciones:

Alternativas descartadas

Métricas

Consecuencias

Positivas

Negativas / tradeoffs

Referencias