docs: actualizar convenciones y añadir buenas prácticas de implementación
This commit is contained in:
parent
bada13a50e
commit
fbfa64509b
208
AGENTS.md
208
AGENTS.md
@ -18,7 +18,7 @@ No imprimir, copiar ni versionar .env locales o secretos.
|
|||||||
- Documentación en /docs, con nombres de ficheros en castellano.
|
- Documentación en /docs, con nombres de ficheros en castellano.
|
||||||
- Comentarios que expliquen decisiones, riesgos o contratos, nunca que repitan el código.
|
- Comentarios que expliquen decisiones, riesgos o contratos, nunca que repitan el código.
|
||||||
- Mantener es y en para textos de interfaz; no insertar literales en áreas con i18n.
|
- Mantener es y en para textos de interfaz; no insertar literales en áreas con i18n.
|
||||||
- En las sentencia condicionales (if) Utiliza siempre llaves cuando el bloque contiene una sola intrucción.
|
- Utilizar siempre llaves en if, else, for, while y estructuras equivalentes, incluso cuando el bloque contenga una sola instrucción.
|
||||||
|
|
||||||
## Disciplina
|
## Disciplina
|
||||||
|
|
||||||
@ -97,3 +97,209 @@ Informar cambios, archivos principales, comandos ejecutados, resultados y pendie
|
|||||||
No afirmar validaciones no ejecutadas ni ocultar fallos conocidos.
|
No afirmar validaciones no ejecutadas ni ocultar fallos conocidos.
|
||||||
|
|
||||||
Precedencia: instrucciones actuales del usuario, AGENTS.md más cercano, este archivo y convenciones existentes.
|
Precedencia: instrucciones actuales del usuario, AGENTS.md más cercano, este archivo y convenciones existentes.
|
||||||
|
|
||||||
|
|
||||||
|
## Buenas prácticas de implementación
|
||||||
|
|
||||||
|
Estas reglas complementan las convenciones y documentos de arquitectura existentes. Antes de introducir un patrón nuevo, comprobar cómo resuelve el repositorio casos equivalentes y mantener coherencia con ellos.
|
||||||
|
|
||||||
|
### Idioma
|
||||||
|
|
||||||
|
- Responder, explicar decisiones, documentar cambios y redactar comentarios y TSDoc en castellano.
|
||||||
|
- Mantener código, identificadores, nombres de tipos, funciones, variables, componentes, hooks y ficheros en inglés.
|
||||||
|
- No traducir nombres de APIs, bibliotecas, protocolos ni conceptos técnicos cuando su denominación habitual esté en inglés.
|
||||||
|
- Los mensajes destinados al usuario final deben pasar por el sistema de internacionalización cuando corresponda.
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
- Mantener TypeScript en modo estricto y resolver los errores de tipos en su origen; no debilitarlos para conseguir que compile.
|
||||||
|
- Preferir inferencia cuando el tipo sea evidente y anotaciones explícitas cuando formen parte de un contrato público o mejoren realmente la comprensión.
|
||||||
|
- Usar `unknown` para datos cuyo tipo todavía no haya sido validado. No sustituir `unknown` por `any` para evitar realizar narrowing.
|
||||||
|
- Validar todos los datos procedentes de fronteras externas: HTTP, base de datos cuando corresponda, variables de entorno, almacenamiento, mensajes, APIs externas y datos serializados.
|
||||||
|
- No considerar un cast `as Tipo` como validación.
|
||||||
|
- Preferir narrowing, type guards, schemas y discriminated unions frente a assertions.
|
||||||
|
- Preferir `satisfies` cuando se quiera comprobar que un valor cumple un contrato conservando su inferencia concreta.
|
||||||
|
- Evitar enums cuando una unión de literales o un objeto constante tipado represente mejor un conjunto cerrado.
|
||||||
|
- Hacer exhaustivos los `switch` sobre discriminated unions mediante `never` cuando sea útil.
|
||||||
|
- Evitar parámetros booleanos cuyo significado no resulte evidente en la llamada; utilizar opciones o tipos semánticos cuando mejoren la legibilidad.
|
||||||
|
- No crear tipos contenedores, aliases o genéricos que solamente oculten otro tipo sin aportar semántica.
|
||||||
|
- No duplicar tipos que puedan derivarse de una única fuente normativa.
|
||||||
|
- Mantener la opcionalidad exacta del dominio: distinguir cuando sea relevante entre propiedad ausente, `undefined` y `null`.
|
||||||
|
- Preferir estructuras inmutables cuando los datos no deban modificarse.
|
||||||
|
- No capturar excepciones únicamente para volver a lanzarlas sin aportar contexto, conversión o recuperación.
|
||||||
|
- No usar excepciones como flujo normal para resultados de negocio esperables.
|
||||||
|
- Las funciones deben tener contratos claros y evitar efectos laterales inesperados.
|
||||||
|
|
||||||
|
### Node.js
|
||||||
|
|
||||||
|
- No bloquear el event loop con operaciones síncronas de I/O dentro de rutas, servicios ejecutados por petición o procesos concurrentes.
|
||||||
|
- Preferir APIs asíncronas para filesystem, red, criptografía y procesos externos cuando formen parte del flujo de ejecución normal.
|
||||||
|
- Toda operación externa susceptible de quedar bloqueada debe disponer de timeout cuando la API utilizada lo permita.
|
||||||
|
- Utilizar `AbortSignal` o mecanismos equivalentes cuando sea necesario propagar cancelación.
|
||||||
|
- No dispersar accesos a `process.env` por la aplicación. Cargar, validar y normalizar la configuración en un punto definido durante el arranque.
|
||||||
|
- Fallar durante el arranque si falta configuración imprescindible, en lugar de descubrirla durante una petición.
|
||||||
|
- No mantener estado mutable global dependiente de una petición.
|
||||||
|
- No almacenar en memoria información cuya persistencia o coherencia dependa de varias instancias del servidor.
|
||||||
|
- Gestionar explícitamente el cierre ordenado de recursos persistentes cuando corresponda: servidor HTTP, conexiones de base de datos, colas y otros recursos externos.
|
||||||
|
- No ocultar `unhandledRejection`, `uncaughtException` ni errores de infraestructura para mantener artificialmente el proceso funcionando.
|
||||||
|
|
||||||
|
### Express
|
||||||
|
|
||||||
|
- Mantener las rutas y controladores pequeños.
|
||||||
|
- El controlador HTTP traduce entre HTTP y la aplicación; no contiene lógica de negocio.
|
||||||
|
- No acceder directamente al ORM desde routers o controladores salvo que la arquitectura documentada establezca expresamente otra cosa.
|
||||||
|
- Validar `params`, `query`, `headers` y `body` en la frontera HTTP antes de utilizarlos.
|
||||||
|
- No confiar en tipos TypeScript para considerar válidos datos recibidos por HTTP.
|
||||||
|
- Centralizar la transformación de errores a respuestas HTTP.
|
||||||
|
- No repetir bloques `try/catch` en cada handler si el mecanismo de errores de Express ya propaga correctamente los rechazos.
|
||||||
|
- Distinguir errores esperables de aplicación, errores de validación, autenticación/autorización, conflictos y errores inesperados de infraestructura.
|
||||||
|
- No enviar al cliente mensajes internos de excepciones, SQL, stack traces ni detalles de implementación.
|
||||||
|
- Una petición debe producir una única respuesta. Evitar ramas que puedan continuar después de enviar la respuesta.
|
||||||
|
- Los middleware deben tener una responsabilidad concreta y efectos explícitos.
|
||||||
|
- No utilizar middleware global para comportamiento que solo pertenece a una ruta o módulo.
|
||||||
|
- Mantener la composición de routers, middleware, controladores, casos de uso y repositorios según la arquitectura documentada del proyecto.
|
||||||
|
|
||||||
|
### React 19
|
||||||
|
|
||||||
|
- Los componentes y hooks deben ser puros durante render.
|
||||||
|
- No producir efectos laterales durante render.
|
||||||
|
- No modificar props, estado, valores recibidos por hooks ni objetos pertenecientes a renders anteriores.
|
||||||
|
- No llamar componentes como funciones ordinarias; renderizarlos mediante JSX.
|
||||||
|
- Respetar estrictamente las Rules of Hooks.
|
||||||
|
- No utilizar hooks condicionalmente ni después de retornos que hagan variar su orden entre renders.
|
||||||
|
|
||||||
|
#### Organización de componentes
|
||||||
|
|
||||||
|
- Como norma general, cada fichero `.tsx` contiene un único componente React principal.
|
||||||
|
- No agrupar varios componentes funcionales relevantes en un mismo fichero por comodidad.
|
||||||
|
- Extraer un componente a su propio fichero cuando tenga props propias, estado, hooks, lógica de interacción, lógica de renderizado significativa o una responsabilidad identificable.
|
||||||
|
- Un subcomponente privado solo puede permanecer en el mismo fichero cuando sea pequeño, puramente presentacional, inseparable del componente principal y no dificulte la lectura.
|
||||||
|
- Si aparecen varios subcomponentes privados en el mismo fichero, reconsiderar la descomposición y extraerlos.
|
||||||
|
- No crear componentes únicamente para reducir el número de líneas de JSX. Extraer por responsabilidad, semántica o reutilización real.
|
||||||
|
- Evitar componentes monolíticos que mezclen consulta de datos, estado complejo, transformación de datos y grandes bloques de presentación.
|
||||||
|
- Mantener próximos entre sí el componente y los elementos que sean exclusivamente suyos, sin convertir los directorios en estructuras artificialmente profundas.
|
||||||
|
|
||||||
|
#### Estado y efectos
|
||||||
|
|
||||||
|
- Mantener el estado mínimo necesario.
|
||||||
|
- No guardar en estado valores que puedan calcularse correctamente a partir de props, estado existente o datos de consulta durante render.
|
||||||
|
- No utilizar `useEffect` para sincronizar un estado React con otro estado React.
|
||||||
|
- No utilizar `useEffect` para responder a una acción concreta del usuario; ejecutar esa lógica desde el event handler correspondiente.
|
||||||
|
- Utilizar efectos para sincronización real con sistemas externos, suscripciones, APIs imperativas del navegador u otros recursos externos.
|
||||||
|
- Todo efecto que cree una suscripción, listener, temporizador o recurso debe realizar su cleanup correspondiente.
|
||||||
|
- Diseñar efectos de forma que soporten correctamente montaje, desmontaje y nueva ejecución.
|
||||||
|
- No introducir `useMemo` o `useCallback` por defecto. Utilizarlos cuando exista una razón concreta de rendimiento, estabilidad referencial requerida por un contrato o evidencia obtenida mediante profiling.
|
||||||
|
- No duplicar en estado local datos gestionados por TanStack Query salvo que exista una necesidad explícita de edición local temporal.
|
||||||
|
- No copiar props a estado salvo que exista una semántica concreta que lo justifique.
|
||||||
|
- Preferir estado local al componente que lo consume y elevarlo únicamente cuando varios consumidores necesiten compartirlo.
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
- Un custom hook debe encapsular comportamiento React reutilizable o una responsabilidad React claramente identificable.
|
||||||
|
- No crear hooks como simple sustitución de funciones normales.
|
||||||
|
- No crear hooks genéricos anticipando reutilización futura sin consumidores reales.
|
||||||
|
- Mantener los hooks independientes de detalles visuales cuando sea posible.
|
||||||
|
- No ocultar efectos importantes o llamadas remotas dentro de hooks con nombres ambiguos.
|
||||||
|
|
||||||
|
#### Componentes visuales
|
||||||
|
|
||||||
|
- Los componentes presentacionales no deben conocer endpoints, Express, Sequelize ni detalles de persistencia.
|
||||||
|
- Los componentes reutilizables no deben depender directamente de DTOs específicos de Metis Desk cuando puedan expresarse mediante props más pequeñas y semánticas.
|
||||||
|
- Preferir composición mediante `children` y props explícitas frente a componentes con multitud de flags booleanos.
|
||||||
|
- Evitar componentes con muchas variantes booleanas que produzcan combinaciones de estados difíciles de comprender.
|
||||||
|
- Mantener accesibilidad semántica: elemento HTML correcto, etiquetas, relaciones entre controles, navegación por teclado y foco.
|
||||||
|
- No implementar manualmente primitivas que shadcn/ui o Base UI ya proporcionen adecuadamente.
|
||||||
|
|
||||||
|
### Formularios
|
||||||
|
|
||||||
|
- Mantener una única fuente de verdad para cada campo.
|
||||||
|
- Utilizar React Hook Form cuando el formulario tenga complejidad suficiente y siguiendo los patrones existentes del repositorio.
|
||||||
|
- Utilizar schemas Zod como fuente normativa de validación cuando corresponda.
|
||||||
|
- No duplicar manualmente reglas de validación entre schema, formulario y llamada HTTP.
|
||||||
|
- Mostrar errores junto al contexto que los origina.
|
||||||
|
- Diferenciar errores de campo, errores globales del formulario y errores inesperados del servidor.
|
||||||
|
- Evitar envíos duplicados y reflejar visualmente estados pendientes.
|
||||||
|
- No limpiar o cerrar un formulario hasta confirmar que la operación que lo requiere se ha completado correctamente.
|
||||||
|
|
||||||
|
### Acceso a datos en frontend
|
||||||
|
|
||||||
|
- Centralizar query keys y mantenerlas estables.
|
||||||
|
- Las funciones de acceso a API no deben depender de componentes React.
|
||||||
|
- No realizar `fetch` directamente dentro de componentes si el módulo dispone de una capa de API o query establecida.
|
||||||
|
- No utilizar `useEffect` como sustituto de TanStack Query para cargar datos remotos.
|
||||||
|
- Después de una mutación, actualizar o invalidar únicamente las queries afectadas con una estrategia explícita.
|
||||||
|
- No invalidar indiscriminadamente toda la caché para evitar razonar sobre dependencias.
|
||||||
|
- Gestionar explícitamente estados de carga inicial, actualización, error, ausencia de datos y permisos insuficientes.
|
||||||
|
|
||||||
|
### Estructura de ficheros
|
||||||
|
|
||||||
|
- Cada fichero debe tener una responsabilidad reconocible.
|
||||||
|
- Evitar ficheros genéricos como `utils.ts`, `helpers.ts`, `common.ts`, `types.ts` o `constants.ts` convertidos en cajones de sastre.
|
||||||
|
- Ubicar utilidades, tipos y constantes junto al dominio o funcionalidad a la que pertenecen.
|
||||||
|
- Extraerlos a una ubicación compartida únicamente cuando existan consumidores reales en diferentes áreas.
|
||||||
|
- No crear ficheros `index.ts` o barrels indiscriminadamente.
|
||||||
|
- Evitar barrels que oculten dependencias, provoquen ciclos de importación o dificulten localizar el origen de un símbolo.
|
||||||
|
- No crear directorios con un único fichero sin que aporten una frontera conceptual útil.
|
||||||
|
- No reorganizar carpetas solamente por preferencia personal durante una tarea no relacionada.
|
||||||
|
|
||||||
|
### Funciones y responsabilidades
|
||||||
|
|
||||||
|
- Preferir funciones pequeñas con una responsabilidad definida, pero no fragmentar una operación sencilla en multitud de funciones triviales.
|
||||||
|
- Los nombres deben describir intención, no implementación accidental.
|
||||||
|
- Una función que realiza una consulta no debe modificar estado salvo que su contrato lo indique claramente.
|
||||||
|
- Separar cálculo puro de I/O cuando esa separación mejore pruebas y razonamiento.
|
||||||
|
- Reducir anidamiento mediante retornos tempranos cuando mejoren la legibilidad.
|
||||||
|
- No utilizar retornos tempranos que oculten invariantes o hagan difícil seguir el flujo.
|
||||||
|
- No crear parámetros, opciones o extensibilidad que ningún consumidor necesite actualmente.
|
||||||
|
|
||||||
|
### Dependencias
|
||||||
|
|
||||||
|
- Antes de añadir una dependencia, comprobar si el proyecto o la plataforma ya resuelven el problema.
|
||||||
|
- No instalar una biblioteca por una única función trivial que pueda implementarse claramente con APIs estándar.
|
||||||
|
- No sustituir una dependencia ya establecida por otra equivalente sin una razón explícita.
|
||||||
|
- Comprobar compatibilidad con las versiones reales de Node.js, React, TypeScript y demás dependencias del repositorio.
|
||||||
|
- No asumir APIs de una versión distinta a la instalada.
|
||||||
|
|
||||||
|
### Errores y observabilidad
|
||||||
|
|
||||||
|
- Los errores deben conservar causa y contexto suficiente para poder diagnosticarlos.
|
||||||
|
- No registrar el mismo error repetidamente en todas las capas.
|
||||||
|
- Registrar el error en la capa responsable de observarlo o resolverlo.
|
||||||
|
- No registrar tokens, contraseñas, cookies, cuerpos sensibles ni credenciales.
|
||||||
|
- No utilizar `console.log` como mecanismo permanente de observabilidad cuando exista infraestructura de logging.
|
||||||
|
- Los mensajes de error internos deben ser útiles para diagnóstico; los destinados al usuario no deben revelar detalles internos.
|
||||||
|
|
||||||
|
### Pruebas
|
||||||
|
|
||||||
|
- Probar comportamiento observable y contratos, no detalles internos de implementación.
|
||||||
|
- No escribir tests cuyo único objetivo sea aumentar cobertura.
|
||||||
|
- Evitar mocks cuando pueda utilizarse una dependencia real rápida y determinista o un fake sencillo.
|
||||||
|
- Mockear fronteras externas, no cada función interna.
|
||||||
|
- Mantener los tests legibles y con preparación mínima.
|
||||||
|
- Cada corrección de un bug reproducible debe considerar una prueba que falle antes de la corrección y pase después.
|
||||||
|
- Para lógica con estados cerrados, cubrir los casos relevantes y los límites, no solamente el camino feliz.
|
||||||
|
|
||||||
|
### Criterio antes de escribir código
|
||||||
|
|
||||||
|
Antes de implementar:
|
||||||
|
|
||||||
|
1. Buscar implementaciones equivalentes dentro del repositorio.
|
||||||
|
2. Consultar la documentación normativa del proyecto aplicable.
|
||||||
|
3. Identificar qué capa es responsable del comportamiento.
|
||||||
|
4. Comprobar si ya existe un componente, hook, schema, utilidad, Value Object o servicio reutilizable.
|
||||||
|
5. Elegir la solución más pequeña que respete los contratos existentes.
|
||||||
|
6. Evitar introducir una abstracción nueva si un patrón existente resuelve adecuadamente el problema.
|
||||||
|
|
||||||
|
Durante la implementación:
|
||||||
|
|
||||||
|
- No ampliar el alcance para corregir cuestiones no relacionadas.
|
||||||
|
- Si se detecta una mejora ajena a la tarea, mencionarla al finalizar en lugar de modificarla automáticamente.
|
||||||
|
- No alterar APIs públicas, contratos HTTP, schemas, migraciones o comportamiento compartido como efecto secundario accidental.
|
||||||
|
- No crear compatibilidad hacia atrás que nadie haya solicitado cuando se pueda actualizar de forma controlada a todos los consumidores.
|
||||||
|
- No dejar código muerto, implementaciones alternativas comentadas ni TODO vagos.
|
||||||
|
|
||||||
|
Al finalizar:
|
||||||
|
|
||||||
|
- Revisar el diff completo, no únicamente los ficheros editados individualmente.
|
||||||
|
- Comprobar que no se hayan introducido duplicaciones, componentes excesivamente grandes, varios componentes relevantes por fichero, imports no usados, casts innecesarios ni efectos React evitables.
|
||||||
|
- Ejecutar las validaciones apropiadas para el alcance real del cambio.
|
||||||
Loading…
Reference in New Issue
Block a user