581 lines
19 KiB
Plaintext
581 lines
19 KiB
Plaintext
# Cursor Rules - EMERGES TES
|
|
## Arquitectura Clean Architecture + TypeScript + PostgreSQL
|
|
|
|
**Última actualización:** 2025-01-29
|
|
**Versión:** 3.0
|
|
|
|
---
|
|
|
|
## 🎯 DECISIONES TÉCNICAS CONSOLIDADAS
|
|
|
|
### 1. Value Objects (Híbrido)
|
|
- ✅ Entidades usan **tipos simples** (`ContentStatusType`, `ContentPriorityType`)
|
|
- ✅ Value Objects (`ContentStatus`, `ContentPriority`) se usan en **servicios** para validación
|
|
- ✅ Domain Layer mantiene entidades como POJOs inmutables
|
|
|
|
### 2. Serialización (Mappers)
|
|
- ✅ **Mappers separados** en `infrastructure/mappers/`
|
|
- ✅ Domain Layer NO tiene métodos `toJSON`/`fromJSON`
|
|
- ✅ Mappers convierten entre Domain ↔ Persistence
|
|
|
|
### 3. IDs (Application Layer)
|
|
- ✅ UUIDs generados en **Application Layer** (Use Cases)
|
|
- ✅ Pasados como parámetro a métodos `create` de entidades
|
|
- ✅ Permite inyección de IDs en tests
|
|
|
|
### 4. Validación (Híbrido)
|
|
- ✅ **Validaciones básicas** en métodos `create` de entidades (formato, longitud)
|
|
- ✅ **Validaciones complejas** en Application Services (unicidad, dependencias)
|
|
- ✅ **Zod** en Application Layer para validar esquemas de entrada
|
|
|
|
### 5. Fechas (ISO 8601 Strings)
|
|
- ✅ Usar `string` con formato ISO 8601: `"2025-01-25T10:00:00Z"`
|
|
- ✅ NO usar `Date` nativo en entidades
|
|
- ✅ Mappers convierten strings ↔ PostgreSQL TIMESTAMPTZ
|
|
|
|
### 6. Arrays (readonly T[])
|
|
- ✅ Usar `readonly string[]` para arrays inmutables
|
|
- ✅ NO usar `ReadonlyArray<T>` (más verboso)
|
|
- ✅ Mantener inmutabilidad por defecto
|
|
|
|
### 7. Opcionales (Híbrido)
|
|
- ✅ `?` para campos opcionales: `readonly description?: string`
|
|
- ✅ `| null` cuando null tiene significado: `readonly validatedAt: string | null`
|
|
- ✅ Distinguir entre "no proporcionado" vs "explícitamente null"
|
|
|
|
### 8. Errores (Personalizados)
|
|
- ✅ Usar `DomainError`, `ValidationError`, `BusinessRuleError`
|
|
- ✅ NO usar errores genéricos de JavaScript
|
|
- ✅ Errores con código y contexto
|
|
|
|
### 9. Versionado (Números Enteros)
|
|
- ✅ `version: number` y `latestVersion: number`
|
|
- ✅ NO usar semantic versioning (`"1.0.0"`)
|
|
- ✅ Incrementales simples para comparación fácil
|
|
|
|
### 10. JSONB (Union Types)
|
|
- ✅ Union types para `content`: `ProtocolContent | GuideContent | ManualContent`
|
|
- ✅ NO usar `Record<string, unknown>` genérico
|
|
- ✅ Type safety completo con narrowing automático
|
|
|
|
---
|
|
|
|
## 📐 ARQUITECTURA
|
|
|
|
### Estructura de Capas
|
|
|
|
```
|
|
domain/ → Entidades, Value Objects, Repository Interfaces
|
|
application/ → Services, Use Cases, DTOs
|
|
infrastructure/ → Repository Implementations, Mappers, Database
|
|
presentation/ → Routes, Middleware, Validators (Zod)
|
|
shared/ → Types, Errors, Utils
|
|
```
|
|
|
|
### Reglas de Dependencias
|
|
|
|
- ✅ **Regla de Dependencia:** Las dependencias deben apuntar siempre hacia adentro (hacia el Dominio)
|
|
- ✅ **Ninguna capa interna puede conocer detalles de una capa externa**
|
|
- ✅ Domain: NO depende de nadie
|
|
- ✅ Application: Solo depende de Domain
|
|
- ✅ Infrastructure: Depende de Domain y Application
|
|
- ✅ Presentation: Depende de Application y Domain
|
|
|
|
---
|
|
|
|
## 🔒 REGLAS DE CÓDIGO
|
|
|
|
### TypeScript
|
|
|
|
- ✅ **PROHIBIDO el uso de `any`** - Todos los tipos deben ser estrictos y explícitos
|
|
- ✅ **Tipado Estricto:** Todos los tipos deben estar definidos explícitamente en `/types` o dentro del dominio
|
|
- ✅ Usar tipos explícitos, evitar `any`
|
|
- ✅ Usar `readonly` para propiedades inmutables
|
|
- ✅ Preferir `interface` sobre `type` para objetos extensibles
|
|
- ✅ Usar `type` para unions, intersections, primitives
|
|
- ✅ NO usar `@ts-ignore` sin comentario explicativo
|
|
- ✅ **Higiene de datos:** Si un tipo no puede ser inferido, definirlo explícitamente
|
|
- ✅ **Tipos en dominio:** Tipos de dominio deben estar en `domain/types/` o dentro de entidades
|
|
|
|
### Entidades de Dominio
|
|
|
|
- ✅ Todas las propiedades `readonly`
|
|
- ✅ Tipos simples (no clases) en interfaces
|
|
- ✅ Métodos estáticos `create()` para construcción
|
|
- ✅ Validaciones básicas en `create()`
|
|
- ✅ IDs recibidos como parámetro (no generados internamente)
|
|
|
|
```typescript
|
|
// ✅ CORRECTO
|
|
interface ContentItem {
|
|
readonly id: string;
|
|
readonly title: string;
|
|
readonly status: ContentStatusType; // Tipo simple
|
|
readonly createdAt: string; // ISO 8601
|
|
readonly tags: readonly string[]; // Array inmutable
|
|
}
|
|
|
|
static create(
|
|
id: string, // ID inyectado
|
|
title: string,
|
|
// ...
|
|
): ContentItem {
|
|
// Validación básica
|
|
if (!title || title.trim().length === 0) {
|
|
throw new ValidationError('Título es obligatorio');
|
|
}
|
|
return { id, title: title.trim(), ... };
|
|
}
|
|
```
|
|
|
|
### Value Objects
|
|
|
|
- ✅ Clases con constructor privado
|
|
- ✅ Métodos estáticos `fromString()`, `create()`
|
|
- ✅ Métodos `toString()`, `equals()`, `canTransitionTo()`
|
|
- ✅ Usados en Services, NO en entidades
|
|
|
|
```typescript
|
|
// ✅ CORRECTO
|
|
export class ContentStatus {
|
|
private constructor(private readonly value: string) {}
|
|
|
|
static fromString(value: string): ContentStatus {
|
|
// Validación
|
|
return new ContentStatus(value);
|
|
}
|
|
|
|
toString(): string {
|
|
return this.value;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Mappers
|
|
|
|
- ✅ En `infrastructure/mappers/`
|
|
- ✅ Métodos estáticos `toDomain()` y `toPersistence()`
|
|
- ✅ Conversión de tipos (string ↔ Date, snake_case ↔ camelCase)
|
|
- ✅ **PROHIBIDO:** Pasar entidades de base de datos directamente a la UI
|
|
- ✅ **OBLIGATORIO:** Implementar Mappers en capa de infraestructura para traducir datos de persistencia a entidades de dominio
|
|
- ✅ **Validación Zod:** Todos los mappers deben validar datos con Zod antes de convertir a dominio
|
|
|
|
```typescript
|
|
// ✅ CORRECTO - Con validación Zod
|
|
import { z } from 'zod';
|
|
|
|
const ContentItemRowSchema = z.object({
|
|
id: z.string().min(1),
|
|
status: z.string(),
|
|
created_at: z.string(),
|
|
// ...
|
|
});
|
|
|
|
class ContentItemMapper {
|
|
static toDomain(row: unknown): ContentItem {
|
|
// Validar con Zod antes de convertir
|
|
const validated = ContentItemRowSchema.parse(row);
|
|
return {
|
|
id: validated.id,
|
|
status: validated.status as ContentStatusType,
|
|
createdAt: validated.created_at, // Ya es string ISO
|
|
// ...
|
|
};
|
|
}
|
|
|
|
static toPersistence(item: ContentItem): Record<string, unknown> {
|
|
return {
|
|
id: item.id,
|
|
status: item.status,
|
|
created_at: item.createdAt, // String ISO
|
|
// ...
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### Validación
|
|
|
|
- ✅ Zod en Application Layer para esquemas de entrada
|
|
- ✅ Validaciones básicas en Domain (`create()`)
|
|
- ✅ Validaciones complejas en Application Services
|
|
- ✅ Mensajes de error claros y específicos
|
|
|
|
### Errores
|
|
|
|
- ✅ Usar `DomainError`, `ValidationError`, `BusinessRuleError`
|
|
- ✅ Incluir código y contexto
|
|
- ✅ NO silenciar errores con `catch` vacío
|
|
- ✅ **Early Returns para errores:** Usar retornos tempranos en lugar de anidar condiciones
|
|
|
|
```typescript
|
|
// ✅ CORRECTO
|
|
throw new ValidationError('Título es obligatorio', {
|
|
field: 'title',
|
|
value: title
|
|
});
|
|
|
|
throw new BusinessRuleError('Slug ya existe', {
|
|
slug,
|
|
existingId: existing.id
|
|
});
|
|
```
|
|
|
|
### Funciones
|
|
|
|
- ✅ Máximo 20-30 líneas
|
|
- ✅ Una sola responsabilidad
|
|
- ✅ Nombres descriptivos
|
|
- ✅ Parámetros máximo 3-4, usar objetos si hay más
|
|
- ✅ **Early Returns obligatorios:** Usar retornos tempranos para manejar condiciones de error o datos no definidos
|
|
- ✅ **Regla de los 15 minutos:** Si la lógica no puede entenderse en 15 minutos, simplificar o dividir en módulos más pequeños
|
|
|
|
### Base de Datos
|
|
|
|
- ✅ Usar parámetros preparados (nunca concatenar SQL)
|
|
- ✅ Validar datos antes de insertar/actualizar
|
|
- ✅ Usar transacciones para operaciones múltiples
|
|
- ✅ Índices apropiados para queries frecuentes
|
|
|
|
---
|
|
|
|
## 📁 CONVENCIONES DE ARCHIVOS
|
|
|
|
### Nomenclatura
|
|
|
|
- **Archivos TypeScript:** `kebab-case.ts` o `kebab-case.tsx` para componentes React
|
|
- **Componentes React:** `kebab-case.tsx` (ej. `rcp-protocol-view.tsx`, `drug-card.tsx`)
|
|
- **Carpetas:** `kebab-case` (siempre)
|
|
- **Tipos/Interfaces:** `PascalCase`
|
|
- **Funciones:** `camelCase`
|
|
- **Constantes:** `UPPER_SNAKE_CASE`
|
|
- **Event Handlers:** Prefijar con `handle` (ej. `handleClick`, `handleSubmit`)
|
|
|
|
### Estructura
|
|
|
|
```
|
|
domain/entities/
|
|
└── ContentItem.ts # Entidad de dominio
|
|
|
|
application/services/
|
|
└── ContentService.ts # Servicio de aplicación
|
|
|
|
infrastructure/repositories/
|
|
└── ContentRepository.ts # Repositorio de infraestructura
|
|
|
|
infrastructure/mappers/
|
|
└── ContentItemMapper.ts # Mapper de infraestructura
|
|
|
|
presentation/routes/
|
|
└── content.ts # Rutas Express
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 TESTING
|
|
|
|
### Estructura
|
|
|
|
- ✅ Tests unitarios en `tests/unit/`
|
|
- ✅ Tests de integración en `tests/integration/`
|
|
- ✅ Tests de API en `tests/api/`
|
|
- ✅ Mocks en `tests/mocks/`
|
|
- ✅ Fixtures en `tests/fixtures/`
|
|
|
|
### Buenas Prácticas
|
|
|
|
- ✅ Un test por caso de uso
|
|
- ✅ Tests independientes
|
|
- ✅ Usar mocks para dependencias externas
|
|
- ✅ Arrange-Act-Assert claro
|
|
- ✅ Cobertura mínima: 80%
|
|
|
|
---
|
|
|
|
## 🚫 ANTI-PATRONES A EVITAR
|
|
|
|
### ❌ NO hacer:
|
|
|
|
- Funciones de más de 30 líneas
|
|
- Mutar objetos directamente (usar inmutabilidad)
|
|
- Validar solo en frontend
|
|
- Usar `any` en TypeScript
|
|
- Código duplicado (DRY)
|
|
- Imports no usados
|
|
- Código comentado (eliminar o documentar)
|
|
- Catch vacío sin logging
|
|
- SQL concatenado (usar parámetros)
|
|
- Tests que dependen de otros tests
|
|
- Métodos `toJSON`/`fromJSON` en entidades
|
|
- Generar IDs dentro de entidades
|
|
- Usar `Date` nativo en entidades
|
|
- Usar `ReadonlyArray<T>` (usar `readonly T[]`)
|
|
- **Componentes de fetching sin estados de loading/error**
|
|
- **Acceder a propiedades sin verificar que el objeto existe** (usar optional chaining o guard clauses)
|
|
- **Código que requiere más de 15 minutos para entender** (simplificar o dividir)
|
|
- **Pasar entidades de BD directamente a UI** (usar mappers)
|
|
- **Casos de uso que invocan otros casos de uso** (lógica circular)
|
|
- **Event handlers sin prefijo `handle`**
|
|
- **Nomenclatura incorrecta** (usar kebab-case para componentes)
|
|
- **TODOs, FIXMEs, comentarios de cierre** en código final
|
|
- **Commits no convencionales** o mensajes >60 caracteres
|
|
- **Falta de validación Zod** en entradas externas
|
|
|
|
---
|
|
|
|
## 📚 PATRONES RECOMENDADOS
|
|
|
|
### Repository Pattern
|
|
|
|
```typescript
|
|
interface IContentRepository {
|
|
findById(id: string): Promise<ContentItem | null>;
|
|
findAll(filters: ContentFilters): Promise<{ items: ContentItem[]; total: number }>;
|
|
save(content: ContentItem): Promise<ContentItem>;
|
|
delete(id: string): Promise<void>;
|
|
}
|
|
```
|
|
|
|
### Service Layer
|
|
|
|
```typescript
|
|
class ContentService {
|
|
constructor(
|
|
private readonly repository: IContentRepository,
|
|
private readonly mapper: ContentItemMapper
|
|
) {}
|
|
|
|
async createContent(input: CreateContentDTO): Promise<ContentItem> {
|
|
// 1. Validar con Zod
|
|
const validated = createContentSchema.parse(input);
|
|
|
|
// 2. Validaciones complejas
|
|
if (await this.repository.existsBySlug(validated.slug)) {
|
|
throw new BusinessRuleError('Slug ya existe');
|
|
}
|
|
|
|
// 3. Generar ID
|
|
const id = randomUUID();
|
|
|
|
// 4. Crear entidad (validaciones básicas aquí)
|
|
const content = ContentItem.create(id, validated.title, ...);
|
|
|
|
// 5. Persistir
|
|
return await this.repository.save(content);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Use Case Pattern
|
|
|
|
```typescript
|
|
class CreateContentUseCase {
|
|
constructor(
|
|
private readonly repository: IContentRepository,
|
|
private readonly validator: ContentValidator
|
|
) {}
|
|
|
|
async execute(input: CreateContentDTO): Promise<ContentItem> {
|
|
// Orquestación del caso de uso
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔍 CODE REVIEW CHECKLIST
|
|
|
|
Antes de hacer commit, verificar:
|
|
|
|
- [ ] Funciones <30 líneas
|
|
- [ ] Validación con Zod en todos los inputs
|
|
- [ ] Tests escritos y pasando
|
|
- [ ] Sin código duplicado
|
|
- [ ] Sin imports no usados
|
|
- [ ] **Sin `any` en TypeScript** (PROHIBIDO)
|
|
- [ ] Entidades inmutables (`readonly`)
|
|
- [ ] Manejo de errores apropiado
|
|
- [ ] Logs de auditoría donde corresponda
|
|
- [ ] Documentación de funciones complejas
|
|
- [ ] IDs generados en Application Layer
|
|
- [ ] Fechas como strings ISO 8601
|
|
- [ ] Arrays como `readonly T[]`
|
|
- [ ] Mappers separados en Infrastructure
|
|
- [ ] **Componentes de fetching tienen estados de loading y error**
|
|
- [ ] **Early returns para condiciones de error y datos undefined**
|
|
- [ ] **Código comprensible en menos de 15 minutos** (si no, simplificar)
|
|
- [ ] **Guard clauses aplicadas antes de acceder a propiedades**
|
|
- [ ] **Nomenclatura kebab-case para componentes React**
|
|
- [ ] **Event handlers prefijados con `handle`**
|
|
- [ ] **Mappers validan con Zod antes de convertir a dominio**
|
|
- [ ] **Casos de uso no invocan otros casos de uso**
|
|
- [ ] **Accesibilidad AA cumplida (roles ARIA, navegación por teclado)**
|
|
- [ ] **Semántica HTML apropiada**
|
|
- [ ] **Sin TODOs ni marcadores en código final**
|
|
- [ ] **Commits convencionales con mensajes <60 caracteres**
|
|
|
|
---
|
|
|
|
## 📖 REFERENCIAS
|
|
|
|
- SPEC.md: Arquitectura completa del proyecto
|
|
- Clean Architecture: Robert C. Martin
|
|
- Domain-Driven Design: Eric Evans
|
|
- Zod: https://zod.dev
|
|
|
|
---
|
|
|
|
## 🛡️ REGLAS DE SEGURIDAD Y ROBUSTEZ
|
|
|
|
### Higiene de Datos
|
|
|
|
- ✅ **PROHIBIDO el uso de `any`** - Todos los tipos deben ser estrictos
|
|
- ✅ Validar todos los datos de entrada antes de procesarlos
|
|
- ✅ Usar tipos explícitos en lugar de inferencia cuando hay ambigüedad
|
|
- ✅ Verificar que arrays/objetos existen antes de acceder a propiedades
|
|
|
|
### Estados Obligatorios en Fetching
|
|
|
|
- ✅ **OBLIGATORIO:** Todos los hooks/componentes que obtienen datos deben manejar:
|
|
- Estado `loading` (mientras se cargan los datos)
|
|
- Estado `error` (si falla la carga)
|
|
- Estado `success` (datos disponibles)
|
|
- Estado `not_found` (recurso no encontrado)
|
|
- ✅ Usar Discriminated Unions para type safety
|
|
- ✅ Renderizar componentes de fallback (`PageLoader`, `NotFound`) según el estado
|
|
- ✅ **Estados de Carga y Error:** Todos los componentes que realicen obtención de datos deben incluir obligatoriamente estados de loading y error
|
|
|
|
### Andragogía clínica y Stress-Ready Design (112/061)
|
|
|
|
La interfaz debe actuar como **socio cognitivo**, no como manual digital: reducir carga cognitiva y respetar la autonomía del facultativo en emergencias.
|
|
|
|
- ✅ **Orientación al problema:** Estructurar por problemas clínicos (ej. "Parada Cardiorrespiratoria"); contenido accionable ("qué hacer") en menos de 2 clics.
|
|
- ✅ **Autonomía:** Navegación no lineal (saltar a dosis/algoritmos sin secuencia rígida); Offline-First cuando sea posible.
|
|
- ✅ **Experiencia previa:** Terminología y modelos familiares (estándares clínicos); resúmenes visuales + detalle expandible para quien lo necesite.
|
|
- ✅ **Procesamiento sensorial / estrés:** Jerarquía visual (Lookability): elementos críticos (alertas, dosis) visualmente dominantes; multimodalidad (señales auditivas, diagramas claros) cuando aplique.
|
|
- ✅ **Simulación y maestría:** Modos de práctica/simulación y feedback inmediato (checklists, confirmaciones) para transferir habilidades al mundo real.
|
|
|
|
Referencia completa: `docs/ANDRAGOGIA_STRESS_READY_112.md`
|
|
|
|
### Seguridad con Early Returns
|
|
|
|
- ✅ **SIEMPRE usar retornos tempranos** para manejar:
|
|
- Datos `undefined` o `null`
|
|
- Condiciones de error
|
|
- Validaciones fallidas
|
|
- Estados de carga
|
|
- ✅ Evitar anidar condiciones profundamente
|
|
- ✅ Aplicar guard clauses al inicio de funciones/componentes
|
|
|
|
```typescript
|
|
// ✅ CORRECTO - Early returns
|
|
function processData(data: Data | undefined): Result {
|
|
if (!data) return { error: 'Datos no disponibles' };
|
|
if (!data.id) return { error: 'ID requerido' };
|
|
if (data.status === 'error') return { error: data.message };
|
|
|
|
// Solo aquí procesamos datos válidos
|
|
return { success: true, result: transform(data) };
|
|
}
|
|
|
|
// ❌ INCORRECTO - Anidación profunda
|
|
function processData(data: Data | undefined): Result {
|
|
if (data) {
|
|
if (data.id) {
|
|
if (data.status !== 'error') {
|
|
return { success: true, result: transform(data) };
|
|
}
|
|
}
|
|
}
|
|
return { error: 'Error' };
|
|
}
|
|
```
|
|
|
|
### Regla de los 15 Minutos
|
|
|
|
- ✅ **Código debe ser comprensible en 15 minutos**
|
|
- ✅ Si una función/componente es demasiado compleja:
|
|
- Dividirla en funciones más pequeñas
|
|
- Extraer lógica a hooks personalizados
|
|
- Crear componentes intermedios
|
|
- Documentar la lógica compleja con comentarios claros
|
|
- ✅ **Aplicar a IA:** Si Cursor propone una lógica que no puede ser comprendida por un humano en menos de 15 minutos, debe ser simplificada o dividida en submódulos
|
|
- ✅ Evitar "deuda de comprensión" - código que solo el autor entiende
|
|
|
|
```typescript
|
|
// ✅ CORRECTO - Función simple y clara
|
|
function calculateTotal(items: Item[]): number {
|
|
if (!items || items.length === 0) return 0;
|
|
return items.reduce((sum, item) => sum + item.price, 0);
|
|
}
|
|
|
|
// ❌ INCORRECTO - Demasiado compleja, requiere más de 15 min para entender
|
|
function processComplexData(data: any): any {
|
|
// 50 líneas de lógica compleja mezclada...
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 GOBERNANZA DEL CÓDIGO IA
|
|
|
|
### Higiene de Commits
|
|
|
|
- ✅ **Commits Convencionales:** Usar siempre formato convencional (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`)
|
|
- ✅ **Mensajes Cortos:** Mantener los mensajes de commit por debajo de 60 caracteres
|
|
- ✅ **Descripción Opcional:** Si se necesita más contexto, usar cuerpo del commit después de línea vacía
|
|
|
|
```bash
|
|
# ✅ CORRECTO
|
|
feat: añadir guard clauses en Farmacos.tsx
|
|
fix: corregir acceso inseguro a drug.id
|
|
docs: actualizar SPEC.md con decisiones técnicas
|
|
|
|
# ❌ INCORRECTO
|
|
Added guard clauses to Farmacos component # ❌ No convencional
|
|
fix: corregir el problema de acceso inseguro a la propiedad id del objeto drug que causaba errores de runtime # ❌ >60 caracteres
|
|
```
|
|
|
|
### Documentación Continua
|
|
|
|
- ✅ **Actualizar SPEC.md:** Por cada cambio mayor, actualizar `SPEC.md` con decisiones técnicas
|
|
- ✅ **Registro de Decisiones:** Mantener ADL (Architecture Decision Log) para decisiones arquitectónicas importantes
|
|
- ✅ **Memoria del Proyecto:** La IA debe mantener la "memoria" del proyecto actualizando documentación
|
|
|
|
### Prohibición de Marcadores
|
|
|
|
- ❌ **NO dejar TODOs** en código final
|
|
- ❌ **NO dejar comentarios de llaves de cierre** (ej. `} // end function`)
|
|
- ❌ **NO dejar marcadores de posición** (ej. `// FIXME`, `// HACK`, `// XXX`)
|
|
- ✅ Si hay trabajo pendiente, crear ticket o documentar en SPEC.md
|
|
|
|
```typescript
|
|
// ❌ INCORRECTO - Marcadores prohibidos
|
|
function calculateDose() {
|
|
// TODO: añadir validación de peso
|
|
return weight * dose;
|
|
} // end calculateDose
|
|
|
|
// ✅ CORRECTO - Código limpio
|
|
function calculateDose(weight: number, dose: number): number {
|
|
if (weight <= 0) throw new ValidationError('Peso debe ser positivo');
|
|
return weight * dose;
|
|
}
|
|
```
|
|
|
|
### Checklist antes de aceptar cambios (IA)
|
|
|
|
**Antes de que el usuario acepte cualquier cambio propuesto, la IA debe verificar y responder explícitamente:**
|
|
|
|
1. **Clean Architecture:** ¿El código cumple con la Clean Architecture y las capas definidas? (Domain → Application → Infrastructure → Presentation; sin dependencias invertidas.)
|
|
2. **Pruebas:** ¿Se han incluido pruebas unitarias con una cobertura mínima del 80% para el código nuevo o modificado?
|
|
3. **Andragogía / UX:** ¿La interfaz reduce la latencia cognitiva siguiendo los principios de andragogía? (Información crítica visible, estados loading/error, fallbacks.)
|
|
4. **Seguridad / PII:** ¿Se han enmascarado los datos sensibles (PII) y evitado claves API en texto plano?
|
|
|
|
- ✅ Documento completo: `docs/CHECKLIST_ANTES_ACEPTAR_CAMBIOS.md`
|
|
- ✅ Si algún punto no se cumple, indicarlo y proponer corrección o excepción documentada.
|
|
|
|
---
|
|
|
|
**Fin de Cursor Rules**
|