Arquitectura¶
Custodiam sigue una arquitectura polyrepo con tres repositorios de código independientes coordinados desde un cuarto de orquestación + un quinto de documentación pública.
Repositorios del proyecto¶
custodiam-workspace/
├── custodiam-app/ ← Flutter (Android + iOS + Web) · github.com/custodiam/custodiam-app
├── custodiam-api/ ← FastAPI + SQLModel + PostgreSQL · github.com/custodiam/custodiam-api
├── custodiam-infra/ ← Docker Compose + Keycloak + Tunnels · github.com/custodiam/custodiam-infra
└── custodiam-book/ ← Documentación pública (este sitio) · github.com/custodiam/custodiam-book
La estructura polyrepo y la separación de los tres componentes de código están justificadas en ADR-001. La existencia del book como repositorio aparte (en lugar de mezclar la documentación con uno de los repos de código) está justificada en ADR-027.
Recorridos por la arquitectura¶
-
:material-stack-overflow: Stack técnico
Tecnologías concretas por capa: Flutter, FastAPI, SQLModel, PostgreSQL, Keycloak, Docker, Cloudflare.
-
:material-graph: Diagrama del sistema
Topología de despliegue y secuencias OAuth + notificación de emergencia.
-
:material-database: Modelo de datos
Esquema relacional, patrón catálogo + instancias + JSONB, diagrama ER del módulo voluntarios.
-
:material-table-network: Diagrama ER completo
Las dieciocho tablas de la base de datos de negocio por módulo y el mapa de relaciones entre módulos.
-
:material-sitemap: Flujos de negocio
Ciclo del voluntario, servicio preventivo, emergencia activa, fichaje, inventario.
-
:material-bell-ring: Notificaciones redundantes
Firebase Cloud Messaging como canal principal + ntfy como fallback automático.
-
:material-clipboard-text-clock: Audit log
Registro cross-module de operaciones críticas con patrón de imports diferidos.
Principios de diseño¶
- Polyrepo (ADR-001): tres repos independientes evitan el "monorepo monstruo" y permiten ciclos de release desacoplados (
custodiam-appcon releases semver para stores,custodiam-apicon su propio versionado,custodiam-infracon tags por entorno). - Clean Architecture estricta en
custodiam-app: tres capasdomain/data/presentation+infrastructurecross-cutting. Domain es Dart puro sin dependencias de framework. Data devuelveResult<T>siempre, no lanza excepciones cross-layer (ADR-014). - SQLModel en
custodiam-api(ADR-002): unifica SQLAlchemy 2.0 + Pydantic en una sola clase. Unatabla=Truees modelo de BD y schema de API en un único punto. - Resiliencia documentada: matriz de fallos del sistema con planes de degradación (FCM caído → ntfy como respaldo, Cloudflare Tunnel caído → modo dev local, Keycloak caído → degradación graceful con error 503).
- Notificaciones redundantes: Firebase Cloud Messaging como canal principal + ntfy como respaldo automático (Notificaciones redundantes).
- Auth basado en estándares: OAuth 2.0 + PKCE (RFC 7636) contra Keycloak (ADR-010, ADR-023). JWT validación local en backend con PyJWT. RBAC con doce roles jerárquicos y cuarenta permisos atómicos espejados en código backend y cliente (ADR-013).
Stack resumido¶
| Capa | Tecnología | Versión | Decisión |
|---|---|---|---|
| App móvil y web | Flutter + Dart | 3.x | ADR-001, ADR-022 (iOS 15+) |
| State management | Riverpod | 2.6+ | ADR-012 |
| BD local app | SQLite vía sqflite | — | ADR-005 |
| Backend | Python + FastAPI | 3.13 + 0.115+ | ADR-026 (uv) |
| ORM | SQLModel + Alembic | 0.0.22+ | ADR-002, ADR-003 |
| BD servidor | PostgreSQL + psycopg3 | 15 + 3.1+ | ADR-008, ADR-009 |
| Auth | Keycloak | 26+ | ADR-010, ADR-023 |
| Push notif | Firebase FCM + ntfy | — | Notificaciones redundantes |
| Email transaccional | Resend | — | ADR-021 |
| Servidor PWA | Nginx Alpine | — | ADR-006 |
| Registro Docker | GHCR | — | ADR-007 |
| Modos de despliegue | Docker Compose (dev / tunnel / prod) | 2.x | ADR-020 |
| Gestión de secretos | sops + age | — | ADR-019 |
| Documentación pública | Material for MkDocs + GitHub Pages | 9.x | ADR-027 |
Referencias¶
- ADRs públicos — registro completo de decisiones arquitectónicas con justificación y alternativas evaluadas.
- Empezar — cómo levantar el stack completo en local.