El admin no es una pestana mas

Las ultimas 24 horas en Nima Project se concentraron en tres repos y en una misma decision:

  • 2026-06-13 07:49 +0200 - Add generic product admin modules
  • 2026-06-13 07:49 +0200 - Document generic product admin modules
  • 2026-06-13 08:02 +0200 - Add Ultimate Porra settings UI
  • 2026-06-13 08:03 +0200 - Document product admin UI overlays
  • 2026-06-13 08:30 +0200 - Add Porra admin domain setup script
  • 2026-06-13 08:30 +0200 - Document Ultimate Porra admin domain
  • 2026-06-13 10:18 +0200 - Remove public Porra admin and fix scoring rules
  • 2026-06-13 10:18 +0200 - Document Ultimate Porra admin boundary

La lectura rapida seria: se ha movido el panel admin a otro sitio y se han ajustado unos puntos de scoring.

La lectura correcta es otra: Ultimate Porra dejo de tratar la administracion como una pestana escondida dentro de la app publica y empezo a tratarla como una superficie de producto distinta.

La frase importante del chat no fue tecnica; fue una frontera

La conversacion que mejor resume este tramo fue corta:

Quiero que este en un subdominio admin

Eso parece una instruccion de DNS.

No lo era.

Era una definicion de frontera:

  • la app publica de la porra es una cosa,
  • el backoffice operativo es otra,
  • y compartir repo o componentes no obliga a compartir superficie ni URL.

La diferencia importa porque dentro de ese admin ya no viven textos o preferencias cosmeticas. Viven:

  • favoritos que invalidan opciones de voto,
  • resultados oficiales,
  • recursos operativos de producto,
  • y acciones con impacto global sobre todas las partidas.

En cuanto eso entra en juego, esconderlo detras de un hash admin dentro del mismo frontend deja de ser una solucion limpia. Pasa a ser una mezcla peligrosa de contextos.

El primer movimiento no fue especifico de Porra; fue plataforma

El commit Add generic product admin modules en nima-system es el punto clave de arquitectura.

No construye un panel aislado para un solo producto. Construye una base reutilizable:

Pieza Lo que habilita Por que importa
productAdminModules descubrir modulos admin por producto evita hardcodear un admin distinto para cada app
recursos admin leer/editar payloads de producto separa superficie UI de adaptadores server-side
acciones admin ejecutar operaciones declaradas evita meter botones ad hoc por todas partes
overlay especifico UI particular solo donde hace falta permite especializar sin romper la capa generica

Ese orden importa.

Si primero hubieras hecho una pantalla solo para ultimate-porra, habrias cerrado una necesidad puntual.

Al hacerlo al reves, se cerro una necesidad puntual sin renunciar a un patron de plataforma.

El segundo movimiento si fue especifico: Porra necesitaba una UI propia

Una vez existia la capa generica, llego Add Ultimate Porra settings UI.

Y aqui hay una leccion util: la abstraccion no elimino la necesidad de una interfaz concreta.

La configuracion de competition-settings de Ultimate Porra necesitaba:

  • selector de competicion,
  • exclusion de favoritos para surpriseTeam,
  • campos de resultado oficial de la previa,
  • guardado por recurso admin,
  • y editor JSON avanzado como fallback.

Eso deja una frontera sana entre dos niveles:

flowchart LR modules["Modulos admin genericos"] --> resource["Recurso competition-settings"] resource --> overlay["UI especifica de Ultimate Porra"] overlay --> save["Guardado por ruta admin generica"] save --> api["API del producto / BFF admin"]

La regla aqui no es "todo debe ser generico".

La regla es mejor: lo generico debe cargar la especializacion, no impedirla.

El diff fuerte no fue lo que se anadio. Fue lo que se quito

El commit mas expresivo del dia fue Remove public Porra admin and fix scoring rules.

En world-cup-porra no se anadieron decenas de componentes nuevos. Se eliminaron.

La app perdio:

  • la ruta admin incrustada,
  • la navegacion hacia admin,
  • renderizadores admin incrustados,
  • autosaves y notificaciones admin dentro del frontend publico,
  • y varios modulos de resultados oficiales que no debian vivir ahi.

El balance del commit lo deja muy claro: alrededor de 1900 lineas borradas frente a menos de 200 anadidas.

Eso no suena a expansion. Suena a correccion de limite.

Y el README del producto lo verbaliza sin rodeos:

  • antes: habia una pantalla admin visible para ciertos usuarios,
  • ahora: sin panel admin en el frontend de usuario; la gestion vive en Nima Admin Console.

La mejora tecnica aqui no fue "ordenar el codigo".

Fue dejar de prometer que la app de usuario puede ser tambien consola operativa.

El dominio no era branding; era semantica operativa

Despues de separar la superficie, llego el subdominio:

  • admin.<dominio-producto>

Otra vez, esto parece presentacion.

Pero no lo es.

Un dominio propio hace visibles varias verdades a la vez:

Senal Lo que comunica
dominio del producto experiencia publica y de usuario
subdominio admin operacion, configuracion y gestion del producto
proyecto Pages separado despliegue y riesgo desacoplados

Las conversaciones de esta parte lo hicieron muy explicito: no bastaba con crear DNS.

Hubo que:

  1. desplegar el build actual de la consola admin,
  2. asociar el custom domain al proyecto Pages de admin,
  3. validar el estado de Pages,
  4. y dejar script y documentacion para repetirlo sin improvisacion.

En otras palabras: el subdominio no era un alias bonito. Era la materializacion de una frontera ya decidida en producto y codigo.

El scoring cambio en el mismo commit por una razon parecida

Puede parecer raro que el commit que saca admin de la app publica tambien toque scoring.

Pero en realidad encaja con la misma disciplina.

La correccion fue precisa: si ya hay marcador exacto, la diferencia y la porteria a cero quedan inferidas por ese marcador y no deben sumarse como bonus independientes.

Eso redujo el conteo y ajusto tests:

  • el bonus de cleanSheet ya no suma cuando el exact score ya lo absorbe,
  • el total de respuestas correctas cambia,
  • y la documentacion de reglas se reescribe para que la interfaz no prometa una puntuacion incoherente.

No es un detalle lateral.

Es la misma idea aplicada a otra capa: una frontera mal definida genera dobles lecturas.

Igual que una app publica no debe fingir que es admin, un marcador exacto no debe cobrarse dos veces por conocimiento que ya contiene.

En el repo raiz no solo aparecieron notas de apoyo.

Aparecieron piezas que fijan el modelo:

  • modulos admin genericos,
  • overlays de UI por producto,
  • dominio admin de Ultimate Porra,
  • y un documento entero de ADMIN_BOUNDARY.md.

Eso importa porque aqui la documentacion no vino "despues para explicar".

Vino para cerrar contratos:

  • que puede hacer la app publica,
  • que debe hacer el admin,
  • donde vive cada cosa,
  • y que rutas o acciones dejan de estar permitidas.

Si no se escribe, dentro de dos iteraciones alguien vuelve a meter un boton operativo en la app de usuario "porque ya existe el fetch".

La idea central: una consola operativa es otra superficie

Estas 24 horas dejaron un cambio de nivel:

Antes Ahora
admin incrustado en el frontend publico admin separado en Nima Admin Console
hash admin dentro de la app subdominio admin
logica admin mezclada con UX de usuario recursos, acciones y overlays con contrato propio
comportamiento especifico hardcodeado patron generico reusable para otros productos

La tentacion inicial en productos pequenos casi siempre es la misma:

"como solo somos nosotros, metemos una pestana admin y ya esta".

Funciona durante un rato.

Hasta que esa pestana:

  • cambia datos que afectan a todos,
  • necesita permisos distintos,
  • requiere despliegue separado,
  • o empieza a parecerse mas a una consola que a una pantalla de usuario.

En ese punto ya no es una pestana.

Es otro producto pequeno pegado al principal.

Y si lo sigues tratando como si no lo fuera, acabas pagando la confusion en seguridad, UX, despliegue y mantenimiento.

Lo que me llevo de este tramo

  • Un panel admin oculto dentro de una app publica puede ser un atajo valido al principio, pero deja de serlo en cuanto toca datos globales y permisos propios.
  • La mejor especializacion de producto suele apoyarse en una base generica, no en ramas ad hoc.
  • Un subdominio admin no es solo marca: hace visible una frontera operativa.
  • Quitar 1900 lineas puede ser un avance mayor que anadir una nueva pantalla.
  • La misma disciplina de fronteras sirve para UI y para reglas: si algo ya esta implicito, no debe cobrarse ni renderizarse dos veces.

Estas no fueron 24 horas de "mover una pantalla".

Fueron 24 horas en las que ultimate-porra acepto algo importante: el backoffice no es una seccion mas de la experiencia publica. Es otra superficie, con otro riesgo, otra semantica y otro contrato.


Parte de mis notas de producto y plataforma. Sigue el blog o escribeme.