- Extraccion de helpers en backend: audit_helpers.py, helpers.py - Modularizacion de schemas en archivos individuales por dominio - Reduccion de audit.py en 953 lineas (74% del archivo) - Reduccion de tickets.py en 655 lineas (60% del archivo) - Expansion de auth.py con recuperacion de contrasenia y tokens - Nuevos modulos: core/email.py, core/cache.py - Reorganizacion de scripts a backend/scripts/ - Frontend: refactorizacion de audit page con array-driven components - Frontend: correccion de 11 errores ortograficos en tickets page - Frontend: proxy Docker corregido en vite.config.js - Frontend: nuevas rutas forgot-password, reset-password, organization, profile - Nuevas utilidades TS: colorUtils.ts, dateFormats.ts - 5 nuevos archivos de tests unitarios en backend/tests/unit/ - Eliminacion de 3 scripts temporales de prueba - Documentacion tecnica: CAMBIOS_v1.10.0.md, OPTIMIZACIONES_RENDIMIENTO.md
727 lines
25 KiB
Markdown
727 lines
25 KiB
Markdown
# ServiceManagerWeb — Versión 1.10.0
|
||
## Reporte Técnico de Cambios y Mejoras
|
||
|
||
---
|
||
|
||
**Proyecto:** ServiceManagerWeb – Mesa de Ayuda B2B Multi-tenant
|
||
**Versión:** 1.10.0
|
||
**Versión base:** 1.8.0 (commit `e644039`) / 1.9.0 (commit `16d795e`)
|
||
**Fecha:** 19 de Febrero de 2026
|
||
**Estado:** Sistema Funcional — Producción MVP
|
||
**Empresa:** Aduanasoft
|
||
**Autor:** Equipo de Desarrollo
|
||
|
||
---
|
||
|
||
## Resumen Ejecutivo
|
||
|
||
La versión 1.10.0 representa una fase de refactorización técnica profunda, optimización de rendimiento, y mejoras significativas en la interfaz de usuario. Los cambios abarcan el ciclo completo del sistema: backend (Python/FastAPI), frontend interno (SvelteKit), frontend cliente (SvelteKit) y la capa de infraestructura (Docker).
|
||
|
||
### Métricas Globales de esta Versión
|
||
|
||
| Indicador | Valor |
|
||
|---|---|
|
||
| Archivos modificados | 31 archivos |
|
||
| Líneas añadidas (total) | ~3,250 líneas |
|
||
| Líneas eliminadas (total) | ~3,440 líneas |
|
||
| Reducción neta de código | ~190 líneas (refactorización limpia) |
|
||
| Archivos nuevos creados | 14 archivos |
|
||
| Archivos eliminados | 3 scripts de prueba temporales |
|
||
| Scripts reorganizados | 3 (movidos a `backend/scripts/`) |
|
||
|
||
---
|
||
|
||
## 1. Backend — Python / FastAPI
|
||
|
||
### 1.1 `backend/app/api/v1/endpoints/audit.py`
|
||
**Cambios:** +166 líneas añadidas / −1,119 líneas eliminadas
|
||
**Balance neto:** −953 líneas (reducción del 74% del archivo)
|
||
|
||
#### Problema detectado
|
||
El archivo `audit.py` tenía 1,285 líneas en la versión 1.8.0. Toda la lógica de detección de amenazas, análisis de seguridad y transformación de datos estaba inline dentro de las funciones de cada endpoint, generando duplicación masiva y dificultando el mantenimiento.
|
||
|
||
#### Cambios realizados
|
||
|
||
**a) Extracción de lógica a módulo auxiliar**
|
||
Se creó el archivo `backend/app/api/v1/audit_helpers.py` (nuevo, ver sección 1.8) con las siguientes funciones extraídas del archivo original:
|
||
|
||
```python
|
||
# ANTES — en audit.py líneas 420-580 (inline)
|
||
# Toda la lógica de detección de amenazas vivía dentro de la función
|
||
# get_security_analysis() sin separación alguna
|
||
|
||
# DESPUÉS — importado desde audit_helpers.py
|
||
from app.api.v1.audit_helpers import (
|
||
audit_log_to_dict,
|
||
apply_tenant_filter,
|
||
get_count_stat,
|
||
get_top_items,
|
||
detect_mass_deletions,
|
||
detect_brute_force,
|
||
detect_privilege_escalation
|
||
)
|
||
```
|
||
|
||
**b) Docstrings compactados**
|
||
Los docstrings multilínea extensos se compactaron a una sola línea donde el nombre era autoexplicativo:
|
||
|
||
```python
|
||
# ANTES (líneas 1-7 del archivo original)
|
||
"""
|
||
Audit Endpoints - ServiceManagerWeb
|
||
|
||
Endpoints para consulta de logs de auditoría.
|
||
Solo accesible por roles: ADMIN, SUPPORT_MANAGER, AUDITOR
|
||
"""
|
||
|
||
# DESPUÉS (línea 1)
|
||
"""Audit Endpoints - ServiceManagerWeb"""
|
||
```
|
||
|
||
**c) Firma de función require_auditor_role refactorizada**
|
||
```python
|
||
# ANTES (líneas 32-47) — 16 líneas
|
||
def require_auditor_role(current_user: User = Depends(get_current_user)) -> User:
|
||
"""
|
||
Dependency que verifica que el usuario tenga rol de auditor.
|
||
Solo ADMIN, SUPPORT_MANAGER y AUDITOR pueden ver logs de auditoría.
|
||
"""
|
||
allowed_roles = [UserRole.ADMIN, UserRole.SUPPORT_MANAGER, UserRole.AUDITOR]
|
||
if current_user.role not in allowed_roles:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_403_FORBIDDEN,
|
||
detail="Solo usuarios con rol ADMIN, SUPPORT_MANAGER o AUDITOR..."
|
||
)
|
||
return current_user
|
||
|
||
# DESPUÉS (líneas 20-24) — 5 líneas
|
||
def require_auditor_role(current_user: User = Depends(get_current_user)) -> User:
|
||
"""Verifica que el usuario tenga rol de auditor"""
|
||
if current_user.role not in [UserRole.ADMIN, UserRole.SUPPORT_MANAGER, UserRole.AUDITOR]:
|
||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
|
||
detail="Solo usuarios con rol ADMIN, SUPPORT_MANAGER o AUDITOR pueden acceder")
|
||
return current_user
|
||
```
|
||
|
||
**d) Firma del endpoint `get_audit_logs` compactada**
|
||
```python
|
||
# ANTES (líneas 49-72) — 24 líneas de parámetros separados
|
||
|
||
# DESPUÉS — parámetros agrupados en 6 líneas
|
||
async def get_audit_logs(
|
||
page: int = Query(default=1, ge=1),
|
||
per_page: int = Query(default=50, ge=1, le=100),
|
||
user_id: Optional[uuid.UUID] = Query(None),
|
||
action: Optional[str] = Query(None),
|
||
...
|
||
```
|
||
|
||
**e) Corrección del schema `SecurityAnalysisResponse`**
|
||
Se añadieron todos los campos requeridos que causaban error 500 al serializar la respuesta. Los campos faltantes eran:
|
||
- `analysis_period_hours`
|
||
- `total_threats_detected`
|
||
- `suspicious_ips_count`
|
||
- `critical_actions_count`
|
||
|
||
---
|
||
|
||
### 1.2 `backend/app/api/v1/endpoints/auth.py`
|
||
**Cambios:** +369 líneas añadidas / −40 líneas eliminadas
|
||
**Balance neto:** +329 líneas
|
||
|
||
#### Cambios realizados
|
||
Se amplió la cobertura de autenticación con:
|
||
- Manejo robusto de tokens de refresco
|
||
- Validación mejorada de credenciales con mensajes de error específicos
|
||
- Soporte para recuperación de contraseña por email
|
||
- Integración con el servicio de email (`app/core/email.py`)
|
||
- Logging estructurado con `structlog` en todos los endpoints críticos
|
||
|
||
---
|
||
|
||
### 1.3 `backend/app/api/v1/endpoints/tickets.py`
|
||
**Cambios:** +217 líneas añadidas / −872 líneas eliminadas
|
||
**Balance neto:** −655 líneas (reducción del 60%)
|
||
|
||
#### Problema detectado
|
||
Igual que `audit.py`, el archivo de tickets tenía lógica de negocio repetida y funciones helper inline.
|
||
|
||
#### Cambios realizados
|
||
|
||
**a) Extracción a `backend/app/api/v1/helpers.py`**
|
||
Se creó un módulo auxiliar general (nuevo, ver sección 1.9) con funciones reutilizables como:
|
||
- `build_ticket_query()` — construye queries SQLAlchemy con filtros dinámicos
|
||
- `paginate_query()` — paginación genérica reutilizable
|
||
- `format_ticket_response()` — serialización consistente
|
||
|
||
**b) Corrección del error de `sla_breached`**
|
||
```python
|
||
# ANTES — causaba AttributeError / 500 en producción
|
||
response.sla_breached = ticket.sla_breached # ← propiedad no existía
|
||
|
||
# DESPUÉS — removido, calculado dinámicamente
|
||
# sla_breached se calcula desde sla_deadline vs datetime.utcnow()
|
||
```
|
||
|
||
---
|
||
|
||
### 1.4 `backend/app/api/schemas/__init__.py`
|
||
**Cambios:** +54 líneas añadidas / −4 líneas eliminadas
|
||
|
||
Se reorganizaron los schemas en módulos separados:
|
||
|
||
```
|
||
# ANTES — un archivo monolítico schemas/__init__.py con todo
|
||
|
||
# DESPUÉS — módulos independientes por dominio:
|
||
backend/app/api/schemas/
|
||
├── __init__.py (re-exports, 58 líneas totales)
|
||
├── auth.py (NUEVO — schemas de autenticación)
|
||
├── category.py (NUEVO — schemas de categorías)
|
||
├── system.py (NUEVO — schemas de sistemas)
|
||
├── tenant.py (NUEVO — schemas de tenants)
|
||
├── ticket.py (NUEVO — schemas de tickets)
|
||
└── user.py (NUEVO — schemas de usuarios)
|
||
```
|
||
|
||
---
|
||
|
||
### 1.5 `backend/app/middleware/tenant.py`
|
||
**Cambios:** +103 líneas añadidas / −37 líneas eliminadas
|
||
**Balance neto:** +66 líneas
|
||
|
||
#### Cambios realizados
|
||
- Mejora del middleware de contexto multi-tenant con mejor manejo de headers `X-Tenant-ID`
|
||
- Logging detallado de tenant context para debugging
|
||
- Validación más robusta del tenant activo
|
||
- Soporte para tenant bypass en endpoints de health/docs
|
||
|
||
---
|
||
|
||
### 1.6 `backend/app/main.py`
|
||
**Cambios:** +7 líneas añadidas / −0 líneas eliminadas
|
||
|
||
```python
|
||
# AÑADIDO — registro de nuevos routers
|
||
from app.api.v1.endpoints import profile # router de perfil de usuario
|
||
app.include_router(profile.router, prefix="/api/v1/profile", tags=["profile"])
|
||
```
|
||
|
||
---
|
||
|
||
### 1.7 `backend/app/core/database.py`
|
||
**Cambios:** +3 líneas / −2 líneas
|
||
|
||
```python
|
||
# ANTES
|
||
engine = create_async_engine(settings.DATABASE_URL, echo=False)
|
||
|
||
# DESPUÉS — pool tuning para mayor concurrencia
|
||
engine = create_async_engine(
|
||
settings.DATABASE_URL,
|
||
pool_pre_ping=True,
|
||
pool_recycle=300
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
### 1.8 `backend/app/api/v1/audit_helpers.py` (ARCHIVO NUEVO)
|
||
**Líneas:** ~120 líneas
|
||
|
||
Módulo auxiliar extraído de `audit.py`. Contiene:
|
||
|
||
| Función | Descripción |
|
||
|---|---|
|
||
| `audit_log_to_dict(log)` | Serializa un AuditLog a dict |
|
||
| `apply_tenant_filter(query, user, tenant, all_tenants)` | Aplica filtro multi-tenant |
|
||
| `get_count_stat(db, model, filters)` | Cuenta registros con filtros |
|
||
| `get_top_items(db, field, limit)` | Top N elementos de un campo |
|
||
| `detect_mass_deletions(logs)` | Detecta patrones de eliminación masiva |
|
||
| `detect_brute_force(logs)` | Detecta intentos de brute force |
|
||
| `detect_privilege_escalation(logs)` | Detecta escalada de privilegios |
|
||
|
||
---
|
||
|
||
### 1.9 `backend/app/api/v1/helpers.py` (ARCHIVO NUEVO)
|
||
**Líneas:** ~80 líneas
|
||
|
||
Helper general para tickets y recursos compartidos.
|
||
|
||
---
|
||
|
||
### 1.10 `backend/app/core/email.py` (ARCHIVO NUEVO)
|
||
Módulo de envío de email para notificaciones y recuperación de contraseña, integrado con Celery workers.
|
||
|
||
---
|
||
|
||
### 1.11 `backend/app/core/cache.py` (ARCHIVO NUEVO)
|
||
Módulo de caché con Redis:
|
||
- `cache_get(key)` / `cache_set(key, value, ttl)`
|
||
- Decorador `@cached(ttl=300)` para funciones async
|
||
- Invalidación por patrón de claves
|
||
|
||
---
|
||
|
||
### 1.12 `backend/migrations/versions/a1b2c3d4e5f6_add_audit_logs_table.py`
|
||
**Cambios:** +57 líneas / −1 línea
|
||
|
||
Migration completada: se añadió la tabla `security_incidents` con campos:
|
||
- `id UUID PRIMARY KEY`
|
||
- `title VARCHAR(255)`
|
||
- `description TEXT`
|
||
- `severity ENUM(low, medium, high, critical)`
|
||
- `status ENUM(active, investigating, resolved)`
|
||
- `tenant_id UUID FK`
|
||
- `created_at TIMESTAMP`
|
||
- `updated_at TIMESTAMP`
|
||
|
||
---
|
||
|
||
### 1.13 `backend/tests/conftest.py`
|
||
**Cambios:** +151 líneas / −13 líneas
|
||
|
||
Se amplió el fixture base para pruebas de integración:
|
||
- Fixtures para multi-tenant testing
|
||
- Fixtures para usuario con rol AUDITOR
|
||
- Data factories para tickets, incidentes y audit logs
|
||
|
||
---
|
||
|
||
### 1.14 Reorganización de Scripts
|
||
```
|
||
# ANTES — en raíz de backend/
|
||
backend/check_tenants.py
|
||
backend/create_test_user.py
|
||
backend/set_test_password.py
|
||
|
||
# DESPUÉS — carpeta dedicada
|
||
backend/scripts/check_tenants.py
|
||
backend/scripts/create_test_user.py
|
||
backend/scripts/set_test_password.py
|
||
```
|
||
|
||
---
|
||
|
||
### 1.15 Nuevos Tests Unitarios (archivos nuevos)
|
||
```
|
||
backend/tests/unit/
|
||
├── test_audit_service.py (cobertura del AuditService)
|
||
├── test_config.py (validación de settings)
|
||
├── test_middleware.py (pruebas del middleware tenant)
|
||
├── test_schemas.py (validación de schemas Pydantic)
|
||
└── test_security.py (pruebas de JWT y hashing)
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Frontend Interno — SvelteKit / TypeScript
|
||
|
||
### 2.1 `frontend-internal/src/routes/audit/+page.svelte`
|
||
**Cambios:** +1,253 líneas añadidas / −554 líneas eliminadas
|
||
**Líneas totales finales:** 2,050 líneas
|
||
|
||
Este es el archivo con más cambios de toda la versión. Se realizó una refactorización completa de la página de auditoría.
|
||
|
||
#### 2.1.1 Tipado TypeScript — Corrección de Warnings
|
||
|
||
```typescript
|
||
// ANTES (líneas 9-17) — tipos implícitos, generaba warnings
|
||
let logs = [];
|
||
let stats = null;
|
||
let users = [];
|
||
let incidents = [];
|
||
let securityAnalysis = null;
|
||
let selectedLog = null;
|
||
let selectedIncident = null;
|
||
|
||
// DESPUÉS — tipos explícitos
|
||
let logs: any[] = [];
|
||
let stats: any = null;
|
||
let users: any[] = [];
|
||
let incidents: any[] = [];
|
||
let securityAnalysis: any = null;
|
||
let selectedLog: any = null;
|
||
let selectedIncident: any = null;
|
||
```
|
||
|
||
#### 2.1.2 Responses de API tipadas
|
||
|
||
```typescript
|
||
// ANTES — response sin tipo, causaba errores
|
||
const response = await api.get('/audit/security/incidents', params);
|
||
incidents = response.incidents || []; // TS error: 'response' is of type 'unknown'
|
||
|
||
// DESPUÉS — response con tipo explícito
|
||
const response: any = await api.get('/audit/security/incidents', params);
|
||
incidents = response.incidents || [];
|
||
```
|
||
|
||
#### 2.1.3 Catch blocks tipados (5 bloques corregidos)
|
||
|
||
```typescript
|
||
// ANTES — 5 bloques con e sin tipo
|
||
} catch (e) {
|
||
console.error('Error:', e);
|
||
|
||
// DESPUÉS — todos tipados
|
||
} catch (e: any) {
|
||
console.error('Error:', e);
|
||
```
|
||
|
||
#### 2.1.4 Botones de período refactorizados con array tipado
|
||
|
||
```typescript
|
||
// ANTES — 5 bloques <button> repetidos, ~40 líneas
|
||
<button on:click={() => changePeriod('today')} class="...">Hoy</button>
|
||
<button on:click={() => changePeriod('yesterday')} class="...">Ayer</button>
|
||
<button on:click={() => changePeriod('last7days')} class="...">Últimos 7 días</button>
|
||
<button on:click={() => changePeriod('last30days')} class="...">Últimos 30 días</button>
|
||
<button on:click={() => changePeriod('custom')} class="...">Personalizado</button>
|
||
|
||
// DESPUÉS — array con tipo estricto + loop, ~15 líneas
|
||
const periodButtons: Array<{
|
||
id: 'today' | 'yesterday' | 'last7days' | 'last30days' | 'custom',
|
||
label: string,
|
||
icon?: boolean
|
||
}> = [
|
||
{ id: 'today', label: 'Hoy' },
|
||
{ id: 'yesterday', label: 'Ayer' },
|
||
{ id: 'last7days', label: 'Últimos 7 días' },
|
||
{ id: 'last30days', label: 'Últimos 30 días' },
|
||
{ id: 'custom', label: 'Personalizado', icon: true }
|
||
];
|
||
|
||
{#each periodButtons as btn}
|
||
<button on:click={() => changePeriod(btn.id)} class="...">
|
||
{btn.label}
|
||
</button>
|
||
{/each}
|
||
```
|
||
|
||
#### 2.1.5 Tarjetas estadísticas refactorizadas con array reactivo
|
||
|
||
```typescript
|
||
// ANTES — 4 bloques <div> idénticos con ~25 líneas cada uno (~100 líneas totales)
|
||
// Total del Acciones — bloque completo
|
||
<div class="bg-white rounded-lg ...">
|
||
<div class="..."><svg .../><span>Total de Registros</span></div>
|
||
<div class="text-3xl ...">{stats.total_actions.toLocaleString()}</div>
|
||
...
|
||
</div>
|
||
// Acciones Hoy — bloque completo (repetido)
|
||
// Esta Semana — bloque completo (repetido)
|
||
// Incidentes Críticos — bloque completo (repetido)
|
||
|
||
// DESPUÉS — array reactivo + loop, ~40 líneas totales
|
||
$: statsCards = [
|
||
{ label: 'Total de Registros', value: stats?.total_actions, icon: 'clipboard', color: 'gray', desc: '...' },
|
||
{ label: 'Actividad Hoy', value: stats?.actions_today, icon: 'zap', color: 'blue', desc: '...' },
|
||
{ label: 'Esta Semana', value: stats?.actions_this_week, icon: 'calendar', color: 'indigo', desc: '...' },
|
||
{ label: 'Incidentes Críticos', value: stats?.critical_actions_today || 0, icon: 'alert', color: 'red', desc: '...', action: true }
|
||
];
|
||
|
||
{#each statsCards as card}
|
||
<div class="bg-white rounded-lg shadow-sm border border-{card.color}-200 p-5 ...">
|
||
...
|
||
</div>
|
||
{/each}
|
||
```
|
||
|
||
#### 2.1.6 Sección de Análisis de Seguridad reemplazada por enlace
|
||
|
||
```svelte
|
||
<!-- ANTES — sección extensa de ~150 líneas con amenazas, acciones recomendadas
|
||
y métricas desplegadas inline en la página principal -->
|
||
|
||
<!-- DESPUÉS — tarjeta compacta (~50 líneas) con enlace a página dedicada -->
|
||
<a href="/audit/security" class="block bg-gradient-to-br from-indigo-500 to-purple-600 rounded-lg ...">
|
||
<!-- Resumen de 3 métricas clave -->
|
||
<!-- Indicador visual del nivel de riesgo -->
|
||
<!-- Enlace "Ir al análisis detallado" -->
|
||
</a>
|
||
```
|
||
|
||
Esta decisión separa la responsabilidad: la página `/audit` muestra el **resumen de actividad**, mientras que `/audit/security` muestra el **análisis detallado de amenazas**.
|
||
|
||
#### 2.1.7 Mejoras de espaciado y layout
|
||
|
||
- **Contenedor principal:** `px-4 sm:px-6 lg:px-8 py-8` — márgenes responsivos
|
||
- **Encabezado de página:** añadido con `h1` + descripción
|
||
- **Separación entre secciones:** `mb-8` uniforme (antes `mb-6` variable)
|
||
- **Etiquetas de sección:** añadidos `<h2>` para "Resumen de Actividad", "Incidentes de Seguridad", "Registros de Auditoría"
|
||
- **Tarjetas con headers descriptivos:** añadidos `<h3>` en toggles y controles
|
||
|
||
---
|
||
|
||
### 2.2 `frontend-internal/src/routes/tickets/+page.svelte`
|
||
**Cambios:** +731 líneas añadidas / −338 líneas eliminadas
|
||
|
||
#### Cambios realizados
|
||
- Corrección de ortografía en 11 etiquetas de texto (ej: "priorida" → "prioridad")
|
||
- Mejora del filtro de estado y prioridad con selects correctamente bound a variables reactivas
|
||
- Vista de tabla compacta con rows más ajustados (`py-2` en lugar de `py-4`)
|
||
- Indicadores de color para prioridad (urgente=rojo, alto=naranja, medio=amarillo, bajo=azul)
|
||
- Modal de detalle de ticket con información de SLA sin acceder a propiedades no existentes
|
||
|
||
---
|
||
|
||
### 2.3 `frontend-internal/src/lib/components/Sidebar.svelte`
|
||
**Cambios:** +17 líneas / −6 líneas
|
||
|
||
```svelte
|
||
<!-- ANTES — enlace a Reportes ausente o comentado -->
|
||
|
||
<!-- DESPUÉS — enlace restaurado y activo -->
|
||
<a href="/reports" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md ..."
|
||
class:bg-indigo-700={$page.url.pathname.startsWith('/reports')}>
|
||
Reportes
|
||
</a>
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 `frontend-internal/vite.config.js`
|
||
**Cambios:** +20 líneas / −16 líneas
|
||
|
||
```javascript
|
||
// ANTES — proxy incorrecto durante desarrollo
|
||
proxy: {
|
||
'/api': 'http://localhost:8000' // ← fallaba dentro de Docker
|
||
}
|
||
|
||
// DESPUÉS — proxy correcto para red Docker
|
||
proxy: {
|
||
'/api': {
|
||
target: 'http://backend:8000',
|
||
changeOrigin: true,
|
||
rewrite: (path) => path.replace(/^\/api/, '')
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2.5 Nuevos Utilitarios Frontend (archivos nuevos)
|
||
|
||
#### `frontend-internal/src/lib/utils/colorUtils.ts` (NUEVO, 74 líneas)
|
||
|
||
```typescript
|
||
// Centraliza todos los mapas de colores del sistema
|
||
type ColorType = 'severity' | 'status' | 'action' | 'priority';
|
||
|
||
export function getColorClass(value: string, type: ColorType = 'status'): string
|
||
export function getStatusIcon(status: string): string
|
||
```
|
||
|
||
#### `frontend-internal/src/lib/utils/dateFormats.ts` (NUEVO, 78 líneas)
|
||
|
||
```typescript
|
||
// Centraliza el formateo de fechas
|
||
export function formatDate(dateString: string, format: DateFormat = 'full'): string
|
||
export function getRelativeTime(dateString: string): string
|
||
export function getDateRangeForPeriod(period: string, from?: string, to?: string): DateRange
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Frontend Cliente — SvelteKit / TypeScript
|
||
|
||
### 3.1 `frontend-client/src/routes/profile/+page.svelte`
|
||
**Cambios:** +194 líneas / −56 líneas
|
||
|
||
Nueva funcionalidad de perfil de usuario con:
|
||
- Visualización de datos personales del cliente
|
||
- Formulario de edición de nombre y contacto
|
||
- Cambio de contraseña con validación de fortaleza
|
||
- Indicador visual del tipo de cuenta
|
||
|
||
---
|
||
|
||
### 3.2 `frontend-client/vite.config.js`
|
||
**Cambios:** +4 líneas / −0 líneas
|
||
|
||
```javascript
|
||
// AÑADIDO — proxy para comunicación con backend
|
||
server: {
|
||
proxy: {
|
||
'/api': { target: 'http://backend:8000', ... }
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 Nuevas Rutas Frontend Cliente (archivos nuevos)
|
||
|
||
```
|
||
frontend-client/src/routes/
|
||
├── forgot-password/ (NUEVO — flujo de recuperación de contraseña)
|
||
├── reset-password/ (NUEVO — formulario de nueva contraseña con token)
|
||
└── organization/ (NUEVO — vista de datos de la organización del cliente)
|
||
```
|
||
|
||
---
|
||
|
||
### 3.4 `frontend-client/src/lib/components/Header.svelte`
|
||
**Cambios:** +8 líneas / −2 líneas
|
||
|
||
- Añadido enlace a perfil de usuario en el dropdown del header
|
||
- Enlace a "Mi Organización" visible para `CLIENT_ADMIN`
|
||
|
||
---
|
||
|
||
## 4. Infraestructura y DevOps
|
||
|
||
### 4.1 `docker/Dockerfile.backend`
|
||
**Cambios:** +3 líneas / −1 línea
|
||
|
||
```dockerfile
|
||
# AÑADIDO — dependencias del sistema para compilar bcrypt
|
||
RUN apt-get install -y build-essential libffi-dev
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 `frontend-internal/package.json`
|
||
**Cambios:** +1 línea / −1 línea
|
||
|
||
```json
|
||
// ACTUALIZADO — versión de @sveltejs/kit para fix de routing
|
||
"@sveltejs/kit": "^1.27.0" // antes ^1.6.0
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Archivos Eliminados
|
||
|
||
| Archivo | Razón |
|
||
|---|---|
|
||
| `test_frontend_integration.ps1` (174 líneas) | Script de prueba temporal — funcionalidad absorbida por suite de tests |
|
||
| `test_manual.ps1` (142 líneas) | Script de prueba manual obsoleto |
|
||
| `test_tenant_update.ps1` (101 líneas) | Script específico para prueba puntual, ya no necesario |
|
||
|
||
**Total eliminado:** 417 líneas de código temporal/obsoleto
|
||
|
||
---
|
||
|
||
## 6. Nuevos Archivos Creados
|
||
|
||
| Archivo | Líneas | Propósito |
|
||
|---|---|---|
|
||
| `backend/app/api/v1/audit_helpers.py` | ~120 | Helpers de auditoría extraídos de audit.py |
|
||
| `backend/app/api/v1/helpers.py` | ~80 | Helpers generales de tickets y queries |
|
||
| `backend/app/api/schemas/auth.py` | ~60 | Schemas Pydantic para autenticación |
|
||
| `backend/app/api/schemas/category.py` | ~30 | Schemas de categorías |
|
||
| `backend/app/api/schemas/system.py` | ~30 | Schemas de sistemas |
|
||
| `backend/app/api/schemas/tenant.py` | ~40 | Schemas de tenants |
|
||
| `backend/app/api/schemas/ticket.py` | ~80 | Schemas de tickets |
|
||
| `backend/app/api/schemas/user.py` | ~50 | Schemas de usuarios |
|
||
| `backend/app/core/email.py` | ~90 | Servicio de envío de email |
|
||
| `backend/app/core/cache.py` | ~70 | Módulo de caché Redis |
|
||
| `backend/tests/unit/test_audit_service.py` | ~100 | Tests del servicio de auditoría |
|
||
| `backend/tests/unit/test_config.py` | ~50 | Tests de configuración |
|
||
| `backend/tests/unit/test_middleware.py` | ~80 | Tests del middleware tenant |
|
||
| `backend/tests/unit/test_schemas.py` | ~70 | Tests de validación de schemas |
|
||
| `backend/tests/unit/test_security.py` | ~60 | Tests de seguridad JWT |
|
||
| `frontend-internal/src/lib/utils/colorUtils.ts` | 74 | Centralización de colores |
|
||
| `frontend-internal/src/lib/utils/dateFormats.ts` | 78 | Centralización de formatos de fecha |
|
||
| `frontend-client/src/routes/forgot-password/` | ~80 | Flujo de recuperación de contraseña |
|
||
| `frontend-client/src/routes/reset-password/` | ~90 | Formulario reset con token |
|
||
| `frontend-client/src/routes/organization/` | ~120 | Vista de organización del cliente |
|
||
| `frontend-internal/src/routes/profile/` | ~150 | Perfil del usuario interno |
|
||
| `OPTIMIZACIONES_RENDIMIENTO.md` | 344 | Guía técnica de optimizaciones futuras |
|
||
|
||
---
|
||
|
||
## 7. Correcciones de Bugs
|
||
|
||
### Bug #1 — Error 500 en `/audit/security/analysis`
|
||
**Causa:** El schema `SecurityAnalysisResponse` de Pydantic no incluía los campos `analysis_period_hours`, `total_threats_detected`, `suspicious_ips_count`, `critical_actions_count`. Al intentar serializar la respuesta, Pydantic lanzaba `ValidationError`.
|
||
**Archivo:** `backend/app/api/v1/endpoints/audit.py`
|
||
**Fix:** Se añadieron los campos faltantes al schema de respuesta en `backend/app/api/schemas/__init__.py`.
|
||
|
||
### Bug #2 — Error 500 en detalle de ticket (`/tickets/{id}`)
|
||
**Causa:** El endpoint accedía a `ticket.sla_breached` que no es una columna de la tabla, sino un cálculo derivado.
|
||
**Archivo:** `backend/app/api/v1/endpoints/tickets.py`
|
||
**Fix:** Se eliminó la referencia a `ticket.sla_breached` y se calcula dinámicamente: `sla_breached = ticket.sla_deadline < datetime.utcnow() if ticket.sla_deadline else False`
|
||
|
||
### Bug #3 — Proxy 404 en desarrollo con Docker
|
||
**Causa:** `vite.config.js` apuntaba a `localhost:8000` en lugar del hostname Docker `backend:8000`.
|
||
**Archivos:** `frontend-internal/vite.config.js`, `frontend-client/vite.config.js`
|
||
**Fix:** Se actualizó el target del proxy a `http://backend:8000` con `changeOrigin: true`.
|
||
|
||
### Bug #4 — Filtros de tickets no aplicaban
|
||
**Causa:** Los parámetros `status` y `priority` del frontend construían query strings con nombres incorrectos (`status_filter` en vez de `status`).
|
||
**Archivo:** `frontend-internal/src/routes/tickets/+page.svelte`
|
||
**Fix:** Corregidos los nombres de parámetros para coincidir con los Query params del backend.
|
||
|
||
### Bug #5 — Archivos con prefijo `+` causaban error de SvelteKit
|
||
**Causa:** Durante el desarrollo se crearon archivos de respaldo con nombres `+page.svelte.backup` y `+page.svelte.tmp`. SvelteKit interpreta cualquier archivo con `+` como una ruta especial.
|
||
**Fix:** Se eliminaron todos los archivos de respaldo con formato `+*.tmp`.
|
||
|
||
---
|
||
|
||
## 8. Correcciones Ortográficas (frontend-internal)
|
||
|
||
En `frontend-internal/src/routes/tickets/+page.svelte` se corrigieron 11 errores ortográficos:
|
||
|
||
| Línea aprox. | Antes | Después |
|
||
|---|---|---|
|
||
| ~145 | `priorida` | `prioridad` |
|
||
| ~189 | `Estad` | `Estado` |
|
||
| ~234 | `Accionnes` | `Acciones` |
|
||
| ~267 | `Assigado` | `Asignado` |
|
||
| ~310 | `Fecah` | `Fecha` |
|
||
| ~345 | `Prioiridad` | `Prioridad` |
|
||
| ~389 | `Ticktes` | `Tickets` |
|
||
| ~412 | `Resolucion` | `Resolución` |
|
||
| ~456 | `Sataus` | `Status` |
|
||
| ~478 | `Critcio` | `Crítico` |
|
||
| ~501 | `Asignar` → etiqueta incorrecta | Texto corregido contextualmente |
|
||
|
||
---
|
||
|
||
## 9. Notas de Migración
|
||
|
||
Para actualizar de v1.8.0 / v1.9.0 a v1.10.0:
|
||
|
||
```bash
|
||
# 1. Actualizar código
|
||
git pull origin main
|
||
git checkout version-1.10.0
|
||
|
||
# 2. Aplicar migraciones de base de datos
|
||
docker-compose exec backend alembic upgrade head
|
||
|
||
# 3. Reconstruir imágenes (cambios en Dockerfile)
|
||
docker-compose build --no-cache backend
|
||
|
||
# 4. Reiniciar todos los servicios
|
||
docker-compose up -d
|
||
|
||
# 5. Verificar salud
|
||
curl http://localhost:8000/health
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Estado del Sistema tras v1.10.0
|
||
|
||
| Componente | Estado | Notas |
|
||
|---|---|---|
|
||
| Backend FastAPI | ✅ Funcional | 0 errores 500 en endpoints principales |
|
||
| Frontend Interno | ✅ Funcional | Proxy Docker correcto |
|
||
| Frontend Cliente | ✅ Funcional | Nuevas rutas de perfil y organización |
|
||
| Base de Datos | ✅ Migrada | Tabla security_incidents disponible |
|
||
| Celery Workers | ✅ Funcional | Integrado con email service |
|
||
| Redis Cache | ✅ Funcional | Módulo cache.py implementado |
|
||
| Tests Unitarios | ✅ Nuevos | 5 nuevos archivos de tests |
|
||
| Docker Compose | ✅ Funcional | Todos los servicios healthy |
|
||
|
||
---
|
||
|
||
*Documento generado: 19 de Febrero de 2026*
|
||
*Versión del documento: 1.0*
|
||
*ServiceManagerWeb — Aduanasoft*
|