← Volver al índice | Análisis Tecnológico | Visión de Plataforma
Arquitectura del Sistema¶
Tipo: Documentación Técnica — Nivel 1
Audiencia: Equipo de desarrollo, arquitectos, DevOps
Relacionado con: Análisis Tecnológico Integral
1. Visión General por Fases¶
flowchart TB
subgraph F1 ["FASE 1 - MVP"]
F1A["App Movil"]
F1B["Web SPA"]
F1C["Backend"]
F1D["IA Engine"]
F1E["Vector DB"]
F1F["Base de Datos"]
end
subgraph F2 ["FASE 2 - Integracion"]
F2A["API Gateway"]
F2B["Modulo Acuicultura"]
F2C["Modulo Medio Marino"]
F2D["Data Lake"]
end
subgraph F3 ["FASE 3 - Plataforma"]
F3A["Dashboard Analytics"]
F3B["Busqueda Semantica"]
F3C["API Publica"]
end
F1A --> F1C
F1B --> F1C
F1C --> F1D
F1D --> F1E
F1C --> F1F
F2A --> F1C
F2A --> F2B
F2A --> F2C
F2B --> F2D
F2C --> F2D
F1C --> F2D
F2D --> F3A
F2D --> F3B
F3B --> F3C
style F1C fill:#e74c3c,color:#fff
style F2A fill:#3498db,color:#fff
style F2D fill:#f39c12,color:#fff
style F3B fill:#9b59b6,color:#fff
2. Stack Tecnológico¶
| Capa | Tecnología | Justificación |
|---|---|---|
| App Móvil | React Native + react-native-vision-camera |
Híbrida iOS/Android, frame processors para visión en tiempo real |
| Web SPA | React + Vite | Misma base de conocimiento que RN, acceso a cámara web/video |
| Backend API | Quarkus 3.20 LTS (Java 25) | Cloud-native, startup 20ms nativo, K8s-ready, live coding |
| Middleware | Dapr (sidecar) | Service invocation, pub/sub, state, workflows, bindings |
| IA/LLM | LangChain4j + Ollama (local) | Interfaces CDI declarativas, multi-modelo, RAG/CAG nativo |
| Ecosistema | Microsoft 365 + Graph API | Ingesta desde SharePoint/OneDrive, identidad Entra ID |
| Modelos | Qwen2.5-VL + OceanGPT + YOLOv11 | Stack departamental especializado, soberanía total |
| Vector DB | ChromaDB (MVP) / Milvus (escala) | Embeddings multimodales, búsqueda por similitud |
| Base de Datos | PostgreSQL + pgvector | Datos relacionales + extensión vectorial nativa |
| Cache | Redis | Cache KV para CAG, sesiones, rate limiting |
| Storage | MinIO (S3-compatible) | Almacenamiento de imágenes y archivos |
| Messaging | Apache Kafka via Dapr Pub/Sub | Eventos asíncronos entre servicios |
| Contenedores | Docker Compose → Kubernetes | Orquestación local → DragonCloud / CSIC |
3. Backend: Quarkus + Dapr + LangChain4j¶
[!IMPORTANT] Quarkus 3.20 LTS (Java 25) como runtime cloud-native. Dapr como middleware de integración (sidecar). LangChain4j para servicios IA declarativos. Ver Análisis de Viabilidad para la justificación completa.
Arquitectura de Capas¶
flowchart TB
subgraph QK ["Quarkus (Java 25)"]
QK1["REST API"]
QK2["WebSocket (Virtual Threads)"]
QK3["Security OIDC/OAuth2"]
QK4["Panache ORM"]
QK5["LangChain4j AI Services"]
end
subgraph DAPR ["Dapr Sidecar"]
D1["Service Invocation"]
D2["Pub/Sub (Kafka)"]
D3["State Management"]
D4["Workflows"]
D5["Bindings"]
end
QK1 --> D1
QK2 --> QK5
QK5 --> D1
D5 --> D3
D4 --> D2
style QK1 fill:#27ae60,color:#fff
style D1 fill:#9b59b6,color:#fff
style QK5 fill:#e74c3c,color:#fff
Responsabilidades por capa¶
| Aspecto | Quarkus | Dapr | LangChain4j |
|---|---|---|---|
| API REST | Nativo (RESTEasy Reactive) | — | — |
| Concurrencia | Virtual Threads (Java 25) | — | — |
| WebSocket/Video | Quarkus WebSocket Next | — | — |
| IA / LLM | — | Service Invocation → Ollama | Interfaces CDI declarativas |
| Workflows | — | Dapr Workflows (long-running) | — |
| Integración | — | Bindings (GSheets, SharePoint) | — |
| Estado | — | State Management (Redis) | — |
| Eventos | — | Pub/Sub (Kafka) | — |
| Resiliencia | K8s probes | Retry policies (YAML) | — |
4. Modelo de Datos¶
erDiagram
DEPARTAMENTO ||--o{ INVESTIGADOR : pertenece
DEPARTAMENTO ||--o{ COLECCION : gestiona
COLECCION ||--o{ MUESTRA : contiene
MUESTRA ||--o{ IMAGEN_MUESTRA : tiene
MUESTRA ||--o{ PARAMETRO_BIOLOGICO : mide
MUESTRA }o--|| ESPECIE : identifica
ESPECIE ||--o{ TAXONOMIA : clasifica
MUESTRA }o--|| CAMPANA : proviene
CAMPANA }o--|| ZONA_GEOGRAFICA : realizada_en
IMAGEN_MUESTRA ||--|| EMBEDDING_VECTOR : genera
MUESTRA {
uuid id PK
string codigo_interno
date fecha_captura
string metodo_captura
float latitud
float longitud
string estado_conservacion
timestamp created_at
}
ESPECIE {
uuid id PK
string nombre_cientifico
string nombre_comun
string familia
string orden
string clase
}
PARAMETRO_BIOLOGICO {
uuid id PK
float talla_cm
float peso_g
string sexo
string madurez_gonadal
int edad_estimada
}
IMAGEN_MUESTRA {
uuid id PK
string ruta_archivo
string tipo_imagen
jsonb metadatos_exif
timestamp fecha_captura
}
EMBEDDING_VECTOR {
uuid id PK
string modelo_embedding
vector embedding_768d
float confidence_score
}
5. Arquitectura Docker Compose del MVP¶
flowchart TB
subgraph FE ["Frontend"]
RN["React Native - Expo"]
WEB["React SPA + React Flow"]
end
subgraph BE ["Backend"]
API["Quarkus (Java 25)"]
DAPR2["Dapr Sidecar"]
end
subgraph AI ["AI / ML"]
OLL["Ollama - Qwen2.5-VL"]
end
subgraph DT ["Data"]
PG["PostgreSQL + pgvector"]
CHR["ChromaDB"]
RDS["Redis"]
end
subgraph MSG ["Messaging"]
KFK["Apache Kafka"]
end
subgraph ST ["Storage"]
MIN["MinIO - S3"]
end
RN --> API
WEB --> API
API --> DAPR2
DAPR2 --> OLL
DAPR2 --> PG
DAPR2 --> CHR
DAPR2 --> RDS
DAPR2 --> KFK
DAPR2 --> MIN
style API fill:#2ecc71,color:#fff
style DAPR2 fill:#9b59b6,color:#fff
style OLL fill:#e74c3c,color:#fff
style PG fill:#3498db,color:#fff
| Servicio | Imagen | Puertos | Propósito |
|---|---|---|---|
api |
Build from Dockerfile (Java 25 + Quarkus) | 8080 | Backend principal |
api-dapr |
daprio/daprd | — | Sidecar Dapr (service mesh) |
web |
node:22 + vite | 5173 | SPA React + React Flow |
ollama |
ollama/ollama | 11434 | Servidor LLM local (Qwen2.5-VL) |
postgres |
pgvector/pgvector:pg16 | 5432 | BD relacional + vectores |
chromadb |
chromadb/chroma | 8000 | Vector DB dedicada |
redis |
redis:7-alpine | 6379 | Cache, state management Dapr |
kafka |
confluentinc/cp-kafka | 9092 | Pub/Sub Dapr |
minio |
minio/minio | 9000/9001 | Almacenamiento de imágenes |
6. Flujos de Uso¶
6.1 Captura y Reconocimiento de Nueva Muestra¶
sequenceDiagram
actor Investigador
participant App as App Movil / Web
participant API as Quarkus API
participant Dapr as Dapr Sidecar
participant AI as Ollama Qwen2.5-VL
participant VDB as ChromaDB
participant DB as PostgreSQL
Investigador->>App: Fotografía nueva muestra
Investigador->>App: Introduce metadatos talla peso zona
App->>API: POST /api/v1/samples imagen + metadatos
API->>Dapr: Service Invocation
Dapr->>AI: LangChain4j genera embedding de imagen
AI-->>Dapr: Embedding vector 768d
Dapr->>VDB: Búsqueda por similitud top-K
VDB-->>Dapr: Muestras similares + scores
Dapr->>AI: Genera informe con contexto CAG/RAG
AI-->>Dapr: Identificación + explicación
Dapr->>DB: Persiste muestra + resultado
Dapr-->>API: Resultado completo
API-->>App: Respuesta JSON con identificación
App-->>Investigador: Especie detectada + confianza + similares
6.2 Video en Tiempo Real con Detección Dinámica¶
sequenceDiagram
actor Investigador
participant App as App Movil / Web
participant WS as Quarkus WebSocket
participant Dapr as Dapr Sidecar
participant AI as Ollama Qwen2.5-VL
Investigador->>App: Activa modo Video en Vivo
App->>WS: WebSocket CONNECT /ws/realtime
loop Cada N frames
App->>WS: Frame base64 / binario
WS->>Dapr: Service Invocation
Dapr->>AI: Clasificación rápida
AI-->>Dapr: Especie + bounding box + confianza
Dapr-->>WS: Detección resultado
WS-->>App: WS message overlay data
App-->>Investigador: Overlay en pantalla
end
Investigador->>App: Captura frame específico
App->>WS: POST /api/v1/samples/from-frame
7. Frontend: App Móvil¶
Arquitectura React Native¶
flowchart TB
subgraph RNApp ["React Native App"]
CAM["Camera View"]
FP["Frame Processor"]
CAP["Captura Manual"]
GAL["Galeria Muestras"]
RES["Resultados IA"]
end
CAM --> FP
CAM --> CAP
FP -->|frame por frame| APIC["API Call"]
CAP -->|imagen completa| APIC
APIC --> RES
GAL --> RES
subgraph FUNC ["Funcionalidades"]
F1["Captura de foto"]
F2["Video en tiempo real"]
F3["Metadatos manuales"]
F4["Historial detecciones"]
F5["Modo offline TFLite"]
end
Librerias clave¶
| Libreria | Función |
|---|---|
react-native-vision-camera |
Acceso a cámara, frame processors nativos via JSI |
react-native-fast-tflite |
Inferencia TensorFlow Lite on-device (Edge AI) |
react-native-worklets-core |
Ejecución en hilo GPU/CPU de cámara |
@tanstack/react-query |
Estado servidor y cache |
react-native-mmkv |
Persistencia local rápida |
Web SPA: Estrategia de Contingencia¶
La app web usa las mismas funcionalidades pero con tecnologías web nativas:
| Capa | Tecnología Web |
|---|---|
| Captura de video | navigator.mediaDevices.getUserMedia (HTML5) |
| Streaming | WebRTC hacia el backend |
| Inferencia local | WebAssembly (WASM) + TensorFlow.js |
| Preprocesado | Canvas API |
8. Consideraciones Tecnicas¶
Privacidad y Soberanía¶
- Todos los modelos de IA corren localmente (Ollama) — sin envio de datos a APIs externas
- Datos del IEO son propiedad del CSIC — soberanía total
- Docker Compose permite despliegue completamente on-premise
- Cloud certificada ENS ALTO con cifrado CMEK cuando se escale
Interoperabilidad con SIRENO¶
- ETL batch para sincronizar datos de SIRENO (Oracle) a PostgreSQL
- API REST como capa de abstracción sobre SIRENO
- Estrategia de migración gradual: coexistencia antes de sustitución
Modelos de IA: Estrategia de Entrenamiento¶
[!NOTE] "LLM entrenado con muestras" no implica reentrenar desde cero: 1. CAG+RAG: Inyectar conocimiento via contexto (sin fine-tuning) 2. Fine-tuning ligero: LoRA/QLoRA sobre Qwen2.5-VL si se necesita mayor precisión 3. Embeddings custom: Modelo de embeddings específico para fauna del Atlántico Centro Oriental
Escalabilidad: Docker → Kubernetes¶
El stack está diseñado para cero cambios de código entre entornos:
| Aspecto | Docker Compose (dev) | Kubernetes (prod) |
|---|---|---|
| Configuración | .env + environment: |
ConfigMap |
| Secretos | .env (gitignored) |
K8s Secret / Dapr Secrets |
| Dapr sidecar | Servicio explícito | Inyección automática (operador) |
| Puertos | 8080 (API) + 8081 (management) | Mismo patrón |
| Health checks | :8081/health/live |
livenessProbe + readinessProbe |
| GPU | deploy.resources.reservations |
NVIDIA Device Plugin |
| Escalado | 1 réplica | N réplicas + HPA |
Convención DevOps del equipo:
# Puerto 8080 = API de negocio (REST, WebSocket)
# Puerto 8081 = Management (health, métricas, readiness)
quarkus.management.enabled=true
quarkus.management.port=8081
quarkus.management.root-path=/
Actualización dinámica de configuración: Dapr Configuration API suscribe a cambios en ConfigMaps y notifica a Quarkus sin restart. Ver Docker Compose para manifiestos K8s completos.
- Dapr ya prepara la transición a K8s (sidecar injection automático)
- Kafka como backbone de eventos entre servicios
- ChromaDB a Milvus para escala
- Keycloak para autenticación federada CSIC
- Target: DragonCloud (infraestructura CSIC)
Documentos Relacionados¶
| Nivel | Documento | Descripción |
|---|---|---|
| Arquitectura | Pivote Quarkus+Dapr | Decisión arquitectónica: stack completo |
| Arquitectura | Viabilidad Pekko→Dapr | FSMs, escenarios, evaluación de migración |
| Arquitectura | MLOps y Workflows Agénticos | MLOps, Dapr Workflow, LangChain4j, sistema agéntico |
| Arquitectura | Arquitectura IA | Pipeline CAG+RAG, modelos, métricas |
| Arquitectura | Modelo de Datos | Schema PostgreSQL + pgvector + ChromaDB |
| Investigación | Gobernanza de Datasets | Fuentes de datos, carga incremental, auditoría |
| Negocio | Visión de Plataforma | Presentación de alto nivel para el cliente |
| Investigación | Análisis Tecnológico Integral | Fundamentos: datos, ENS, M365, CAG+RAG, Edge AI |
| Infraestructura | Docker Compose | Configuración detallada del entorno |
| Proyecto | Roadmap | Hitos y criterios de aceptación |