# IMPACTO DE CAMBIOS EN ENTITY

**Version:** 1.0.0
**Fecha:** 2025-12-08
**Prioridad:** OBLIGATORIA - Consultar antes de modificar Entities
**Sistema:** SIMCO + CAPVED

---

## PROPOSITO

Documentar especificamente los impactos de modificar Entities de TypeORM, que son el puente entre la base de datos y la logica de negocio.

---

## 1. PRINCIPIO FUNDAMENTAL

```
╔══════════════════════════════════════════════════════════════════════╗
║  ENTITY ES REFLEJO DE DDL, NO AL REVES                               ║
║                                                                       ║
║  DDL (fuente) ──────▶ Entity (reflejo) ──────▶ DTO (contrato API)   ║
║                                                                       ║
║  ⚠️  NUNCA crear Entity sin DDL existente                            ║
║  ⚠️  NUNCA modificar Entity sin verificar DDL primero                ║
╚══════════════════════════════════════════════════════════════════════╝
```

---

## 2. TIPOS DE CAMBIOS EN ENTITY

### 2.1 Cambios de Columna

| Tipo de Cambio | Impacto DDL | Impacto DTO | Impacto Service | Impacto Frontend |
|----------------|-------------|-------------|-----------------|------------------|
| Agregar campo | SI | SI | Posible | SI |
| Eliminar campo | SI | SI | Verificar | SI |
| Renombrar campo | SI | SI | SI | SI |
| Cambiar tipo | SI | SI | Posible | SI |
| Cambiar nullable | SI | SI | Posible | SI |
| Agregar default | SI | Posible | NO | NO |

### 2.2 Cambios de Relacion

| Tipo de Cambio | Impacto DDL | Impacto DTO | Impacto Service | Impacto Frontend |
|----------------|-------------|-------------|-----------------|------------------|
| Agregar ManyToOne | SI (FK) | SI | SI | SI |
| Agregar OneToMany | NO | SI | SI | SI |
| Agregar ManyToMany | SI (junction) | SI | SI | SI |
| Eliminar relacion | SI | SI | SI | SI |
| Cambiar cascade | NO | NO | Verificar | NO |

### 2.3 Cambios de Indice/Constraint

| Tipo de Cambio | Impacto DDL | Impacto DTO | Impacto Service | Impacto Frontend |
|----------------|-------------|-------------|-----------------|------------------|
| Agregar indice | SI | NO | NO | NO |
| Agregar unique | SI | NO | Manejar error | Manejar error |
| Agregar check | SI | NO | Manejar error | Manejar error |

---

## 3. AGREGAR CAMPO A ENTITY

### Flujo Completo

```
┌─────────────────────────────────────────────────────────────────────┐
│ PASO 1: DDL (Database-Agent)                                        │
├─────────────────────────────────────────────────────────────────────┤
│ ALTER TABLE auth.users ADD COLUMN phone VARCHAR(20);                │
│                                                                      │
│ Validar: ./recreate-database.sh && psql -c "\d auth.users"         │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ PASO 2: Entity (Backend-Agent)                                      │
├─────────────────────────────────────────────────────────────────────┤
│ @Column({ type: 'varchar', length: 20, nullable: true })           │
│ phone: string | null;                                               │
│                                                                      │
│ Validar: npm run build                                              │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ PASO 3: DTOs (Backend-Agent)                                        │
├─────────────────────────────────────────────────────────────────────┤
│ CreateUserDto:                                                      │
│   @IsOptional()                                                     │
│   @IsString()                                                       │
│   @MaxLength(20)                                                    │
│   phone?: string;                                                   │
│                                                                      │
│ UserResponseDto:                                                    │
│   @ApiProperty({ required: false })                                 │
│   phone: string | null;                                             │
│                                                                      │
│ Validar: npm run build && npm run lint                              │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ PASO 4: Frontend (Frontend-Agent)                                   │
├─────────────────────────────────────────────────────────────────────┤
│ user.types.ts:                                                      │
│   interface User {                                                  │
│     phone: string | null;                                           │
│   }                                                                 │
│                                                                      │
│ user.schema.ts:                                                     │
│   phone: z.string().max(20).optional()                              │
│                                                                      │
│ Validar: npm run build && npm run typecheck                         │
└─────────────────────────────────────────────────────────────────────┘
```

### Checklist Agregar Campo

```
[ ] 1. DDL tiene la columna con tipo correcto
[ ] 2. Entity @Column refleja DDL (tipo, length, nullable)
[ ] 3. CreateDto tiene validaciones apropiadas
[ ] 4. UpdateDto hereda de CreateDto (automatico con PartialType)
[ ] 5. ResponseDto tiene el campo con ApiProperty
[ ] 6. Frontend interface tiene el campo
[ ] 7. Frontend Zod schema tiene validacion equivalente
[ ] 8. Swagger documenta correctamente
[ ] 9. Build pasa en backend
[ ] 10. Build y typecheck pasan en frontend
```

---

## 4. ELIMINAR CAMPO DE ENTITY

### ADVERTENCIA

```
⚠️  ELIMINAR CAMPO ES OPERACION DESTRUCTIVA

ANTES DE ELIMINAR:
1. Verificar que no hay datos importantes
2. Buscar TODAS las referencias en codigo
3. Considerar deprecar primero (nullable + ignorar)
4. Planear migracion de datos si necesario
```

### Flujo de Eliminacion

```bash
# PASO 0: Buscar todas las referencias
grep -rn "fieldName" src/
grep -rn "fieldName" apps/
grep -rn "field_name" db/  # snake_case en DDL

# PASO 1: Eliminar uso en Frontend primero (evita errores de tipo)
# PASO 2: Eliminar uso en Service/Controller
# PASO 3: Eliminar de DTOs
# PASO 4: Eliminar de Entity
# PASO 5: Eliminar de DDL (ultimo porque es irreversible)
```

### Checklist Eliminar Campo

```
[ ] 1. Buscar referencias en backend: grep -rn "field" src/
[ ] 2. Buscar referencias en frontend: grep -rn "field" apps/
[ ] 3. Eliminar de componentes Frontend
[ ] 4. Eliminar de types/interfaces Frontend
[ ] 5. Eliminar de Zod schemas Frontend
[ ] 6. Eliminar de Service (si hay logica)
[ ] 7. Eliminar de ResponseDto
[ ] 8. Eliminar de CreateDto
[ ] 9. Eliminar de Entity
[ ] 10. Eliminar de DDL (con migracion)
[ ] 11. Build pasa en todos los proyectos
```

---

## 5. AGREGAR RELACION A ENTITY

### 5.1 ManyToOne (FK hacia otra tabla)

```typescript
// Entity: Order tiene un User
@ManyToOne(() => UserEntity, { nullable: false })
@JoinColumn({ name: 'user_id' })
user: UserEntity;

// Columna FK explicita (opcional pero recomendado)
@Column({ type: 'uuid' })
userId: string;
```

**Impacto:**

| Capa | Archivo | Cambio Requerido |
|------|---------|------------------|
| DDL | `XX-orders.sql` | `user_id UUID REFERENCES auth.users(id)` |
| Entity | `order.entity.ts` | `@ManyToOne` + `@JoinColumn` |
| CreateDto | `create-order.dto.ts` | `@IsUUID() userId: string;` |
| ResponseDto | `order-response.dto.ts` | `userId: string;` o `user: UserResponseDto;` |
| Service | `order.service.ts` | Decidir: cargar relacion o no |
| Frontend | `order.types.ts` | `userId: string;` o `user: User;` |

### 5.2 OneToMany (Coleccion inversa)

```typescript
// Entity: User tiene muchos Orders
@OneToMany(() => OrderEntity, order => order.user)
orders: OrderEntity[];
```

**Impacto:**

| Capa | Archivo | Cambio Requerido |
|------|---------|------------------|
| DDL | N/A | Sin cambio (FK esta en orders) |
| Entity | `user.entity.ts` | `@OneToMany` |
| ResponseDto | `user-response.dto.ts` | Decidir: incluir o no |
| Service | `user.service.ts` | Decidir: cargar relacion o no |
| Frontend | `user.types.ts` | `orders?: Order[];` |

### 5.3 ManyToMany (Tabla junction)

```typescript
// Entity: User tiene muchos Roles
@ManyToMany(() => RoleEntity)
@JoinTable({
    name: 'user_roles',
    joinColumn: { name: 'user_id' },
    inverseJoinColumn: { name: 'role_id' },
})
roles: RoleEntity[];
```

**Impacto:**

| Capa | Archivo | Cambio Requerido |
|------|---------|------------------|
| DDL | `XX-user-roles.sql` | Crear tabla junction |
| Entity | `user.entity.ts` | `@ManyToMany` + `@JoinTable` |
| ResponseDto | `user-response.dto.ts` | `roles: RoleResponseDto[];` |
| Service | `user.service.ts` | Logica para asignar/remover roles |
| Controller | `user.controller.ts` | Endpoints para manejar roles |
| Frontend | `user.types.ts` | `roles: Role[];` |
| Frontend | `useUserRoles.ts` | Hook para manejar roles |

### Checklist Agregar Relacion

```
[ ] 1. DDL tiene FK o tabla junction
[ ] 2. Entity tiene decorador de relacion correcto
[ ] 3. Entity relacionada tiene relacion inversa (si necesario)
[ ] 4. CreateDto acepta ID de relacion
[ ] 5. ResponseDto decide: incluir objeto o solo ID
[ ] 6. Service decide: eager loading o lazy
[ ] 7. Frontend types reflejan estructura
[ ] 8. Frontend tiene logica para manejar relacion
```

---

## 6. CAMBIAR TIPO DE CAMPO

### Mapeo de Cambios Comunes

| Cambio | DDL | Entity | DTO | Frontend |
|--------|-----|--------|-----|----------|
| `INT` → `BIGINT` | ALTER TYPE | `number` (sin cambio) | Sin cambio | Sin cambio |
| `VARCHAR` → `TEXT` | ALTER TYPE | Sin cambio | Ajustar MaxLength | Ajustar max |
| `INTEGER` → `DECIMAL` | ALTER TYPE | `number` → `string` | Ajustar validador | Ajustar tipo |
| `BOOLEAN` → `ENUM` | ALTER TYPE | `boolean` → `enum` | Cambiar validador | Cambiar tipo |
| `VARCHAR` → `UUID` | ALTER TYPE + datos | `string` (sin cambio) | Agregar @IsUUID | Agregar validacion |

### Ejemplo: INTEGER a DECIMAL

```sql
-- DDL
ALTER TABLE products ALTER COLUMN price TYPE DECIMAL(10,2);
```

```typescript
// Entity ANTES
@Column({ type: 'integer' })
price: number;

// Entity DESPUES
@Column({ type: 'decimal', precision: 10, scale: 2 })
price: string;  // String para precision
```

```typescript
// CreateDto ANTES
@IsNumber()
price: number;

// CreateDto DESPUES
@IsNumberString()
@Matches(/^\d+(\.\d{1,2})?$/)
price: string;
```

```typescript
// Frontend ANTES
interface Product {
    price: number;
}

// Frontend DESPUES
interface Product {
    price: string;
}

// Uso en componente
const displayPrice = parseFloat(product.price).toFixed(2);
```

---

## 7. PATRON DE MIGRACION SEGURA

### Para cambios que pueden romper

```
FASE 1: Agregar nuevo (sin eliminar viejo)
═══════════════════════════════════════════════════════════════
1. Agregar nuevo campo/columna junto al existente
2. Actualizar codigo para escribir en ambos
3. Deploy backend

FASE 2: Migrar datos
═══════════════════════════════════════════════════════════════
1. Script para copiar datos de viejo a nuevo
2. Verificar integridad

FASE 3: Cambiar lecturas
═══════════════════════════════════════════════════════════════
1. Actualizar codigo para leer de nuevo
2. Deploy backend + frontend

FASE 4: Eliminar viejo
═══════════════════════════════════════════════════════════════
1. Eliminar campo viejo de codigo
2. Eliminar columna de DDL
3. Deploy final
```

---

## 8. DECORADORES ENTITY Y SU IMPACTO

### @Column Options

| Option | Impacto si cambia | Requiere DDL |
|--------|-------------------|--------------|
| `type` | Tipo TS, validacion DTO | SI |
| `length` | Validacion DTO | SI |
| `nullable` | Tipo TS (null), validacion | SI |
| `default` | Posible logica Service | SI |
| `unique` | Manejo error Service | SI |
| `name` | Ninguno (mapeo interno) | SI |
| `precision/scale` | Tipo TS, formateo FE | SI |

### @Index

| Cambio | Impacto |
|--------|---------|
| Agregar | Solo performance, DDL |
| Eliminar | Solo performance, DDL |
| Cambiar columnas | Solo performance, DDL |

### Relation Options

| Option | Impacto si cambia |
|--------|-------------------|
| `eager: true` | Queries cargan automatico |
| `cascade: true` | Operaciones se propagan |
| `onDelete` | Comportamiento al eliminar padre |
| `nullable` | Validacion, tipo TS |

---

## 9. COMANDOS DE VERIFICACION

```bash
# Ver diferencias entre DDL y Entity
# (manual: comparar columnas)
psql -d mydb -c "\d schema.table"
cat src/modules/x/entities/x.entity.ts

# Verificar que Entity compila
npm run build

# Verificar que no hay referencias rotas
npm run lint

# Verificar sincronizacion con frontend
npm run typecheck --prefix apps/web

# Buscar uso de campo especifico
grep -rn "fieldName" src/ apps/
```

---

## 10. MATRIZ DE DECISION

```
¿Que tipo de cambio en Entity?

┌─────────────────────┐
│ Agregar campo       │──▶ DDL primero → Entity → DTO → Frontend
└─────────────────────┘

┌─────────────────────┐
│ Eliminar campo      │──▶ Frontend primero → Service → DTO → Entity → DDL
└─────────────────────┘

┌─────────────────────┐
│ Cambiar tipo        │──▶ DDL primero → Entity → DTO → Frontend
└─────────────────────┘

┌─────────────────────┐
│ Agregar relacion    │──▶ DDL (FK) → Entity → DTO → Service → Frontend
└─────────────────────┘

┌─────────────────────┐
│ Renombrar campo     │──▶ Migracion segura (agregar nuevo → migrar → eliminar viejo)
└─────────────────────┘
```

---

**Version:** 1.0.0 | **Sistema:** SIMCO | **Tipo:** Guia de Impacto
