Decisiones de Arquitectura (ADRs)¶
Los ADRs (Architecture Decision Records) documentan las decisiones técnicas importantes: qué se decidió, por qué, y qué alternativas se descartaron.
Los archivos completos están en docs/es/adr/.
Índice¶
| ADR | Título | Estado |
|---|---|---|
| ADR-001 | Arquitectura de microservicios con FastAPI | Aceptado |
| ADR-002 | Multi-tenancy con schema isolation en PostgreSQL | Aceptado |
| ADR-003 | asyncpg directo en lugar de SQLAlchemy ORM | Aceptado |
| ADR-005 | API de operaciones por lotes (batch) | Aceptado |
| ADR-006 | Proveedor de IA configurable (multi-proveedor, global) para la capa de conocimiento | Propuesto |
| ADR-007 | Metadatos documentales con JSONB validado por plantilla | Propuesto |
| ADR-008 | Auditoría inmutable con audit_log encadenado por hash |
Propuesto |
| ADR-009 | Historial de flujos como eventos append-only + proyección | Propuesto |
| ADR-010 | Librería compartida orpycamcp_common (auditoría y eventos) |
Aceptado |
| ADR-011 | Frontend SvelteKit (SSR) como app de presentación en el monorepo | Propuesto |
| ADR-012 | Migraciones por tenant (runner global/ + tenant/) |
Aceptado |
| ADR-013 | Autorización resuelta en la BD por request (Keycloak autentica, la BD autoriza) | Aceptado |
| ADR-014 | Búsqueda con PostgreSQL FTS (tsvector + pg_trgm + JSONB), no Elasticsearch | Aceptado |
| ADR-015 | Modelo TRD/CCD: jerarquía serie↔subserie, retención en dos fases, disposición AGN (CT/E/S/M) | Aceptado |
| ADR-016 | Firma electrónica nativa (hash SHA-256 + identidad + sello de tiempo), PKI/PDF diferida | Aceptado |
| ADR-017 | Archivo físico: ubicación (dirección recursiva) ≠ unidad de conservación (contenedor móvil), patrón ArchivesSpace | Aceptado |
| ADR-018 | Interoperabilidad saliente por webhooks HTTP firmados (HMAC-SHA256) sobre el bus de eventos, suscritos por tenant | Aceptado |
| ADR-019 | Capa MCP como fachada fina cliente del gateway (catálogo de tools declarativo, sin lógica ni BD) | Aceptado |
| ADR-020 | Sistema de diseño Orpyca (tokens Sass + custom properties, branding por tenant) y asistente conversacional (texto/voz) como traductor a tools MCP con IA local opt-in | Propuesto |
| ADR-021 | Reclamación de PEL y dead-letter por grupo consumidor en Redis Streams (signature/workflow/notification-service) | Aceptado |
| ADR-022 | Perfil v2 del índice electrónico — metadatos RT-15 por documento (formato, tamaño, foliación) | Aceptado |
| ADR-023 | WORM / Object-Lock de preservación (MinIO) y hoja de ruta AIP/PREMIS | Aceptado (Increment A) |
| ADR-024 | USUA_PERM_ROOT no se concede desde la API — el administrador de entidad no es el techo de su entidad; ROOT solo se aprovisiona fuera de banda |
Aceptado |
| ADR-025 | La TRD es un instrumento convalidado, no una tabla de configuración: versionado append-only y fijación de la versión que gobierna cada expediente | Implementado (Increment 1+2) |
| ADR-026 | La TVD es el mismo instrumento con otro contenido: discriminador tipo_instrumento sobre trd_series, no tabla propia (registro y circuito de convalidación + amarre y calendario del fondo acumulado) |
Implementado (Increment 1+2) |
| ADR-027 | MinIO archivó su proyecto libre y retiró sus imágenes: el almacén pasa a RustFS, y el motor lo elige una batería de conformidad WORM contra un S3 real (RustFS 7/7, MinIO 7/7, Garage 0/7), no un folleto | Implementado |
| ADR-028 | El flujo mueve el estado del radicado: una función pura escrita en la misma transacción que el paso, cierre solo por «Finalizar trámite», closed/anulado terminales (409) y tenencia en marcar_leido; remediación de auditoría: clearance y tenencia en assign/transfer, la anulación cancela el paso, evidencia inmutable del backfill |
Implementado |
| ADR-029 | Ubicación actual del radicado: tres columnas flujo_* que escribe el workflow-service en el mismo UPDATE que el estado, dos columnas generadas ubicacion_* (por pares), una función pura derivar_ubicacion (último paso por cuándo se cerró, no por su número), código solo si el nombre es único, backfill con evidencia de solo inserción y fuera de todo lo público |
Implementado |
| ADR-031 | Constancia de autorización: IP firmada por el gateway en rutas públicas, política de tratamiento por entidad servida y releída por el servidor, y acuse de envío con autor y sin reutilización | Aceptado |
| ADR-032 | La dependencia se correlaciona por código, no por nombre: codigo inmutable (trigger + 422), función única resolver_codigo_dependencia con historial de nombres, contrato con código canónico y nombre como alias deprecado, backfill que falla cerrado ante lo ambiguo, desactivar/eliminar por código |
Aceptado |
| ADR-033 | Entrada de producción: nginx en contenedor (edge) como único servicio con puertos, TRUSTED_PROXIES sin el gateway de la red para que la IP sellada no se pueda forjar, Keycloak publicado solo en /realms/ y /resources/, y terceros fijados por tag y digest |
Aceptado |
| ADR-034 | La firma XAdES se declara como se aplica: Transforms explícitos en las referencias que signxml deja sin ellos, SignedInfo firmado después del parcheo (sello y firma personal), autoverificación fail-closed con XAdESVerifier() por defecto, sin atajo de canonicalización al verificar, y entrada del ArchiveTimeStamp según EN 319 132-1 §5.5.2; validado contra EU DSS |
Aceptado |
| ADR-035 | El estado de la entidad se hace cumplir en el borde: /auth/validate informa tenant_estado, el api-gateway veta (403 tenant_inactivo, 503 tenant_no_provisionado/tenant_estado_no_disponible, fail-closed) con el TTL de 15 s de su caché, cada get_tenant_conn lo vuelve a comprobar antes del search_path, una entidad suspendida conserva las lecturas públicas (verificación, OAI, CMIS, publicidad de la eliminación) y cierra sus escrituras con 503 canal_no_disponible, mientras inexistente, dada de baja y sin aprovisionar responden un 404 idéntico; el login no entrega token a una entidad no operativa y la identidad firmada caduca a los 120 s; consumidores de eventos y tareas en segundo plano quedan fuera a propósito |
Aceptado |
| ADR-036 | La identidad firmada se ata al método y a la ruta de la petición: ambos entran en la base del HMAC (v2) sin viajar como cabeceras, ruta_canonica (sin query, decodificada hasta estabilizar) idéntica en emisor y verificador, API sin valores por defecto y guardián AST que exige que la ruta firmada sea la llamada; una identidad reproducida en otra operación da 401 identidad_no_autentica y el despliegue es un corte atómico |
Aceptado |
Cómo proponer un nuevo ADR¶
- Crea el archivo
docs/es/adr/ADR-{NNN}-{slug}.md - Usa el formato estándar: Contexto, Decisión, Consecuencias, Alternativas
- Actualiza esta página con el nuevo ADR
- Abre un MR para discusión antes de marcar como "Aceptado"