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 modules2026-06-13 07:49 +0200-Document generic product admin modules2026-06-13 08:02 +0200-Add Ultimate Porra settings UI2026-06-13 08:03 +0200-Document product admin UI overlays2026-06-13 08:30 +0200-Add Porra admin domain setup script2026-06-13 08:30 +0200-Document Ultimate Porra admin domain2026-06-13 10:18 +0200-Remove public Porra admin and fix scoring rules2026-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:
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:
- desplegar el build actual de la consola admin,
- asociar el custom domain al proyecto Pages de admin,
- validar el estado de Pages,
- 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
cleanSheetya 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.
La documentacion fue parte del cambio, no el epilogo
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
1900lineas 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.