Ir al contenido

Convenciones

  • TypeScript estricto: sin any (se usa unknown o se define el tipo) y los tipos se importan con import type.
  • Alias de importación (@/…) en vez de rutas relativas largas.
  • Server Components por defecto. "use client" solo cuando hace falta estado, efectos, eventos o APIs del navegador, y lo más abajo posible en el árbol; nunca en un layout.
  • Datos desde los servicios, no desde los componentes: la página pide al servicio y pasa props. Los datos de ejemplo viven en los servicios, no en las páginas.
  • Carga con esqueletos: cada componente que pide datos exporta su esqueleto y se envuelve en Suspense.
  • Estilos con Tailwind y los tokens del tema (bg-card, text-brand-blue…), nunca colores escritos a mano; clases condicionales con cn() y variantes con CVA.
  • La lógica que se puede probar sin Next va en funciones puras (en app/lib/ o en el _lib/ de la pantalla) con su prueba .test.mjs al lado.
  • Comentarios que explican el porqué, en español, sobre todo cuando el código parece raro por una razón que no se ve.
app/(protected)/<pantalla>/
├── page.tsx # entrada (Server Component)
├── loading.tsx # estado de carga de la ruta
├── error.tsx # límite de error de la ruta
├── _components/ # interfaz propia de la pantalla
├── _lib/ # lógica propia (opcional)
└── _types/ # tipos propios (opcional)

Toda pantalla nueva se agrega al inventario de permisos por pantalla con el permiso que de verdad comprueba; una prueba falla si aparece una carpeta de página que no está en él.

El proxy de la web (protege las rutas y decide el aterrizaje), la configuración de la sesión y las rutas de alias de TypeScript. Un error en cualquiera de ellos deja a todos sin entrar o rompe las importaciones del proyecto entero.

Las reglas de BoostAPI que ya costaron caro (están en su CLAUDE.md):

  • Sin migraciones. Todo cambio de tablas se escribe a mano como SQL, con su reversa, se ensaya en una base desechable y se aplica antes del despliegue. La sincronización automática del esquema nunca se enciende contra una base compartida.

  • Ningún script arranca la aplicación completa contra producción: encendería sus procesos de fondo. Se lee con la base en solo lectura y se escribe por la API, con la CLI boost.

  • Los DTO de creación no llevan valores iniciales: el DTO de edición se deriva de ellos y los colaría en cada cambio parcial.

  • Un día del usuario es un día de Guatemala; las columnas guardan UTC.

  • Enviar a Meta o por correo solo pasa por el servicio de envío de los canales (src/channels/send/).

  • Los nombres engañan. Varias piezas del canal llevan communications en el nombre y son el camino vivo de los mensajes (el cliente de envío, la tubería de ingreso, los interruptores): no se borran por el nombre ni se les agregan llamadas sin leer antes el documento de canales del backend.

  • Las colas y los temporizadores son por entorno: un proceso local nunca usa los de producción.

  • Ninguna autorización depende del nombre de un rol: se decide por el código del permiso.

  • Los archivos enormes se buscan por símbolo (el servicio de interacciones pasa de 18 000 líneas).

  • Se trabaja en una rama propia creada desde la rama principal actualizada del repositorio de la organización, en un worktree aparte si hay cambios locales en curso.

  • El PR va desde el fork personal hacia el repositorio de la organización (desarrollos-roo/Boost para el Monorepo, desarrollos-roo/BoostAPI para el backend).

  • Mensajes de commit en español, con el área: feat(interacciones): …, fix(cartera): …, docs(web): ….

  • Antes del PR: tipos, lint, las pruebas y el build de lo que se tocó (ver Levantar el proyecto y, para el backend, su lista). Si se cambió un contrato que otros consumen, la suite completa.

  • Cada PR que entra a la rama principal del backend lo redespliega y reinicia el servicio: se espera a que el despliegue quede vivo antes de probar en producción, y conviene no fusionar mientras corre un envío programado grande.

  • Un cambio que se ve en una pantalla actualiza su página en esta documentación en el mismo PR.
  • Un cambio técnico actualiza el documento de su área en docs/modulos/ del repositorio. Lo que deja de regir se marca como histórico o se mueve a la carpeta de archivo; nunca se deja como si siguiera vigente.
  • Aquí no van direcciones de API, credenciales ni datos de clientes; el build lo revisa y falla si los encuentra. Ver Mantener esta documentación.

Lo que no se deduce leyendo el código —por qué algo es así, qué no se puede romper, qué riesgo se aceptó— se registra en .rationale/ como un registro con su enunciado, su razón, el código al que aplica y su evidencia. Un registro por decisión. Antes de cambiar código no trivial se consulta qué registros lo gobiernan; si uno está fijado, es una regla del proyecto y no se rodea: se pregunta. Los documentos técnicos enlazan los registros por su identificador en vez de repetirlos.