diff --git a/README.md b/README.md
index 5c54be6..bf56ccc 100644
--- a/README.md
+++ b/README.md
@@ -1763,24 +1763,31 @@ La infraestructura de despliegue se divide en los entornos de cliente, la red de
* **Dispositivos físicos (iOS/Android):** Dentro opera el *Flutter Engine*, entorno encargado de ejecutar la aplicación mobile.
* **Computadoras de los usuarios:** Utilizan un navegador web como nodo de ejecución para renderizar la aplicación web (Angular).
-2. **Entorno de Nube - Red Perimetral (AWS Edge Location):**
- Para garantizar baja latencia y alta seguridad antes de que el tráfico llegue a los servidores principales, se utilizan los nodos Edge de AWS distribuidos globalmente.
- * **Amazon CloudFront (CDN & Reverse Proxy):** Actúa como el primer punto de contacto (Proxy Inverso). Almacena en caché los archivos estáticos de la Web App en ubicaciones cercanas al usuario para cargas instantáneas, y enruta de forma segura y eficiente el tráfico dinámico hacia la región principal de AWS.
+2. **Entorno Global - DNS y Red Perimetral (AWS Global):**
+ El dominio propio (`tamci.app`) y la distribución de contenido son servicios globales de AWS, sin una región específica asociada.
+ * **Amazon Route 53:** Aloja la zona DNS de `tamci.app`. El subdominio `app.tamci.app` resuelve hacia la distribución de CloudFront (tráfico real de usuarios); el subdominio `api.tamci.app` resuelve hacia el Application Load Balancer, pero únicamente como *origen técnico* de CloudFront — no es alcanzable directamente desde internet (ver Security Groups más abajo).
+ * **AWS Certificate Manager (ACM):** Emite y renueva automáticamente los certificados TLS gratuitos para `api.tamci.app` y `app.tamci.app`.
+ * **Amazon CloudFront (CDN & Reverse Proxy):** Actúa como el único punto de contacto público de toda la plataforma. Sirve los archivos estáticos de la Web App (Angular) desde un bucket S3 privado, y enruta el tráfico dinámico (`/api/*`, `/ws/*`) hacia el backend en la región `us-east-1`. Una **CloudFront Function** ejecutada en el edge rechaza (HTTP 403) cualquier petición cuyo encabezado `Host` no sea `app.tamci.app`, bloqueando así el dominio genérico `*.cloudfront.net` que AWS asigna por defecto.
3. **Entorno de Nube - Procesamiento (AWS North America — us-east-1, Virginia):**
- La lógica de negocio se aloja en la región de AWS North America, elegida por su alta disponibilidad y ecosistema completo de servicios administrados.
- * **AWS API Gateway:** Recibe el tráfico dinámico desde CloudFront (web) y directamente desde la app móvil, funcionando como orquestador de peticiones REST y WebSocket hacia el backend.
- * **ECS Cluster (AWS ECS + Fargate):** El backend se despliega como un contenedor Docker en **AWS ECS con Fargate** (serverless containers). Fargate abstrae completamente la gestión de servidores EC2 subyacentes, provisionando cómputo bajo demanda con autoescalado automático. La task definition del ECS define dos contenedores en la misma unidad de ejecución: el **ReqsAI Backend Service** (Java 25 + Spring Boot 4) y el **Grafana Alloy** como sidecar de observabilidad.
- * **Observability Server (AWS EC2 + Docker Compose):** Una instancia EC2 dedicada ejecuta el stack de observabilidad completo mediante Docker Compose: **Prometheus** (almacén de métricas, consultado con PromQL), **Loki** (agregación de logs, consultado con LogQL), **Tempo** (trazas distribuidas, consultado con TraceQL) y **Grafana** (dashboard unificado que visualiza las tres fuentes). Grafana Alloy, corriendo como sidecar en el ECS Cluster, colecta las métricas del endpoint `/actuator/prometheus`, logs del stdout del contenedor y trazas OTLP, enviándolos al servidor de observabilidad mediante push.
+ La lógica de negocio se aloja en una VPC dedicada dentro de la región AWS North America, elegida por su alta disponibilidad y ecosistema completo de servicios administrados. La VPC segmenta el tráfico en subredes públicas, privadas y de base de datos, cada una protegida por *Security Groups* que solo confían en la capa inmediatamente anterior.
+ * **Application Load Balancer (subred pública):** Termina TLS con el certificado de `api.tamci.app` y reenvía el tráfico HTTP al backend. Su Security Group **solo acepta conexiones desde el rango de IPs administrado de CloudFront** (AWS Managed Prefix List) — ni la propia URL del balanceador ni ningún otro origen pueden alcanzarlo directamente.
+ * **ECS Cluster (subred privada, AWS ECS + Fargate):** El backend se despliega como un único contenedor Docker en **AWS ECS con Fargate** (serverless containers, 1 vCPU / 2 GB), sin contenedores adicionales de observabilidad en la misma tarea. Fargate abstrae completamente la gestión de servidores EC2 subyacentes, provisionando cómputo bajo demanda. Su Security Group solo acepta tráfico proveniente del ALB.
+ * **NAT Gateway (subred pública):** Permite que las tareas de ECS, alojadas en subred privada, realicen llamadas salientes hacia APIs externas (LLM, STT, SMTP) y descarguen la imagen Docker desde ECR, sin exponer las tareas directamente a internet.
-4. **Entorno de Nube - Persistencia (AWS RDS):**
- * **AWS RDS (PostgreSQL + pgvector):** La base de datos principal se gestiona completamente en **Amazon RDS**, el servicio de base de datos relacional administrado de AWS. Se utiliza **PostgreSQL** con la extensión **pgvector** habilitada, esencial para el almacenamiento de embeddings vectoriales que alimentan el motor RAG. RDS provee backups automáticos, failover multi-AZ y actualizaciones de parches sin downtime.
+4. **Entorno de Nube - Persistencia (subred de base de datos):**
+ * **AWS RDS (PostgreSQL + pgvector):** La base de datos principal se gestiona completamente en **Amazon RDS** (`db.t4g.micro`, single-AZ, almacenamiento cifrado), con la extensión **pgvector** habilitada para el almacenamiento de embeddings vectoriales que alimentan el motor RAG. Su Security Group solo acepta conexiones desde las tareas de ECS.
+
+5. **Servicios administrados de soporte (sin infraestructura propia):**
+ * **Amazon ECR:** Registro privado de las imágenes Docker del backend, actualizado en cada despliegue por el pipeline de CI/CD.
+ * **AWS Secrets Manager:** Almacena las llaves de firma JWT, las credenciales SMTP, las API keys de los proveedores de IA (Deepgram, OpenAI) y la contraseña maestra de RDS (autogenerada y rotada por el propio servicio). El backend los lee al arrancar, inyectados como variables de entorno por ECS — nunca quedan en texto plano en la Task Definition.
+ * **Amazon CloudWatch Logs:** Recibe los logs de aplicación (stdout/stderr) del contenedor vía el driver `awslogs`.
**Comunicación e Interacción de Nodos**
-* **App Web:** El navegador carga el SPA Angular desde **CloudFront** (Edge Location más cercano). Las llamadas de API del SPA viajan CloudFront → API Gateway → ECS Backend.
-* **App Móvil:** La app Flutter instalada en el dispositivo del usuario realiza llamadas HTTPS **directamente la API Gateway**, sin pasar por CloudFront, ya que no es una aplicación web servida desde CDN.
-* **Observabilidad:** Grafana Alloy (sidecar en ECS) colecta continuamente métricas, logs y trazas del backend y los envía al Observability Server en EC2. Grafana consulta Prometheus, Loki y Tempo para mostrar el estado del sistema en tiempo real.
+* **App Web:** El navegador carga el SPA Angular desde **CloudFront** (Edge Location más cercano, dominio `app.tamci.app`). Las llamadas de API del SPA usan rutas relativas (`/api/*`, `/ws/*`) que el propio CloudFront reenvía al ALB bajo el mismo origen — el frontend nunca necesita conocer una URL de backend distinta.
+* **App Móvil:** La app Flutter también dirige sus llamadas a través de **CloudFront** (`app.tamci.app/api`, `/ws`); a diferencia del diseño original, el Security Group del ALB ya no permite tráfico directo desde ningún cliente que no sea CloudFront, por lo que ninguna llamada puede saltarse el edge.
+* **Observabilidad:** El backend escribe sus logs a **Amazon CloudWatch Logs**; no existe un stack de observabilidad autoadministrado (Prometheus/Loki/Tempo/Grafana) en esta iteración de la infraestructura.
* **Persistencia:** El backend se conecta a **AWS RDS** via JDBC/JPA para todas las operaciones transaccionales de los 5 Bounded Contexts.
# Capítulo V: Tactical-Level Software Design
@@ -6270,7 +6277,8 @@ Para garantizar el despliegue automático, escalable y seguro de cada uno de los
| **Web Application (Angular)** | **AWS S3 + CloudFront** | Distribución global de la Single Page Application (SPA), almacenamiento seguro de compilados y redirección de APIs. | [https://aws.amazon.com/cloudfront](https://aws.amazon.com/cloudfront) |
| **Backend Service (Spring Boot)** | **AWS ECS + Fargate** | Despliegue serverless de la API modularizada en contenedores Docker y orquestación de recursos de cómputo. | [https://aws.amazon.com/ecs](https://aws.amazon.com/ecs) |
| **Database (PostgreSQL)** | **AWS RDS** | Base de datos relacional administrada para almacenar datos transaccionales, de tenants y embeddings vectoriales (pgvector). | [https://aws.amazon.com/rds](https://aws.amazon.com/rds) |
-| **Observability (Grafana Stack)** | **AWS EC2 + Docker Compose** | Instancia dedicada para almacenar y consultar logs (Loki), métricas (Prometheus) y trazas (Tempo) de la infraestructura. | [https://aws.amazon.com/ec2](https://aws.amazon.com/ec2) |
+| **DNS y certificados (tamci.app)** | **AWS Route 53 + ACM** | Zona DNS del dominio propio y certificados TLS gratuitos autorenovables para el ALB y CloudFront. | [https://aws.amazon.com/route53](https://aws.amazon.com/route53) |
+| **Logs de aplicación** | **Amazon CloudWatch Logs** | Recolección de logs de stdout/stderr del contenedor del backend vía el driver `awslogs`. | [https://aws.amazon.com/cloudwatch](https://aws.amazon.com/cloudwatch) |
@@ -6282,12 +6290,13 @@ Para garantizar el despliegue automático, escalable y seguro de cada uno de los
* Se configura una distribución en **Amazon CloudFront** que sirve de CDN. Se establece una política de Control de Acceso de Origen (OAC) para bloquear el acceso público directo a S3, obligando a los usuarios a acceder a través de CloudFront.
* Se configuran reglas de redirección de errores en CloudFront de modo que cualquier error HTTP 404 sea redirigido a `/index.html` con un código HTTP 200, garantizando el correcto funcionamiento del enrutamiento del lado del cliente del SPA.
* Se asocia un dominio personalizado y certificados SSL/TLS gratuitos administrados por **AWS Certificate Manager (ACM)** para brindar HTTPS.
+* Para el Aplicativo Web, la distribución de CloudFront agrega el Application Load Balancer del backend como un segundo origen, enrutando las rutas `/api/*` y `/ws/*` hacia él (sin caché) — así el SPA llama al backend con rutas relativas, bajo el mismo origen, sin necesidad de configurar CORS. Una **CloudFront Function** ejecutada en el edge rechaza cualquier petición cuyo encabezado `Host` no sea el dominio propio, bloqueando el acceso vía el dominio genérico `*.cloudfront.net`.
**2. Backend Service (AWS ECS con Fargate)**
* Se define un `Dockerfile` multietapa para compilar el backend modular con Java 25 y Spring Boot 4, creando una imagen Docker ligera optimizada para producción.
-* Al realizar un merge en la rama `main`, un pipeline de CI/CD en **GitHub Actions** ejecuta las pruebas automatizadas, empaqueta la imagen Docker y la sube al repositorio privado en **Amazon ECR (Elastic Container Registry)**.
-* Se configura una **Task Definition** en AWS ECS que define los parámetros de ejecución. Esta especifica dos contenedores que operan conjuntamente en la misma tarea (patrón sidecar): el contenedor de la aplicación backend Reqs-AI (expuesto en el puerto 8080) y el agente **Grafana Alloy** para la recolección de logs, métricas y trazas distribuidas.
-* La tarea se ejecuta de manera serverless en **AWS Fargate** asignando CPU y memoria virtual dinámicamente y protegiendo el servicio mediante un Balanceador de Carga de Aplicación (ALB) asociado al AWS API Gateway.
+* Al realizar un merge en la rama `main`, un pipeline de CI/CD en **GitHub Actions** (autenticado vía OIDC, sin llaves de AWS de larga duración) ejecuta las pruebas automatizadas, empaqueta la imagen Docker y la sube al repositorio privado en **Amazon ECR (Elastic Container Registry)**.
+* Se configura una **Task Definition** en AWS ECS con un único contenedor (1 vCPU / 2 GB) para la aplicación backend Reqs-AI, expuesto en el puerto 8080. Las variables de entorno no sensibles (URLs, nombres de proveedor) se definen en texto plano en la Task Definition; los secretos (llaves JWT, credenciales SMTP, API keys de IA, contraseña de RDS) se inyectan en tiempo de arranque desde **AWS Secrets Manager**, referenciados por su ARN.
+* La tarea se ejecuta de manera serverless en **AWS Fargate** dentro de una subred privada, protegida por un **Application Load Balancer** cuyo Security Group solo acepta tráfico proveniente del rango de IPs administrado de **Amazon CloudFront** — no existe una ruta de acceso directa al backend desde internet.
**3. Base de Datos Relacional y Multitenancy (AWS RDS)**
* Se provisiona una instancia relacional de **PostgreSQL** administrada a través de **AWS RDS** dentro de subredes privadas.
diff --git a/assets/diagrams/architecture/deployment-diagram.png b/assets/diagrams/architecture/deployment-diagram.png
index 8953e89..0251bb2 100644
Binary files a/assets/diagrams/architecture/deployment-diagram.png and b/assets/diagrams/architecture/deployment-diagram.png differ
diff --git a/assets/diagrams/architecture/deployment-diagram.puml b/assets/diagrams/architecture/deployment-diagram.puml
index be33fb1..cf505ad 100644
--- a/assets/diagrams/architecture/deployment-diagram.puml
+++ b/assets/diagrams/architecture/deployment-diagram.puml
@@ -56,73 +56,84 @@ node "User Workstations [Windows / macOS / Linux]" as workstations {
}
' ────────────────────────────────────────────────────────────────────
-' AWS EDGE LOCATION
+' AWS GLOBAL / EDGE (DNS + CDN son servicios globales, sin region)
' ────────────────────────────────────────────────────────────────────
-node "AWS Edge Location [Amazon CloudFront]" as edgeLayer {
- artifact "CDN & Reverse Proxy\n[Amazon CloudFront]\nSirve SPA estatico + enruta API" as cdn
+node "AWS Global [DNS + Edge Network]" as awsGlobal {
+ artifact "Amazon Route 53\n[Hosted Zone: tamci.app]\napp.tamci.app -> CloudFront\napi.tamci.app -> ALB (solo como origen)" as route53
+ artifact "AWS Certificate Manager\n[ACM]\nCertificados TLS:\napi.tamci.app, app.tamci.app" as acm
+
+ node "Amazon CloudFront Distribution [app.tamci.app]" as cdn {
+ artifact "CloudFront Function\n[Viewer Request]\nRechaza Host != app.tamci.app\n(bloquea el dominio *.cloudfront.net\ny cualquier acceso directo)" as cfFunction
+ artifact "Cache Behaviors\nDefault /* -> S3 (SPA estatico)\n/api/*, /ws/* -> ALB (sin cache)" as cfBehaviors
+ }
}
' ────────────────────────────────────────────────────────────────────
-' AWS NORTH AMERICA (us-east-1 — Virginia)
+' AWS North America (us-east-1 — Virginia) — VPC
' ────────────────────────────────────────────────────────────────────
-node "AWS North America [AWS Region us-east-1 (Virginia)]" as awsNorthAmerica {
+node "AWS North America [AWS Region us-east-1 (Virginia) — VPC]" as awsNorthAmerica {
- node "API Gateway [AWS API Gateway]" as apiGatewayNode {
- artifact "API Gateway\n[AWS API Gateway]\nRouting REST + WebSocket" as apiGw
+ node "Public Subnets" as publicSubnets {
+ artifact "Application Load Balancer\n[HTTPS :443, cert api.tamci.app]\nHTTP :80 -> redirect HTTPS\nSecurity Group: solo trafico desde\nCloudFront (managed prefix list)" as alb
+ artifact "NAT Gateway" as nat
}
- node "ECS Cluster [AWS ECS + Fargate]" as ecsCluster {
- component "ReqsAI Backend Service\n[Java 25 + Spring Boot 4 / Docker Container]\n\nModulos: IAM · Billing · Workspace\nRequirement Discovery · Integration Gateway" as backend
- artifact "Grafana Alloy\n[Sidecar Container]\nColecta metricas, logs y trazas\ndel backend y los envia al\nservidor de observabilidad" as alloy
+ node "Private Subnets" as privateSubnets {
+ node "ECS Cluster [AWS ECS + Fargate]" as ecsCluster {
+ component "ReqsAI Backend Service\n[Java 25 + Spring Boot 4 / Docker]\n1 vCPU / 2 GB — Fargate\n\nModulos: IAM · Billing · Workspace\nRequirement Discovery · Integration Gateway\n\nSecurity Group: solo trafico desde el ALB" as backend
+ }
}
- node "Observability Server [AWS EC2 + Docker Compose]" as obsServer {
- component "Prometheus\n[Metricas]" as prometheus
- component "Loki\n[Logs]" as loki
- component "Tempo\n[Trazas distribuidas]" as tempo
- component "Grafana\n[Dashboards]" as grafana
+ node "Database Subnets" as dbSubnets {
+ database "AWS RDS — PostgreSQL + pgvector\n[db.t4g.micro, single-AZ, cifrado]\nSecurity Group: solo trafico\ndesde las tareas ECS" as db
}
}
' ────────────────────────────────────────────────────────────────────
-' AWS RDS
+' AWS MANAGED SERVICES (soporte al runtime, sin servidor propio)
' ────────────────────────────────────────────────────────────────────
-node "AWS RDS [Managed Relational Database]" as dbNode {
- database "PostgreSQL + pgvector\n[ReqsAI Main Database]" as db
+node "AWS Managed Services [sin infraestructura propia que administrar]" as awsManaged {
+ artifact "Amazon ECR\n[Registro de imagenes Docker]" as ecr
+ artifact "AWS Secrets Manager\n[JWT keys, credenciales SMTP,\nAPI keys de IA, password de RDS]" as secretsManager
+ artifact "Amazon CloudWatch Logs\n[Logs de aplicacion via awslogs]" as cloudwatch
+ artifact "Amazon S3\n[Bucket privado — build Angular\nsolo legible via CloudFront OAC]" as s3web
}
' ────────────────────────────────────────────────────────────────────
' RELATIONS
' ────────────────────────────────────────────────────────────────────
' Web: pasa por CloudFront
-webApp --> cdn : "HTTPS"
-cdn --> webApp : "Sirve SPA estatico\n(Edge Locations)"
-cdn --> apiGw : "Enruta trafico API\nHTTPS"
+webApp --> cdn : "HTTPS\napp.tamci.app"
+cdn --> webApp : "Sirve SPA estatico\n(Edge Locations)"
+
+' Mobile: tambien pasa por CloudFront -- el ALB no acepta trafico\ndirecto (Security Group solo confia en CloudFront)
+mobileApp --> cdn : "Llamadas API\nHTTPS / REST + WebSocket\napp.tamci.app/api, /ws"
-' Mobile: directo al API Gateway (app instalada, no servida por CDN)
-mobileApp --> apiGw : "Llamadas API directas\nHTTPS / REST + WebSocket"
+cdn --> s3web : "Origen 1: assets estaticos\n(Origin Access Control)"
+cdn --> alb : "Origen 2: /api/*, /ws/*\nHTTPS, SNI = api.tamci.app"
-apiGw --> backend : "Route all requests\nHTTPS / REST"
+route53 ..> cdn : "resuelve\napp.tamci.app"
+route53 ..> alb : "resuelve\napi.tamci.app"
+acm ..> cdn : "certificado TLS"
+acm ..> alb : "certificado TLS"
-' Observabilidad: Alloy como sidecar recolecta del backend
-backend --> alloy : "Metricas /actuator/prometheus\nLogs stdout · Trazas OTLP"
-alloy --> prometheus : "Push metricas\nRemote Write"
-alloy --> loki : "Push logs"
-alloy --> tempo : "Push trazas\nOTLP"
-grafana --> prometheus : "Query metricas\nPromQL"
-grafana --> loki : "Query logs\nLogQL"
-grafana --> tempo : "Query trazas\nTraceQL"
+alb --> backend : "Forward\nHTTP :8080"
-' Persistencia
-backend --> db : "Reads and writes\nJDBC / JPA"
+' Persistencia y soporte runtime
+backend --> db : "Reads and writes\nJDBC / JPA"
+backend --> secretsManager : "Lee secretos en el arranque\n(inyectados como env vars)"
+backend --> cloudwatch : "Logs stdout/stderr\n(awslogs driver)"
+backend ..> nat : "Salida a internet\n(APIs externas: LLM, STT, SMTP)"
+ecsCluster ..> ecr : "Pull de la imagen\nal iniciar la tarea"
legend bottom right
|= Elemento |= Descripcion |
| Nodo | Infraestructura / entorno de despliegue |
- | Artefacto | Aplicacion o servicio desplegado |
+ | Artefacto | Servicio administrado o desplegado |
| Componente | Modulo de aplicacion (Spring Modulith) |
| Base de datos | Almacenamiento relacional (PostgreSQL) |
- | -> | Comunicacion entre nodos |
+ | -> | Comunicacion de trafico / datos |
+ | ..> | Resolucion DNS / certificado / soporte |
endlegend
@enduml