Y la tensión que aparece con el offline · Orchestra, tarea 003 · 2026-08-24 · panorámica · modo de trabajo · stack anterior
| Vía | Necesita | Qué hace |
|---|---|---|
| AssetMapper (Symfony 6.3+) | Nada | Sirve JS y CSS con importmap, sin empaquetador. En producción compila,
versiona por huella y comprime. Es la vía oficial actual y no toca ningún runtime JavaScript. |
| Tailwind bundle | Nada | Descarga el binario autónomo de Tailwind: un ejecutable, sin runtime JS. Compila y minifica el CSS. Esto responde tu pregunta: sí, se puede. |
| Encore | Node | Es Webpack por dentro. Potente y veterano, pero arrastra el ecosistema que quieres evitar. |
| Vite via bundle | Node o Deno | Deno sí puede correr Vite y sustituir a Node aquí. Pero meter un runtime entero solo para el CSS es peor que no meter ninguno: AssetMapper ya lo resuelve. |
Tú eres quien aprueba el trabajo de los agentes. Ese es el eslabón que sostiene todo el método: los agentes escriben, y alguien con criterio decide si eso entra o no.
Un stack teóricamente superior que no puedes revisar a fondo convierte tu aprobación en un trámite. Un stack que dominas convierte cada diff en una revisión real. En un proyecto llevado por agentes, la familiaridad del humano que aprueba no es una comodidad: es un control de calidad.
Si dominas Symfony, ese argumento solo pierde frente a un impedimento técnico duro. Y hay uno que hay que mirar de frente: el offline.
Los voters de Symfony son exactamente el patrón de la «puerta única»: una pregunta —¿puede este usuario hacer esto sobre este objeto?— resuelta en un solo lugar, con acceso al contexto completo.
Y encajan de lujo con los permisos que caducan: el mandato vencido se evalúa en el voter, no en cada pantalla. Aquí Symfony gana claro.
Twig generando el HTML del acta, y de ahí a PDF. Es exactamente para lo que sirve una plantilla de servidor, y es una parte grande del producto.
El tablero de la junta y el verificador público de actas son páginas que deben cargar en un teléfono viejo sin JavaScript. Twig las sirve mejor que cualquier framework de cliente.
PHP moderno tipado sostiene bien el dominio: quórum, mandatos, validez de acuerdo. No es tan expresivo como otros lenguajes, pero es más que suficiente y se prueba rápido.
Messenger para enviar citaciones, generar actas y rendiciones. Pieza madura y ya integrada, sin añadir infraestructura.
Symfony es muy opinado: hay una forma canónica de hacer cada cosa y muchísimo material público. Los agentes rinden mejor copiando un patrón fuerte que inventando.
Twig renderiza en el servidor. Sin servidor no hay pantalla. Tomar asistencia en una sede sin señal exige lógica en el teléfono: guardar datos localmente y encolar acciones.
Eso se escribe a mano, con o sin Symfony. La pregunta no es si se puede —se puede— sino cuánta aplicación tiene que funcionar así.
Funciona vía bundles espaciales, pero es menos pulido que en otros ecosistemas. Parte de las consultas geográficas se escribirán en SQL nativo. Es una molestia, no un impedimento.
Storybook no existe para Twig. Pero el catálogo se puede hacer como una ruta más de la aplicación que renderiza cada componente en todos sus estados — y eso es incluso más fiel: es la app enseñándose a sí misma, sin herramienta intermedia.
Los snapshots se capturan con Chrome headless, que no necesita Node.
Dijiste que el offline es requisito. Con Symfony eso empuja en una dirección concreta, y conviene elegirla a ojos abiertos en vez de descubrirla a medio camino.
Toda la aplicación es Symfony con Twig: pantallas, formularios, actas, páginas públicas. Donde hace falta interactividad, Symfony UX. Y las dos o tres pantallas que deben funcionar sin señal —tomar asistencia, registrar acuerdos en la sede— se construyen como islas: una porción de JavaScript autónomo dentro de una página Twig, con su almacenamiento local y su cola de envío.
Sin Node ni Deno en el proyecto. Una sola aplicación, un solo despliegue, un solo lenguaje que dominas.
El offline queda acotado a donde de verdad importa, en vez de contaminar toda la arquitectura.
El catálogo de pantallas es una ruta de la propia app: imposible que se desincronice del producto.
Las islas hay que escribirlas a mano y mantenerlas con disciplina, o se convierten en una aplicación de cliente mal hecha por acumulación.
Si dentro de un año media aplicación tiene que ser offline, este camino se queda corto.
Symfony expone la API y sirve las páginas públicas y los documentos. Una PWA aparte —TypeScript— se encarga de todo lo que usa el dirigente, con offline pleno.
Cumple todos los requisitos sin concesiones, y el offline es de primera clase en todas las pantallas.
Deja el camino abierto a una app de tienda el día que se quiera.
Dos ecosistemas, dos despliegues, y Node vuelve por la puerta del frontend.
Es el doble de superficie para que un agente se equivoque, y el doble de revisión para ti.
Como el camino 1, pero el JavaScript de las islas se escribe con una biblioteca pequeña traída por
importmap de AssetMapper — sin empaquetador y sin node_modules.
Más orden que escribir JavaScript suelto, sin traer el ecosistema completo.
Herramientas de desarrollo más pobres para esa parte: sin tipos y sin las comodidades del ecosistema.
| Capa | Antes | Ahora | Nota |
|---|---|---|---|
| Base de datos | Postgres + PostGIS | Igual | No cambia nada |
| Acceso a datos | Drizzle | Doctrine | Migraciones versionadas; SQL nativo para lo geográfico |
| Dominio | TypeScript puro | PHP tipado puro | Misma idea: sin base de datos, sin HTTP, probado al milisegundo |
| API y pantallas | Fastify + React | Symfony + Twig | Una sola aplicación en vez de dos |
| Contratos | Zod → OpenAPI | DTOs → OpenAPI | La regla «contrato antes que pantalla» se mantiene intacta |
| Estilos | Tailwind con Node | Tailwind binario | Mismo Tailwind, sin runtime JS |
| Catálogo | Storybook | Ruta propia de la app | Más fiel, y una dependencia menos |
| Snapshots | Playwright | Chrome headless | Capturas sin Node |
| Pruebas | Vitest | PHPUnit | El dominio sigue probándose en milisegundos |
| Puerta única | Paquete propio | Voters de Symfony | Mejora: es el patrón nativo del framework |
| Offline | Toda la app | Islas acotadas | El cambio de fondo. Es lo que hay que decidir |