@startuml security-threat-model !include _style.iuml scale max 1850 width top to bottom direction title 4. Modelo de amenazas STRIDE — Capas de seguridad skinparam ranksep 35 skinparam nodesep 30 actor "Cliente / Prestador\n(app móvil)" as MOBILE actor "Admin / Soporte\n(web)" as ADMIN cloud "Internet" as NET node "Edge TLS\n(Vercel)" as EDGE { artifact "HSTS, TLS 1.3" as TLS } node "Aplicación Next.js" as APP { component "Middleware JWT\n(jose verifyToken)" as JWT component "Guards de sesión\n(requireSession,\nrequireRole, requireOwner)" as GUARDS component "Validación Zod\n(schemas estrictos)" as ZOD component "Logger auditoría\n(logs_auditoria)" as AUDIT } database "Neon Postgres" as DB { artifact "RLS habilitado\npor tabla" as RLS artifact "RBAC permisos\nroles_admin x permisos" as RBAC artifact "logs_auditoria\nappend-only" as ALOG artifact "pins_soporte_cliente +\ncasos_soporte_abiertos\n(break-glass)" as BG } MOBILE --> NET ADMIN --> NET NET --> EDGE EDGE --> APP APP --> DB note right of TLS Mitigación TLS edge: Spoofing -> HSTS, TLS 1.3 termina en Vercel; rechazo de tráfico HTTP plano. end note note right of JWT Mitigación autenticación: Spoofing -> JWT firmado HS256 con JWT_SECRET (min 32 chars, validado al startup); rechazo de tokens forjados o expirados. end note note right of GUARDS Mitigación autorización: ElevationOfPrivilege -> requireSession bloquea sin token; requireRole valida rol contra lista; requireOwner consulta SQL para confirmar ownership antes de retornar recursos. end note note right of ZOD Mitigación tampering / DoS: Tampering -> schemas estrictos con strip de campos extra (rol, cliente_id forzados son ignorados); DoS -> límites de tamaño (cursor 256, notas 1000, limit 50, password 128). end note note right of AUDIT Mitigación Repudiation: cada mutación llama logAccion con actor_id, accion, recurso; el log se persiste en logs_auditoria antes de retornar la respuesta. end note note right of RLS Mitigación InformationDisclosure: ALTER TABLE ... ENABLE ROW LEVEL SECURITY en pins_soporte_cliente, casos_soporte_abiertos y demás tablas sensibles. Política de scoping a nivel app, alineada con el resto del schema. end note note right of RBAC Zero Trust default: rol lector_basico tiene solo usuarios.acceder_perfil; nuevos admins arrancan sin acceso. super_admin acumula todos los permisos explícitamente; cada rol está definido por filas en roles_permisos. end note note right of ALOG Mitigación Repudiation / forensics: append-only, consultable por timestamp, actor y recurso. Soporta reconstrucción de historia ante incidente. end note note right of BG Break-glass Zero Trust: el cliente genera un PIN desde su app (15 min de vigencia, hash en DB); el agente abre caso usando el PIN, lo que crea fila en casos_soporte_abiertos (vigente 4h). Sin PIN no hay acceso al perfil del cliente desde admin. end note note bottom of EDGE Mitigación DoS edge: rate limiting por IP en Vercel + WAF. Límites paginación (max 50) y payload (Zod max sizes). end note note top of APP Trust boundary 1: borde móvil <-> backend. Token siempre verificado; cookies HttpOnly + SameSite. end note note top of DB Trust boundary 2: backend <-> base de datos. DATABASE_URL solo en runtime Vercel; conexión TLS pooled. Trust boundary 3 (admin): admin <-> PII cliente requiere caso break-glass abierto. end note footer Fuente: apps/web/src/lib/auth/, packages/validations/src/, migrations/003_pins_soporte_cliente.sql, migrations/004_rbac_permisos_zero_trust.sql @enduml