


Crea una aplicación TypeScript full-stack con esquemas de API compartidos por servidor y cliente
Úsalo al crear o cambiar una aplicación TypeScript full-stack. La IA define una sola vez cada solicitud y respuesta de la API para rutas y hooks del cliente, comprueba la autenticación antes de leer la entrada, mantiene coherentes dependencias, caché y estilos, y escribe pruebas rápidas.
Para usar estas reglas de IA
## Mantén las dependencias entre paquetes en un solo sentido y decide dónde va cada estado
Organiza la base de código para que la propiedad, la dirección de las dependencias y la ubicación del estado sigan siendo predecibles a medida que crezca el sistema.
### Estructura por responsabilidad
- Da a cada componente, hook, almacén, servicio y paquete un propósito claro, y prefiere componer unidades pequeñas en lugar de añadir ramas y modos a una unidad que ya sea compleja.
- Mantén el código de la aplicación por encima de los paquetes reutilizables en el grafo de dependencias; los paquetes de nivel inferior no deben importar módulos de la aplicación.
- Mantén los servicios aislados libres de frameworks de interfaz, registros, SDK de proveedores y motores de ejecución que no estén relacionados.
- Comparte la autenticación mediante una sesión y un modelo de datos compatibles en lugar de volver a implementarla en cada aplicación.
### Conserva la propiedad de los tipos y del estado
- Define interfaces explícitas para las propiedades y el estado de los componentes, las entradas de las funciones y los valores devueltos.
- No uses `any`; utiliza `unknown` con guardas de tipo cuando el tipo sea realmente incierto.
- Mantén el estado del servidor en la biblioteca de estado del servidor, el estado global del cliente en un almacén y el estado local de presentación en el componente.
- Divide un almacén complejo en módulos de implementación y de tipos; conserva de forma persistente solo el estado que deba sobrevivir a las recargas y selecciona explícitamente los campos persistentes.
## Usa los helpers y herramientas compartidos del repositorio en vez de copias locales
Utiliza una única cadena de herramientas canónica y patrones de implementación compartidos en lugar de crear sustitutos locales.
### Aplica convenciones de código coherentes
- Utiliza el gestor de paquetes, el formateador, el linter, el verificador de tipos y los comandos de auditoría elegidos por el repositorio.
- Utiliza registros estructurados en lugar de la salida de consola; los envoltorios de rutas con ámbito de solicitud deben adjuntar automáticamente identificadores de solicitud.
- Sigue un orden coherente para los nombres y las importaciones; utiliza importaciones solo de tipos, aserciones de constantes, tipos explícitos para elementos de referencia y TSDoc en lugar de comentarios decorativos o sin estructura.
- Prefiere las importaciones absolutas. Crea un archivo barrel solo cuando una carpeta tenga al menos 3 exportaciones y no vuelvas a exportar desde archivos que no sean barrel.
### Reutiliza ayudantes probados
- Utiliza ayudantes compartidos para generar ID, introducir demoras, normalizar errores, extraer mensajes, realizar clonaciones profundas, filtrar objetos, truncar y aplicar retroceso de reintentos con variación aleatoria; no los recrees con paquetes locales ni lógica específica para una sola ocasión.
- Integra en línea un ayudante que use 1 consumidor; pásalo a un módulo de utilidades cuando lo necesiten al menos 2 archivos.
- Extrae un componente cuando supere aproximadamente 50 líneas, sirva al menos a 2 llamadores o posea estado o lógica; mantén en línea un fragmento meramente presentacional de uso único con menos de 10 líneas.
## Define una sola vez cada solicitud y respuesta de la API y justifica cada fetch directo
Define una sola vez cada solicitud y respuesta HTTP para que las rutas y los clientes no deriven hacia formatos de transmisión incompatibles.
### Haz del contrato la fuente de verdad del límite
- Mantén un módulo de contrato por familia de recursos, con esquemas separados para los parámetros de ruta, los valores de consulta, el cuerpo, los encabezados y la respuesta, combinados en un único contrato de ruta.
- Exporta esquemas con nombre y alias con nombre para los tipos de entrada y salida de los clientes, y reutiliza primitivas de identificadores compartidas en vez de derivar tipos de transmisión improvisados o redefinir identificadores basados en cadenas.
- Permite que los validadores de dominio utilicen directamente la biblioteca de esquemas, pero mantén los esquemas de los límites de las rutas fuera de los controladores de rutas y de los clientes.
### Controla explícitamente las excepciones
- Exige una anotación razonada justo encima de cualquier raw fetch excepcional, conversión doble, lectura de JSON sin procesar o respuesta deliberadamente sin tipar.
- Permite raw fetch solo en casos como streaming, transferencia binaria, carga multipart, URL firmadas, redirecciones de OAuth u orígenes externos.
- Permite lecturas de JSON sin procesar solo para envoltorios o análisis tolerantes que no puedan utilizar el analizador estándar, y respuestas sin tipar solo para datos realmente opacos.
- Mantén las excepciones legítimas de archivos completos en una lista de permitidos revisada, en lugar de dispersar elusiones línea por línea.
- Haz que una auditoría estricta de límites falle si faltan motivos o hay esquemas locales de rutas, lecturas sin procesar, fetch no aprobados o conversiones dobles inseguras.
## Añade una ruta de API y su hook de cliente empezando por el esquema
Añade una funcionalidad de límite siguiendo una secuencia fija para que la autenticación, la validación, el tipado de las respuestas y el almacenamiento en caché concuerden de extremo a extremo.
### Sigue la secuencia de implementación
1. Redacta el contrato y sus tipos de entrada y salida con nombre.
2. Envuelve la ruta con el envoltorio canónico de contexto de solicitud y gestión de errores, componiendo el middleware compartido de autenticación, limitación de frecuencia y control de acceso en lugar de volver a implementarlo en cada ruta.
3. Autentica y autoriza antes de analizar entradas no confiables y, después, analiza todas las partes de la solicitud mediante el contrato.
4. Devuelve exactamente la estructura JSON declarada por el esquema de respuesta.
5. Añade un hook de cliente tipado que envíe y valide los datos mediante el mismo contrato.
6. Utiliza el hook en el componente y muestra su mensaje de error tipado.
### Revisa los esquemas como si fueran migraciones
- Distingue la omisión de `null`; combinar optional y nullable crea un tercer estado y debe hacerse de forma intencionada.
- Compara cada punto de llamada de respuesta con el esquema de respuesta declarado.
- Establece límites explícitos para cadenas, matrices, topes y tamaños, con errores descriptivos específicos de cada campo.
- Trata los esquemas unknown como excepcionales y documenta por qué la carga útil es opaca; prefiere las uniones discriminadas cuando el formato de transmisión contenga un discriminador.
- Utiliza revisión humana para la calidad semántica; las auditorías estructurales no pueden detectar todos los límites débiles ni las estructuras de respuesta imprecisas.
## Mantén correcta la caché de consultas tras cancelaciones y actualizaciones optimistas
Haz explícitas la cancelación, el almacenamiento en caché, la invalidación y las actualizaciones optimistas en vez de ocultar el estado del servidor en el estado del componente.
### Crea hooks y claves de consulta estables
- Utiliza una referencia cuando una función de retorno estable deba leer la entrada más reciente, y actualiza esa referencia cuando cambie la entrada.
- Reenvía la señal de cancelación desde cada función de consulta y asigna a cada consulta un intervalo de vigencia explícito.
- Crea claves jerárquicas desde una raíz hasta los prefijos de lista y detalle para una invalidación dirigida, y conserva los datos anteriores solo para consultas con claves variables, no para consultas estáticas.
### Reconcilia las mutaciones de forma segura
- Antes de una actualización optimista, cancela las consultas afectadas y guarda el valor anterior de la caché para poder restaurarlo si se produce un error.
- Reconcilia e invalida al finalizar, no solo cuando haya éxito, porque tanto el éxito como el fracaso requieren coherencia en la caché.
- Prefiere la invalidación dirigida a invalidar todo el árbol de recursos.
- No añadas innecesariamente métodos u objetos de mutación estables a las dependencias de las funciones de retorno.
- Dirige el JSON del mismo origen a través del ayudante de solicitudes tipado; las excepciones de raw fetch deben cumplir la política de límites documentada.
## Deja que cada componente compartido controle su aspecto y ajústalo con props
Trata la apariencia de los componentes compartidos como una única fuente de verdad que pertenece al componente, no a cada consumidor.
### Mantén la presentación local y componible
- No modifiques los estilos globales para una funcionalidad local; limita los estilos a los componentes.
- Utiliza el ayudante de clases condicionales y la notación abreviada de dimensiones del proyecto en lugar de duplicar la lógica de creación de clases.
- Utiliza herramientas de variantes solo cuando un componente tenga al menos 2 variantes reales; utiliza una clase condicional sencilla para alternar un estado.
- Importa los componentes compartidos mediante el punto de entrada público compatible y no a través de subrutas internas.
- Comprueba que existan las variables CSS a las que se hace referencia, porque una variable no definida puede recurrir silenciosamente a un color no deseado.
### Expresa la intención mediante propiedades
- Expón propiedades para errores, adornos, etiquetas, indicaciones, estado obligatorio y modos de comportamiento; reserva las anulaciones de clases del consumidor para la disposición y el tamaño, no para bordes, rellenos, radios, alturas, colores ni tratamiento del foco canónicos.
- Utiliza propiedades de unión discriminada para los modos en lugar de mantener componentes casi duplicados.
- Utiliza el envoltorio canónico de campos con etiqueta dentro del cuerpo de los cuadros modales para que los espacios de los campos se alineen con los encabezados y pies.
- Retira las variantes heredadas después de la migración en lugar de dejar rutas paralelas en el sistema de diseño.
## Escribe pruebas rápidas en Vitest con mocks compartidos y temporizadores simulados
Utiliza el ejecutor de pruebas estándar del repositorio, sus fixtures globales y patrones de tiempo deterministas.
### Aísla el comportamiento
- Nombra cada prueba junto a su código fuente mediante el sufijo de prueba estándar del repositorio.
- Reutiliza los mocks globales y las fábricas compartidas, sustituyendo uno solo cuando una prueba necesite un comportamiento diferente; limpia el estado de los mocks antes de cada prueba y define explícitamente los valores devueltos por cada prueba.
- Simula los registros pesados y las dependencias de proveedores cuando la prueba no los examine.
- Utiliza un entorno de ejecución de servidor salvo que se necesiten API del navegador.
- Evita los temporizadores reales; utiliza temporizadores simulados o la demora determinista más pequeña que requiera el comportamiento.
### Evita la costosa rotación de módulos
- En Vitest, prefiere los mocks elevados y las importaciones estáticas.
- No combines restablecimientos de módulos, mocks tardíos e importaciones dinámicas, y no importes implementaciones reales mediante `importActual` cuando basten mocks explícitos.
- Mantén explícitos los mocks de autenticación y registro en lugar de llamar a ayudantes que oculten mocks tardíos.
- Ejecuta la auditoría estricta de los límites de la API junto con las pruebas pertinentes antes de la revisión.
## Añade integraciones sin convertir variables antes de que se resuelvan
Crea las integraciones en orden de dependencia y conserva las referencias sin resolver hasta la ejecución.
### Sigue la secuencia de integración
1. Define y registra herramientas con identificadores `snake_case` estables.
2. Añade el bloque consumidor y regístralo en el orden canónico.
3. Añade el icono y los metadatos necesarios.
4. Añade un activador solo cuando la integración lo necesite.
5. Verifica el comportamiento del servicio según la documentación oficial de la API.
### Respeta los tiempos del ciclo de vida
- Distingue la configuración en el momento de la serialización de la resolución de parámetros durante la ejecución.
- Nunca fuerces la conversión de tipos al serializar valores sin resolver; hacerlo puede destruir referencias dinámicas.
- Realiza conversiones numéricas y de otros tipos solo después de que las variables se resuelvan durante la ejecución.
- Mantén sincronizados los metadatos de herramientas, bloques, activadores, autenticación y entradas de archivos.
- Ejecuta el linter, las comprobaciones de tipos, las pruebas y las auditorías estrictas de límites; después, revisa la diferencia final para comprobar la coherencia de los contratos, la caché, los estilos y el registro.
