Skip to content

Arquitectura Backend - Intranet Despertares (Híbrida)

Resumen del Modelo Híbrido

UbicaciónComponentesResponsabilidad
AWS (nube)S3, SES, CognitoAlmacenamiento, correos, autenticación
Servidor (VPS/on‑premise)API + Base de datosLógica de negocio, persistencia

Solo tres servicios en AWS: S3, SES y Cognito. El resto (API y base de datos) corre en un servidor propio. Backend en Java (Spring Boot).


Stack Tecnológico

CapaTecnologíaDónde correPropósito
APISpring Boot 3 + Spring Web (MVC)ServidorREST, controladores, seguridad
LenguajeJava 17+--
ValidaciónBean Validation (Jakarta)ServidorValidación de DTOs
Base de datosPostgreSQLServidorDatos relacionales
ORMSpring Data JPA / HibernateServidorEntidades y repositorios
MigracionesFlywayServidorCambios de schema versionados (desde el inicio)
AutenticaciónAWS CognitoAWSJWT; Spring Security valida el token
StorageAWS S3AWSAWS SDK for Java 2.x, signed URLs
EmailAWS SESAWSAWS SDK for Java 2.x
Compresión imágenesThumbnailator / ImageIOServidorComprimir antes de subir a S3

Requisitos del servidor que alojará el backend

El servidor corre API Java (Spring Boot) y PostgreSQL (mismo equipo o separados). Dimensionado para una intranet escolar (centenares de usuarios, no millones).

Carga esperada (referencia)

MétricaEstimación
Usuarios concurrentes pico50 – 150
Requests/minuto pico200 – 500
Uso más pesadoCompresión de imágenes (Thumbnailator), reportes, envío de correos
Base de datosTablas estándar (usuarios, notas, noticias, pagos); crecimiento moderado

Especificaciones recomendadas

RecursoMínimo (apretado)RecomendadoCómodo
vCPUs124
RAM2 GB4 GB8 GB
Disco40 GB SSD60–80 GB SSD100+ GB SSD
Red100 Mbps100 Mbps1 Gbps
OSUbuntu 22.04 LTSUbuntu 22.04 LTSUbuntu 22.04 LTS

Cómo se usa cada recurso

ComponenteUso aproximado
API Java (Spring Boot)~512 MB – 1.2 GB RAM (JVM); 1–2 vCPUs.
PostgreSQL~512 MB – 1.5 GB RAM según datos y conexiones. 1 vCPU suficiente; disco para datos + WAL + logs.
Sistema + logs~500 MB RAM; 5–10 GB disco para OS, 10–20 GB para logs y backups locales.

Servidor único (API + PostgreSQL en la misma máquina)

  • Recomendado: 2 vCPU, 4 GB RAM, 60–80 GB SSD.
  • Mínimo viable: 1 vCPU, 2 GB RAM, 40 GB SSD (suficiente para empezar; monitorear y escalar si hace falta).

API y base de datos en servidores separados

RolvCPURAMDisco
Servidor API1–22 GB20–40 GB SSD
Servidor PostgreSQL1–22 GB40–60 GB SSD

Requisitos adicionales (software / red)

RequisitoDetalle
SOLinux (Ubuntu 22.04 LTS recomendado).
Runtime APIJava 17+ (OpenJDK).
PostgreSQL15 o 16.
Puertos22 (SSH), 80/443 (API o detrás de Nginx/Caddy), 5432 solo local o VPN si DB en mismo host.
Salida a internetHTTPS para AWS (Cognito, S3, SES) y SUNAT.
Conexión estableNo hace falta ancho de banda alto; estabilidad y baja latencia sí.

Ejemplos de ofertas (referencia de precio)

ProveedorPlan típicoEspecificacionesPrecio aprox./mes
DigitalOceanBasic Droplet2 vCPU, 4 GB RAM, 80 GB SSD~24 USD
HetznerCX222 vCPU, 4 GB RAM, 40 GB SSD~6 EUR
LinodeShared 4GB2 vCPU, 4 GB RAM, 80 GB SSD~24 USD
AWS EC2t3.medium2 vCPU, 4 GB RAM~30 USD + almacenamiento
VultrCloud Compute2 vCPU, 4 GB RAM, 80 GB SSD~24 USD

Para este proyecto, 2 vCPU, 4 GB RAM, 60–80 GB SSD en un VPS es un buen equilibrio coste/rendimiento.


Entornos: dev, staging, prod

Tres entornos bien definidos desde el inicio. Cada uno tiene su perfil Spring, su base de datos (o schema) y su URL pública si aplica.

EntornoPropósitoPerfil SpringBase de datosURL típicaRama / Origen
devDesarrollo local e integracióndevdespertares_dev (local o compartida)http://localhost:8080develop o local
stagingPruebas preproducción, UATstagingdespertares_staging (servidor staging)https://staging.despertares.edu.pestaging o tag
prodUsuarios realesproddespertares (servidor producción)https://despertares.edu.pemain + tag o release

Reglas por entorno

Aspectodevstagingprod
DatosDatos de prueba o seed; se puede borrar/restaurarCopia sanitizada o subset de prod; no datos reales sensiblesDatos reales; solo cambios controlados
LogsNivel DEBUG permitido; stack traces completosINFO; sin volcar datos sensiblesWARN/ERROR; sin PII en logs
Secrets.env local o defaults; nunca commitearVariables de entorno o vaultSolo variables de entorno o vault; rotación documentada
MigracionesFlyway aplica al arrancar; se pueden resetear DBFlyway aplica en deploy; no ejecutar DDL manualFlyway aplica en deploy; cambios solo vía migraciones versionadas
BackupsOpcional (ej. antes de refactors)Diarios; retención 7–14 díasDiarios; retención ≥30 días; pruebas de restore
DeployLocal o CI en cada push a developAutomático desde staging o manual con confirmaciónSolo con aprobación; desde main o tag
Cognito / S3 / SESMismo User Pool de dev o pool separado; buckets/dominios de devPool y buckets de staging (no mezclar con prod)Pool y buckets exclusivos de producción

Variables y configuración

  • dev: SPRING_PROFILES_ACTIVE=dev; DATABASE_URL, DB_USER, DB_PASSWORD (o defaults en application-dev.yml); credenciales AWS de dev si aplica.
  • staging / prod: Todas las config sensibles vía variables de entorno (o secret manager). No dejar URLs de prod en código; usar ${COGNITO_USER_POOL_ID}, ${AWS_S3_BUCKET}, etc., en application-staging.yml y application-prod.yml.

Buenas prácticas (nivel senior)

Criterios que el equipo debe seguir para mantener código mantenible, seguro y desplegable.

Arquitectura y diseño

PrácticaDescripción
Capas clarasController → Service → Repository. Controllers delgados (validación, delegación); lógica de negocio en servicios; acceso a datos en repositorios.
DTOs para APINo exponer entidades JPA directamente. Request/Response DTOs con Bean Validation; mapeo con MapStruct o manual en servicio.
Transacciones explícitas@Transactional en capa de servicio, con ámbito bien definido (readOnly cuando solo lectura).
Manejo de errores centralizado@ControllerAdvice + excepciones de negocio; respuestas HTTP y mensajes consistentes; no filtrar stack traces en prod en respuestas al cliente.
SeguridadSpring Security con JWT de Cognito; roles en el token; @PreAuthorize o filtros por rol; CORS configurado por entorno; sin credenciales en código ni en logs.

Base de datos

PrácticaDescripción
Solo Flyway para schemaSin ddl-auto: create/update en ningún entorno. Todo cambio de tablas/índices vía migraciones versionadas (V1__, V2__, etc.).
Migraciones reversiblesDonde sea posible, migración “down” o script de rollback documentado para cambios destructivos.
Índices y consultasRevisar queries lentas; índices para filtros y FKs usados en búsquedas; evitar N+1 (fetch joins, DTOs con proyecciones).

Código y pruebas

PrácticaDescripción
NomenclaturaNombres claros; paquetes por contexto (auth, backoffice, admin, teacher, parent, student); convenciones de Java/Spring.
TestsUnit tests en servicios (lógica crítica); tests de integración para controllers y repositorios; mocks para AWS y externos en tests.
Sin lógica en controllersControllers solo reciben request, validan (Bean Validation), llaman al servicio y devuelven DTO.
LoggingLogs estructurados si es posible; nivel por perfil (dev/staging/prod); no loguear contraseñas ni tokens.

Operaciones y despliegue

PrácticaDescripción
Health checksEndpoint /actuator/health (y si aplica readiness/liveness) para orquestación y monitoreo.
Config por entornoUn perfil por entorno; secretos fuera del repo; documentar variables necesarias en README o en docs.
Backups antes de cambiosEn staging y prod, backups de BD antes de desplegar migraciones grandes o cambios críticos.
DocumentaciónREADME con cómo levantar dev; documentar migraciones y proceso de backup/restore.

Patrones nivel senior: cache y event bus

PatrónUso en este backendDetalle
Cache (Caffeine)Listado público de noticias aprobadas (GET /public/news)Reduce lecturas a BD en la landing. TTL 5 min; máximo 100 entradas por página. Se invalida al aprobar o rechazar una noticia. Config: CacheConfig, PublicNewsService con @Cacheable.
Event bus (in-process)Desacoplar efectos secundarios del flujo principalSpring ApplicationEventPublisher + @EventListener. Eventos: GradePostedEvent (al registrar/actualizar nota), NewsApprovedEvent (al aprobar noticia). Listeners en DomainEventListeners: hoy solo log; se puede extender a envío de email al padre, auditoría, etc. Sin colas externas (RabbitMQ/Kafka) para mantener el alcance “solo 3 servicios AWS”.
Backup BD → S3No es responsabilidad del backendEl backend no ejecuta pg_dump ni sube a S3. Los scripts backup-db.sh / restore-db.sh generan o consumen archivos locales; la programación (cron) y la subida a S3 se configuran en infraestructura. Ver OPERACION_BACKUP_RESTORE.md.

Migraciones y backups (desde el inicio)

Implementar migraciones versionadas y estrategia de backups desde el primer día; evita deuda técnica y pérdida de datos.

Migraciones con Flyway

  • Herramienta: Flyway (integrado con Spring Boot).
  • Ubicación: src/main/resources/db/migration/.
  • Nomenclatura: V{número}__descripción_corta.sql (ej. V1__create_users_and_roles.sql, V2__add_news_table.sql).
  • Ejecución: Al arrancar la aplicación, Flyway aplica las migraciones pendientes en orden. En todos los entornos (dev, staging, prod) el schema se gestiona solo con Flyway; no usar ddl-auto: create ni update.
  • Buenas prácticas:
    • Migraciones idempotentes cuando sea posible (ej. CREATE TABLE IF NOT EXISTS solo si Flyway no tiene control de checksums y se requiere; en general Flyway controla por versión).
    • No modificar un script ya aplicado; para cambios posteriores, crear una nueva migración (V3, V4, …).
    • En cambios destructivos (DROP COLUMN, DROP TABLE), documentar en el script o en un README el impacto y, si existe, el procedimiento de rollback manual.

Estrategia de backups (desde el inicio)

EntornoFrecuenciaRetenciónDestinoNotas
devBajo demanda (antes de refactors)Según necesidadLocal o carpeta compartidaOpcional.
stagingDiario (cron)7–14 díasServidor o almacenamiento externo (S3, NFS)Permite restaurar staging para reproducir fallos.
prodDiario (cron) + pre-deploy si hay migracionesMínimo 30 díasAlmacenamiento externo (S3, otro servidor)Crítico; cifrado y permisos restringidos.

Contenido del backup

  • Base de datos PostgreSQL: pg_dump (formato custom -Fc para restores selectivos, o SQL plano para inspección).
  • No incluir en el backup de BD: archivos subidos a S3 (S3 tiene su propia versión y políticas); solo la BD.

Comandos de referencia (backup/restore)

Backup (ejemplo):

bash
# Backup completo, formato custom (recomendado para restore)
pg_dump -h localhost -U postgres -Fc -f despertares_$(date +%Y%m%d_%H%M%S).dump despertares

# Subir a S3 o copiar a servidor de backups
aws s3 cp despertares_*.dump s3://bucket-backups/despertares/

Restore (solo cuando sea necesario, con precaución):

bash
# Detener la aplicación que usa la BD
pg_restore -h localhost -U postgres -d despertares_restore --clean --if-exists despertares_YYYYMMDD.dump
# Revisar integridad antes de apuntar la aplicación a la BD restaurada

Automatización y documentación

  • Scripts: Incluir en el repo (ej. infra/scripts/backup-db.sh, restore-db.sh) con instrucciones en el README o en esta doc.
  • Cron (staging/prod): Ejemplo diario a las 02:00: 0 2 * * * /ruta/backup-db.sh.
  • Pruebas de restore: Al menos una vez por trimestre en staging (o tras cambios importantes), restaurar un backup y validar que la aplicación arranca y los datos son coherentes.
  • Migraciones + backups: Antes de desplegar una migración que borre columnas o tablas, hacer backup explícito de prod y documentar el punto de restauración.

Con esto, migraciones y backups quedan definidos desde el inicio y listos para aplicar en dev, staging y prod.


Arquitectura General

┌─────────────────────────────────────────────────────────────────────────┐
│                              CLIENTES                                    │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │   Landing    │  │  Backoffice  │  │   Intranet   │  │   Intranet   │ │
│  │   (Public)   │  │   (Admin)    │  │   (Padres)   │  │  (Profesores)│ │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘ │
└─────────┼─────────────────┼─────────────────┼─────────────────┼─────────┘
          │                 │                 │                 │
          ▼                 ▼                 ▼                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                    Servidor (VPS / On‑premise / EC2)                      │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                     API Java (Spring Boot)                            │ │
│  │  • REST /api/*   • Spring Security (JWT Cognito)   • Lógica negocio   │ │
│  │  • Compresión imágenes (Thumbnailator) antes de subir a S3           │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                     PostgreSQL                                        │ │
│  │  • Usuarios, alumnos, profesores, notas, noticias, pagos, etc.        │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
          │                         │                         │
          │                         │                         │
          ▼                         ▼                         ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   AWS Cognito   │    │      AWS S3     │    │     AWS SES     │
│   (Auth)        │    │   (Archivos)    │    │   (Correos)     │
│                 │    │                 │    │                 │
│ • User Pool     │    │ • Bucket        │    │ • Envío         │
│ • Login alias   │    │   privado       │    │   transaccional │
│ • JWT           │    │ • Signed URLs   │    │ • @despertares   │
│ • Triggers      │    │ • Compresión   │    │   .edu.pe        │
│                 │    │   en servidor   │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Qué va en AWS (solo 3 servicios)

1. Cognito

  • User Pool con login por alias (preferred_username).
  • Grupos: ADMIN, EDITOR, TEACHER, PARENT, STUDENT.
  • Triggers opcionales: PreSignUp, PostConfirmation, PreTokenGeneration (para sincronizar con PostgreSQL si se desea).
  • La API en el servidor solo verifica el JWT con el public key de Cognito; no aloja usuarios.

2. S3

  • Un bucket privado para archivos e imágenes.
  • Acceso desde la API vía SDK (IAM o access key del servidor).
  • El frontend recibe signed URLs generadas por la API (no acceso directo al bucket).
  • Compresión de imágenes hecha en el servidor (Thumbnailator/ImageIO) antes de PutObject.

3. SES

  • Dominio verificado @despertares.edu.pe.
  • Envío de correos transaccionales (notificaciones, recuperación de contraseña, etc.).
  • La API usa el SDK de SES desde el servidor con credenciales IAM o SMTP.

Qué va en el servidor

API (Java + Spring Boot)

  • Una sola aplicación Spring Boot que sirve todas las rutas /api/*.
  • Spring Security: validar JWT de Cognito (Resource Server o filtro con public key).
  • Controladores organizados por contexto: auth, backoffice, admin, teacher, parent, student.
  • Subida de archivos: MultipartFile → comprimir con Thumbnailator/ImageIO → subir a S3 → guardar referencia en PostgreSQL.
  • Configuración por perfiles (application-dev.yml, application-staging.yml, application-prod.yml) para cada entorno.

Base de datos (PostgreSQL)

  • Entidades de negocio: usuarios (vinculados a cognito_id), estudiantes, profesores, padres, cursos, clases, notas, asistencia, noticias, pagos, archivos, notificaciones, etc.
  • Migraciones con Flyway desde el primer día (ver sección Migraciones y backups).
  • Servidor: VPS, EC2 u on‑premise.

Estructura de Carpetas (Backend Java - Buenas prácticas)

Estructura tipo capas y paquetes por dominio/contexto, alineada con prácticas senior (separación de responsabilidades, testabilidad).

despertares-intranet/

├── backend/                         # API Java (Spring Boot)
│   ├── pom.xml                      # o build.gradle.kts
│   ├── Dockerfile
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/pe/edu/despertares/intranet/
│   │   │   │   ├── IntranetApplication.java
│   │   │   │   │
│   │   │   │   ├── config/              # Configuración (Security, S3, SES, CORS)
│   │   │   │   ├── security/            # JWT Cognito, filtros, roles
│   │   │   │   ├── common/               # Excepciones globales, DTOs base, constantes
│   │   │   │   │
│   │   │   │   ├── auth/                # Contexto: autenticación
│   │   │   │   │   ├── controller/
│   │   │   │   │   ├── service/
│   │   │   │   │   ├── repository/
│   │   │   │   │   └── domain/
│   │   │   │   ├── backoffice/
│   │   │   │   ├── admin/
│   │   │   │   ├── teacher/
│   │   │   │   ├── parent/
│   │   │   │   └── student/
│   │   │   │
│   │   │   └── resources/
│   │   │       ├── application.yml
│   │   │       ├── application-dev.yml
│   │   │       ├── application-staging.yml
│   │   │       ├── application-prod.yml
│   │   │       └── db/migration/        # Flyway (V1__...sql, V2__...sql)
│   │   └── test/
│   │       └── java/...                  # Tests unitarios e integración
│   │
│   ├── infra/                       # IaC AWS (Terraform o SST)
│   │   ├── terraform/
│   │   │   ├── main.tf
│   │   │   ├── cognito.tf
│   │   │   ├── s3.tf
│   │   │   └── ses.tf
│   │   └── scripts/
│   │       ├── backup-db.sh
│   │       └── restore-db.sh
│   │
│   └── web/                         # Frontend React (si monorepo)
│       └── ...

└── docs/
    ├── COBERTURA_INTRANET_LMS.md
    ├── ARQUITECTURA_BACKEND.md
    └── GUIA_DESPLIEGUE.md
  • Perfiles Spring: spring.profiles.active=dev|staging|prod según entorno.
  • Flyway: scripts en src/main/resources/db/migration/; se ejecutan al arrancar la aplicación.
  • Tests: mismo paquete que el código (*Test, *IT para integración).

Flujos Principales

Autenticación (Cognito + API): cómo está el login ahora

Hay dos formas de que el usuario obtenga un JWT; la que tienes configurada (Managed login + dominio propio) es la opción 1.


Opción 1: Managed login (Hosted UI) — la que tienes ahora

El login ocurre en la pantalla de Cognito en https://auth.despertares.edu.pe. El frontend nunca ve la contraseña; solo redirige al usuario y luego recibe un código (o tokens) por redirect.

Flujo paso a paso:

  1. Usuario hace clic en “Iniciar sesión” en tu app (ej. https://app.despertares.edu.pe o http://localhost:5173).
  2. El frontend redirige al navegador a la URL de autorización de Cognito, por ejemplo:
    https://auth.despertares.edu.pe/oauth2/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=https://app.despertares.edu.pe/login/callback&scope=openid+email+profile&state=<random>
    • redirect_uri debe ser exactamente una de las Callback URL(s) del App client (por eso las configuramos en el Paso 1).
  3. El usuario ve la pantalla de Cognito (Managed login) en auth.despertares.edu.pe: introduce alias y contraseña. Solo se permiten correos @despertares.edu.pe (Pre-sign-up Lambda).
  4. Cognito valida y redirige de vuelta a tu app a la callback URL con un código en la query, por ejemplo:
    https://app.despertares.edu.pe/login/callback?code=abc123...&state=...
  5. El frontend (en la ruta /login/callback) lee el code y lo intercambia por tokens llamando al token endpoint de Cognito (desde el frontend o desde tu backend):
    POST https://auth.despertares.edu.pe/oauth2/token
    Content-Type: application/x-www-form-urlencoded
    grant_type=authorization_code&code=abc123...&client_id=<CLIENT_ID>&redirect_uri=https://app.despertares.edu.pe/login/callback
    Cognito devuelve access_token, id_token, refresh_token y expires_in.
  6. El frontend guarda los tokens (memoria, sessionStorage o cookie segura) y ya considera al usuario “logueado”.
  7. En cada petición a tu API, el frontend envía:
    Authorization: Bearer <access_token>
  8. La API (Spring Boot) no hace login: solo valida el JWT con la clave pública de Cognito (JWK Set de auth.despertares.edu.pe o del User Pool), lee sub, custom:userId, custom:role (si los tienes) y autoriza el request.

Resumen lógico:

  • Login = redirigir a Cognito → usuario pone alias/contraseña en Cognito → redirect a tu callback con code → frontend cambia code por tokens.
  • API = recibe Authorization: Bearer <token>, valida JWT y usa los claims para saber quién es el usuario y su rol.

Opción 2: Login “directo” (formulario en tu app)

El usuario escribe alias y contraseña en tu propia página; el frontend (o el backend) llama a Cognito con InitiateAuth (flujo USER_PASSWORD_AUTH) y recibe los tokens. La contraseña pasa por tu frontend (o por tu backend si el login lo hace la API). No hay redirect a auth.despertares.edu.pe.

  • Si lo hace el frontend: usa el SDK de Cognito (ej. amazon-cognito-identity-js o Amplify Auth) con signIn(alias, password).
  • Si lo hace el backend: el frontend envía alias + contraseña a POST /api/auth/login; la API llama a Cognito InitiateAuth y devuelve los tokens al frontend.

En ambos casos, la API sigue igual: solo valida el JWT en las peticiones protegidas; no hace el “login” por el usuario.


Qué tienes configurado (resumen)

ElementoEstado
Dominio de loginhttps://auth.despertares.edu.pe (Managed login)
Quién pide alias/contraseñaCognito (pantalla de Managed login)
Callback tras loginRedirect a la URL que pusiste en “Callback URL(s)” (ej. .../login/callback) con ?code=...
Restricción de correoSolo @despertares.edu.pe (Pre-sign-up)
Rol de la APISolo validar JWT; no aloja la pantalla de login ni hace InitiateAuth (salvo que añadas opción 2)

Subida de archivos (S3)

  1. El cliente envía el archivo a la API (multipart).
  2. La API comprime con Thumbnailator/ImageIO y sube a S3 con AWS SDK.
  3. La API guarda en PostgreSQL la clave del objeto (ej. uploads/2025/xxx.jpg).
  4. Para descargar, el cliente pide a la API una signed URL; la API la genera con S3 Presigner y la devuelve.

Envío de correos (SES)

  1. La API usa AWS SES (SDK) desde el servidor con credenciales configuradas (env o IAM).
  2. Dominio verificado @despertares.edu.pe.
  3. Uso: notificaciones, recuperación de contraseña (si se hace vía API), citaciones, etc.

Seguridad y datos sensibles (cumplimiento de estándares)

La intranet maneja datos sensibles (notas, asistencia, datos de menores, pagos). A continuación se resume cómo el diseño actual cumple con prácticas de seguridad habituales y qué se recomienda reforzar en producción.

Lo que ya cumple el diseño actual

ÁreaPráctica / estándarCómo se cumple en este proyecto
TransporteCifrado en tránsito (TLS)Login en HTTPS (auth.despertares.edu.pe con certificado ACM). API y frontend en HTTPS en staging y producción. Comunicación con AWS (Cognito, S3, SES) por HTTPS.
AutenticaciónContraseñas no expuestas en la appCon Managed login, la contraseña solo se introduce en la página de Cognito; el frontend nunca la recibe. La API no procesa contraseñas; solo valida JWT.
ContraseñasPolítica robustaCognito: mínimo 8 caracteres, mayúscula, minúscula y número. Recuperación por email verificado.
Acceso restringidoSolo usuarios del dominioPre-sign-up Lambda: solo se permite registro con correo @despertares.edu.pe.
AutorizaciónRoles y permisosGrupos Cognito (ADMIN, EDITOR, TEACHER, PARENT, STUDENT). API valida JWT y aplica control por rol (@PreAuthorize o filtros).
SecretsNo en código ni en repoContraseñas de BD, credenciales AWS y tokens se inyectan por variables de entorno (o vault). No commitear .env ni archivos con secretos. Terraform: no credenciales en .tf ni en .tfvars commitados.
Almacenamiento (S3)Cifrado y acceso privadoBucket privado, Block Public Access activado, encriptación SSE-S3 en reposo. Acceso solo vía API (IAM/signed URLs).
LogsNo registrar datos sensiblesEn prod: nivel WARN/ERROR; no loguear contraseñas, tokens ni PII. En staging: INFO sin volcar datos sensibles.
CORSOrigen controladoCORS configurado por entorno; solo orígenes permitidos (app.despertares.edu.pe, sin wildcard abierto en prod).
Callbacks OAuthURLs explícitasCallback y sign-out URLs registradas en el App client; en producción usar solo URLs HTTPS de tu dominio (no localhost).

Recomendaciones adicionales para producción (datos sensibles)

RecomendaciónAcción
PKCE en el flujo OAuthUsar PKCE (code_verifier / code_challenge) en el flujo authorization code desde el frontend (SPA). Cognito lo soporta; reduce el riesgo si el código de autorización fuera interceptado.
Almacenamiento de tokens en el frontendPreferir cookies HttpOnly, Secure, SameSite (o un proxy en el backend que guarde el token en cookie) para access/refresh en lugar de localStorage, para mitigar XSS. Si se usan tokens en memoria/sessionStorage, limitar superficie de XSS (CSP, sanitización).
MFA (opcional)Para roles con acceso muy sensible (ej. ADMIN), valorar MFA en Cognito (TOTP o SMS) como capa adicional.
Callbacks en producciónEn prod, en el App client de Cognito no incluir http://localhost en Callback URL(s). Solo URLs HTTPS de tu dominio (ej. https://app.despertares.edu.pe/login/callback).
Rate limitingEn la API, aplicar límite de peticiones por IP o por usuario (ej. filtro o gateway) para mitigar abuso y fuerza bruta en endpoints sensibles.
Base de datosCifrado en reposo del volumen donde corre PostgreSQL (muchos proveedores VPS/cloud lo ofrecen). Backups cifrados y acceso restringido.
Headers de seguridadEn la API y en el frontend: HSTS, X-Content-Type-Options, Content-Security-Policy (CSP) según lo que permita tu stack.

Resumen de confirmación

  • , el diseño actual está alineado con estándares de seguridad habituales para una intranet con datos sensibles: transporte cifrado, autenticación delegada en Cognito sin manejo de contraseñas en la API, autorización por roles, secretos fuera del código, almacenamiento S3 cifrado y privado, y logs sin datos sensibles.
  • Para endurecer en producción, aplicar las recomendaciones de la tabla anterior (PKCE, almacenamiento seguro de tokens, callbacks solo HTTPS en prod, rate limiting, cifrado de BD y backups, headers de seguridad).

Orden de Desarrollo (Backend Java)

Fase 1: Fundamentos (Semana 1–2)

#TareaDóndeTiempo
1.1Proyecto Spring Boot 3 + perfiles (dev/staging/prod)backend2h
1.2PostgreSQL + Flyway: primera migración (V1__init.sql)backend3h
1.3Cognito en AWS (User Pool, alias, grupos)infra4h
1.4Spring Security + validación JWT Cognitobackend4h
1.5Controladores auth (login/refresh vía Cognito, logout)backend4h
1.6Entidad User + sincronización con Cognito (opcional)backend + migración3h

Fase 2: Storage y Email (Semana 2–3)

#TareaDóndeTiempo
2.1S3 bucket privado en AWSinfra1h
2.2Cliente S3 en API + signed URLsbackend3h
2.3Subida de archivos + compresión (Thumbnailator)backend4h
2.4SES dominio + envío desde APIinfra + backend3h

Fase 3: Backoffice y Admin (Semana 3–4)

#TareaDóndeTiempo
3.1CRUD noticias, aprobaciones (migraciones Flyway)backend6h
3.2Notificaciones y gestión de imágenesbackend4h
3.3Panel admin: usuarios, pagos, horariosbackend8h
3.4Integración SUNAT (si aplica)backend8h

Fase 4: Portales (Semana 4–6)

#TareaDóndeTiempo
4.1Rutas profesor (clases, notas, asistencia, archivos)backend12h
4.2Rutas padre (hijos, notas, calendario, agenda)backend8h
4.3Rutas estudiante (notas, tareas, archivos, Corefo iframe)backend6h

Infraestructura AWS (solo S3, SES, Cognito)

Repositorio: La IaC puede vivir en un repositorio separado (ej. despertares-intranet-infra) para aislar state, permisos y ciclos de vida. Ver docs/GUIA_DESPLIEGUE.md para despliegue en AWS y servidor.

Opción A: Terraform

  • Ventaja: Un solo lenguaje de IaC si ya lo usan para el servidor o redes.
  • Alcance: Tres módulos: cognito.tf, s3.tf, ses.tf. Sin Lambda, sin API Gateway, sin DynamoDB.

Opción B: SST (solo recursos AWS)

  • Ventaja: Rápido para solo 3 servicios (Cognito, S3, SES).
  • Alcance: Un único sst.config.ts que declare User Pool, bucket S3 y configuración SES (verificación de dominio suele hacerse manual o con un recurso Route53 si el DNS está en AWS).

Configuración por entorno (Spring profiles)

Cada entorno usa su perfil y su propio archivo de propiedades. No commitear secretos; usar variables de entorno o un vault en prod.

application.yml (común):

yaml
spring:
  application:
    name: despertares-intranet-api
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}
  flyway:
    enabled: true
  jpa:
    hibernate:
      ddl-auto: validate   # Nunca create/update; solo Flyway

application-dev.yml (desarrollo local):

yaml
server:
  port: 8080
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/despertares_dev
    username: ${DB_USER:postgres}
    password: ${DB_PASSWORD:postgres}
logging:
  level:
    pe.edu.despertares: DEBUG
    org.hibernate.SQL: DEBUG

application-staging.yml (staging):

yaml
spring:
  datasource:
    url: ${DATABASE_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}
logging:
  level:
    pe.edu.despertares: INFO

application-prod.yml (producción):

yaml
spring:
  datasource:
    url: ${DATABASE_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}
logging:
  level:
    pe.edu.despertares: WARN
    root: WARN

Variables por entorno (Cognito, S3, SES, DB) se inyectan vía env (ej. COGNITO_USER_POOL_ID, AWS_S3_BUCKET, AWS_REGION) y se referencian en los application-*.yml con ${VAR}.


Costos Estimados (Híbrido)

AWS (solo 3 servicios)

ServicioUsoCosto/mes
Cognito< 50K MAU$0
S3~20 GB + requests~$1–2
SES~10K correos~$1
Total AWS~$2–3

Servidor (VPS / EC2)

  • VPS 2 vCPU, 4 GB RAM: ~$20–40/mes (según proveedor).
  • PostgreSQL: incluido en el mismo servidor o RDS si más adelante lo pasan a AWS.

Total estimado: ~$25–45/mes (AWS + servidor), dependiendo del proveedor del servidor.


Resumen del Plan Backend

TemaDecisión
En la nube (AWS)Solo S3, SES y Cognito.
En servidorAPI Java (Spring Boot) y PostgreSQL.
AuthCognito (login por alias); API verifica JWT con Spring Security.
ArchivosS3 privado; compresión en servidor (Thumbnailator); acceso por signed URLs.
CorreosSES desde la API.
Base de datosPostgreSQL; Flyway para migraciones desde el inicio.
Entornosdev, staging, prod con perfiles Spring y config específica.
BackupsEstrategia definida desde el inicio (ver sección Migraciones y backups).
IaC AWSTerraform o SST solo para Cognito, S3 y SES.