59bd2d2d8a
- Añade servicios y configuración Cognito para login web (admins) y API (scanners) - Soporta Floci cuando AWS_ENDPOINT_URL está definido; AWS real en caso contrario - Incluye bootstrap Floci, docker-compose.local.yml y carga automática en run-local.sh - Documenta arquitectura, flujos y arranque manual/IntelliJ en README - Actualiza gitignore: excluye Flutter, H2 local y artefactos generados
728 lines
22 KiB
Markdown
728 lines
22 KiB
Markdown
# Base Admin Web
|
||
|
||
Proyecto base de Spring Boot con Metronic, autenticación Cognito (o local), panel administrativo y API de escaneo para la app móvil Flutter.
|
||
|
||
Sirve como plantilla reutilizable para nuevos paneles internos: estructura modular, seguridad dual (web + API), módulo de códigos pase con QR y soporte H2/PostgreSQL.
|
||
|
||
---
|
||
|
||
## Tabla de contenidos
|
||
|
||
- [Vista general](#vista-general)
|
||
- [Stack](#stack)
|
||
- [Arquitectura del sistema](#arquitectura-del-sistema)
|
||
- [Módulos Maven](#módulos-maven)
|
||
- [Seguridad y autenticación](#seguridad-y-autenticación)
|
||
- [Cognito: local (Floci) vs AWS](#cognito-local-floci-vs-aws)
|
||
- [Módulo de códigos pase](#módulo-de-códigos-pase)
|
||
- [API REST](#api-rest)
|
||
- [App Flutter (escáner)](#app-flutter-escáner)
|
||
- [Arranque local](#arranque-local)
|
||
- [Arranque manual e IntelliJ IDEA](#arranque-manual-e-intellij-idea)
|
||
- [Perfiles Spring](#perfiles-spring)
|
||
- [Variables de entorno](#variables-de-entorno)
|
||
- [Objetivo de esta base](#objetivo-de-esta-base)
|
||
|
||
---
|
||
|
||
## Vista general
|
||
|
||
El sistema tiene **dos canales de acceso** con roles distintos:
|
||
|
||
| Canal | Usuario | Rol | Autenticación |
|
||
|-------|---------|-----|---------------|
|
||
| Panel web (Thymeleaf) | `admin` | `ROLE_ADMIN` | Sesión HTTP (form login) |
|
||
| API móvil / externa | `scanner` | `ROLE_SCANNER` | JWT Bearer (stateless) |
|
||
|
||
Por defecto ambos canales usan **Amazon Cognito** (emulado en local con Floci). Con `APP_COGNITO_ENABLED=false` se usa autenticación local contra la base de datos y JWT firmado con secreto propio.
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph clients["Clientes"]
|
||
Browser["Navegador<br/>Panel admin"]
|
||
Flutter["App Flutter<br/>QR Scanner"]
|
||
end
|
||
|
||
subgraph app["Spring Boot — base-admin-web-jar"]
|
||
WebChain["Filter chain web<br/>sesión + CSRF"]
|
||
ApiChain["Filter chain API<br/>stateless + JWT"]
|
||
PassCodes["PassCodeService"]
|
||
DB[("H2 / PostgreSQL")]
|
||
end
|
||
|
||
subgraph auth["Autenticación"]
|
||
Cognito["Cognito<br/>Floci local o AWS"]
|
||
LocalAuth["BD local + JWT HS256<br/>APP_COGNITO_ENABLED=false"]
|
||
end
|
||
|
||
Browser -->|"/login, /admin/**"| WebChain
|
||
Flutter -->|"/api/auth/login<br/>/api/pass-codes/scan"| ApiChain
|
||
WebChain --> PassCodes
|
||
ApiChain --> PassCodes
|
||
PassCodes --> DB
|
||
WebChain --> Cognito
|
||
ApiChain --> Cognito
|
||
WebChain -.-> LocalAuth
|
||
ApiChain -.-> LocalAuth
|
||
```
|
||
|
||
**URLs locales:**
|
||
|
||
| Recurso | URL |
|
||
|---------|-----|
|
||
| Login | http://localhost:8080/login |
|
||
| Dashboard | http://localhost:8080/dashboard |
|
||
| Códigos pase | http://localhost:8080/admin/pass-codes |
|
||
| H2 Console | http://localhost:8080/h2-console |
|
||
| Floci (Cognito local) | http://localhost:4566 |
|
||
|
||
---
|
||
|
||
## Stack
|
||
|
||
| Capa | Tecnología |
|
||
|------|------------|
|
||
| Backend | Spring Boot 4.0.6, Java 25 |
|
||
| Seguridad | Spring Security, OAuth2 Resource Server, AWS SDK Cognito |
|
||
| Vistas | Thymeleaf + Metronic (`base-web`) |
|
||
| Persistencia | JPA / Hibernate, H2 (dev), PostgreSQL (perfil `postgres`) |
|
||
| Auth | Cognito (default) o BD local + JWT HS256 |
|
||
| Móvil | Flutter (`flutter-app/qrscanner`) |
|
||
| Local AWS | [Floci](https://floci.io/floci/getting-started/quick-start/) (Cognito en puerto 4566) |
|
||
|
||
---
|
||
|
||
## Arquitectura del sistema
|
||
|
||
### Capas y dependencias
|
||
|
||
```mermaid
|
||
flowchart BT
|
||
jar["base-admin-web-jar<br/>punto de entrada + application.yml"]
|
||
web["base-admin-web-web<br/>controladores + Thymeleaf"]
|
||
config["base-admin-web-configuration<br/>seguridad, JWT, Cognito"]
|
||
app["base-admin-web-application<br/>servicios + carga inicial"]
|
||
domain["base-admin-web-domain<br/>entidades + repositorios"]
|
||
|
||
jar --> web
|
||
jar --> config
|
||
jar --> app
|
||
jar --> domain
|
||
web --> config
|
||
web --> app
|
||
config --> app
|
||
app --> domain
|
||
```
|
||
|
||
| Módulo | Responsabilidad |
|
||
|--------|-----------------|
|
||
| `base-admin-web-domain` | Entidades JPA (`AppUser`, `PassCode`, `Role`), repositorios |
|
||
| `base-admin-web-application` | `PassCodeService`, `AppUserDetailsService`, `InitialDataLoader` |
|
||
| `base-admin-web-configuration` | `SecurityConfig`, `ApiSecurityConfig`, Cognito, `JwtConfig` |
|
||
| `base-admin-web-web` | Controladores MVC y API, DTOs, plantillas HTML |
|
||
| `base-admin-web-jar` | `BaseAdminWebApplication`, perfiles, dependencias runtime (H2, PostgreSQL) |
|
||
|
||
### Dos cadenas de seguridad
|
||
|
||
Spring Security define **dos filter chains** con distinto comportamiento:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph order1["@Order(1) — ApiSecurityConfig"]
|
||
A1["/api/**"]
|
||
A2["Stateless"]
|
||
A3["JWT Bearer"]
|
||
A4["ROLE_SCANNER en /scan"]
|
||
end
|
||
|
||
subgraph order2["@Order(2) — SecurityConfig"]
|
||
B1["Todo excepto /api/**"]
|
||
B2["Sesión HTTP"]
|
||
B3["Form login /login"]
|
||
B4["ROLE_ADMIN en /admin/**"]
|
||
end
|
||
|
||
A1 --> A2 --> A3 --> A4
|
||
B1 --> B2 --> B3 --> B4
|
||
```
|
||
|
||
| Ruta | Acceso | Mecanismo |
|
||
|------|--------|-----------|
|
||
| `/login`, `/assets/**`, `/error`, `/h2-console/**` | Público | — |
|
||
| `/dashboard`, `/admin/**` | `ROLE_ADMIN` | Sesión web |
|
||
| `/api/auth/login`, `/api/auth/refresh` | Público | Emite tokens (solo `scanner`) |
|
||
| `/api/pass-codes/scan` | `ROLE_SCANNER` | JWT Bearer |
|
||
|
||
---
|
||
|
||
## Seguridad y autenticación
|
||
|
||
### Usuarios iniciales
|
||
|
||
#### Administrador (panel web)
|
||
|
||
- Usuario: `admin` / `Admin123*`
|
||
- Grupo Cognito: `admins` → `ROLE_ADMIN`
|
||
- Acceso: login en `/login`, dashboard, módulo de códigos pase
|
||
- El usuario `scanner` **no** puede entrar al panel web
|
||
|
||
#### Escáner (API / Flutter)
|
||
|
||
- Usuario: `scanner` / `Scanner123*`
|
||
- Grupo Cognito: `scanners` → `ROLE_SCANNER`
|
||
- Acceso: `POST /api/auth/login` y `POST /api/pass-codes/scan`
|
||
- El usuario `admin` **no** puede autenticarse por API
|
||
|
||
### Flujo de login web (panel admin)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
actor Admin as Navegador (admin)
|
||
participant SC as SecurityConfig
|
||
participant CP as CognitoWebAuthenticationProvider
|
||
participant CA as CognitoUserAuthenticator
|
||
participant Cognito as Cognito (Floci/AWS)
|
||
|
||
Admin->>SC: POST /login (user, password)
|
||
SC->>CP: authenticate()
|
||
CP->>CA: admin client + ROLE_ADMIN
|
||
CA->>Cognito: InitiateAuth USER_PASSWORD_AUTH
|
||
Cognito-->>CA: tokens + cognito:groups
|
||
CA-->>CP: AuthenticatedWebUser (grupo admins)
|
||
CP-->>SC: sesión HTTP creada
|
||
SC-->>Admin: redirect /dashboard
|
||
```
|
||
|
||
**Clases clave:** `SecurityConfig`, `CognitoWebSecurityConfig`, `CognitoWebAuthenticationProvider`, `CognitoUserAuthenticator`, `AuthController`
|
||
|
||
Con `APP_COGNITO_ENABLED=false`, el flujo usa `DaoAuthenticationProvider` → `AppUserDetailsService` → tabla `users` (BCrypt).
|
||
|
||
### Flujo de login y escaneo API
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
actor App as Flutter (scanner)
|
||
participant API as AuthApiController
|
||
participant AS as ApiAuthService
|
||
participant Cognito as Cognito
|
||
participant Scan as PassCodeApiController
|
||
participant Svc as PassCodeService
|
||
|
||
App->>API: POST /api/auth/login
|
||
API->>AS: login()
|
||
AS->>Cognito: scanner client + ROLE_SCANNER
|
||
Cognito-->>App: accessToken, refreshToken, idToken
|
||
|
||
App->>Scan: POST /api/pass-codes/scan<br/>Authorization: Bearer ...
|
||
Scan->>Scan: validar JWT (JWK o HS256)
|
||
Scan->>Svc: scan(code)
|
||
Svc-->>App: código marcado UTILIZADO
|
||
```
|
||
|
||
**Clases clave:** `ApiSecurityConfig`, `AuthApiController`, `ApiAuthService`, `CognitoAuthService`, `PassCodeApiController`, `JwtConfig`
|
||
|
||
### Modo local sin Cognito
|
||
|
||
Con `APP_COGNITO_ENABLED=false` (perfil `test` lo usa automáticamente):
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph web["Web"]
|
||
W1["Form login"] --> W2["AppUser en BD"]
|
||
end
|
||
subgraph api["API"]
|
||
A1["POST /api/auth/login"] --> A2["BD + JwtEncoder HS256"]
|
||
A3["POST /api/auth/refresh"] --> A4["No disponible"]
|
||
A5["Bearer token"] --> A6["localJwtDecoder HS256"]
|
||
end
|
||
```
|
||
|
||
| `APP_COGNITO_ENABLED` | Web | API login | Validación JWT | Refresh |
|
||
|----------------------|-----|-----------|----------------|---------|
|
||
| `true` (default) | Cognito client admin | Cognito client scanner | JWK Set URI | Sí |
|
||
| `false` | BD + BCrypt | BD + JWT local | Secreto HS256 | No |
|
||
|
||
Los usuarios se siembran con `InitialDataLoader` usando `APP_ADMIN_*` y `APP_SCANNER_*`.
|
||
|
||
---
|
||
|
||
## Cognito: local (Floci) vs AWS
|
||
|
||
El SDK de Cognito elige el destino según `AWS_ENDPOINT_URL`:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start["APP_COGNITO_ENABLED=true"]
|
||
Check{"¿AWS_ENDPOINT_URL<br/>definido?"}
|
||
Floci["Floci localhost:4566<br/>credenciales test/test"]
|
||
AWS["Cognito real en AWS<br/>DefaultCredentialsProvider<br/>IAM / perfil / env AWS"]
|
||
|
||
Start --> Check
|
||
Check -->|Sí| Floci
|
||
Check -->|No| AWS
|
||
```
|
||
|
||
### Local con Floci
|
||
|
||
`./run-local.sh` hace todo el setup:
|
||
|
||
1. Levanta Floci (y PostgreSQL si el perfil lo incluye)
|
||
2. Espera el bootstrap de Cognito (hasta 120 s)
|
||
3. Carga `docker/floci/generated/cognito.local.env` automáticamente
|
||
|
||
El script `docker/floci/init/ready.d/10-cognito-bootstrap.sh` crea:
|
||
|
||
| Recurso | Valor |
|
||
|---------|-------|
|
||
| User Pool ID | `us-east-1_BaseAdminWeb` |
|
||
| Usuario admin | `admin` / `Admin123*` → grupo `admins` |
|
||
| Usuario scanner | `scanner` / `Scanner123*` → grupo `scanners` |
|
||
| App client admin | `base-admin-web-admin` |
|
||
| App client scanner | `base-admin-web-scanner` |
|
||
|
||
Variables generadas en `docker/floci/generated/cognito.local.env` (gitignored).
|
||
|
||
**Levantar solo Floci:**
|
||
|
||
```bash
|
||
./scripts/floci-up.sh
|
||
```
|
||
|
||
**Levantar stack Docker completo:**
|
||
|
||
```bash
|
||
docker compose -f docker-compose.local.yml up -d
|
||
```
|
||
|
||
| Servicio | Puerto | Persistencia |
|
||
|----------|--------|--------------|
|
||
| Floci | 4566 | volumen `base_admin_web_floci_data` |
|
||
| PostgreSQL | 5432 | volumen `base_admin_web_postgres_data` |
|
||
|
||
### Producción con AWS Cognito
|
||
|
||
**No definir** `AWS_ENDPOINT_URL`. Configura el User Pool real:
|
||
|
||
```bash
|
||
export APP_COGNITO_ENABLED=true
|
||
export COGNITO_REGION=us-east-1
|
||
export COGNITO_USER_POOL_ID=us-east-1_XXXXX
|
||
export COGNITO_ISSUER_URI=https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX
|
||
export COGNITO_JWK_SET_URI=https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX/.well-known/jwks.json
|
||
export COGNITO_ADMIN_CLIENT_ID=...
|
||
export COGNITO_SCANNER_CLIENT_ID=...
|
||
# Credenciales AWS vía IAM role, perfil o AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
|
||
```
|
||
|
||
En AWS replica la misma estructura que Floci: grupos `admins`/`scanners`, clients con `USER_PASSWORD_AUTH` habilitado.
|
||
|
||
### Verificar Cognito local
|
||
|
||
```bash
|
||
export AWS_ENDPOINT_URL=http://localhost:4566
|
||
export AWS_DEFAULT_REGION=us-east-1
|
||
export AWS_ACCESS_KEY_ID=test
|
||
export AWS_SECRET_ACCESS_KEY=test
|
||
|
||
aws cognito-idp list-user-pools --max-results 10 --endpoint-url $AWS_ENDPOINT_URL
|
||
aws cognito-idp list-users --user-pool-id us-east-1_BaseAdminWeb --endpoint-url $AWS_ENDPOINT_URL
|
||
```
|
||
|
||
---
|
||
|
||
## Módulo de códigos pase
|
||
|
||
Panel para dar de alta y consultar códigos pase con QR.
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> ACTIVO: admin crea código (10 chars)
|
||
ACTIVO --> UTILIZADO: scanner escanea QR
|
||
```
|
||
|
||
| Campo | Descripción |
|
||
|-------|-------------|
|
||
| Nombre | Etiqueta descriptiva |
|
||
| Código | Aleatorio de 10 caracteres (único) |
|
||
| Estatus | `ACTIVO` / `UTILIZADO` |
|
||
| Escaneado | Indicador booleano |
|
||
| Fechas | Creación y escaneo |
|
||
|
||
**Panel web:** `GET /admin/pass-codes` — tabla Metronic, modal QR, refresco automático al cerrar el modal.
|
||
|
||
**Entidad:** `PassCode` → **Servicio:** `PassCodeService` → **Controladores:** `PassCodeController` (web), `PassCodeApiController` (API).
|
||
|
||
---
|
||
|
||
## API REST
|
||
|
||
### Login escáner
|
||
|
||
```http
|
||
POST /api/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "scanner",
|
||
"password": "Scanner123*"
|
||
}
|
||
```
|
||
|
||
Respuesta (Cognito):
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"accessToken": "eyJhbG...",
|
||
"refreshToken": "dXMtZWFzdC0x...",
|
||
"idToken": "eyJhbG...",
|
||
"tokenType": "Bearer",
|
||
"expiresIn": 3600,
|
||
"username": "scanner",
|
||
"roles": ["ROLE_SCANNER"]
|
||
}
|
||
```
|
||
|
||
### Renovar token
|
||
|
||
```http
|
||
POST /api/auth/refresh
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"refreshToken": "dXMtZWFzdC0x..."
|
||
}
|
||
```
|
||
|
||
Solo disponible con Cognito habilitado.
|
||
|
||
### Escanear código pase
|
||
|
||
```http
|
||
POST /api/pass-codes/scan
|
||
Authorization: Bearer eyJhbG...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"code": "K7P2M9XQ4R"
|
||
}
|
||
```
|
||
|
||
### Listado JSON (panel admin, requiere sesión)
|
||
|
||
```http
|
||
GET /admin/pass-codes/list
|
||
```
|
||
|
||
---
|
||
|
||
## App Flutter (escáner)
|
||
|
||
Ubicación: `flutter-app/qrscanner/`
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Login["LoginScreen"] --> Home["HomeScreen"]
|
||
Home --> Scanner["ScannerScreen"]
|
||
Scanner -->|QR detectado| API["POST /api/pass-codes/scan"]
|
||
Login -->|credenciales| Auth["POST /api/auth/login"]
|
||
```
|
||
|
||
| Archivo | Rol |
|
||
|---------|-----|
|
||
| `lib/screens/login_screen.dart` | Login y sesión |
|
||
| `lib/screens/scanner_screen.dart` | Lectura QR + escaneo |
|
||
| `lib/services/auth_service.dart` | Login, SharedPreferences |
|
||
| `lib/services/pass_code_service.dart` | Scan con Bearer token |
|
||
| `lib/config/api_config.dart` | URL base de la API |
|
||
|
||
**Ejecutar apuntando al backend local:**
|
||
|
||
```bash
|
||
cd flutter-app/qrscanner
|
||
flutter run --dart-define=API_BASE_URL=http://TU_IP:8080
|
||
```
|
||
|
||
La app valida que el usuario tenga `ROLE_SCANNER` (o grupo `scanners`) antes de permitir el escaneo.
|
||
|
||
---
|
||
|
||
## Arranque local
|
||
|
||
### Opción recomendada
|
||
|
||
```bash
|
||
./run-local.sh
|
||
```
|
||
|
||
El script:
|
||
|
||
- Detecta Java 25 (Temurin)
|
||
- Levanta Floci (y PostgreSQL si aplica)
|
||
- Espera y carga `cognito.local.env`
|
||
- Compila e inicia `base-admin-web-jar`
|
||
|
||
Si ya tienes `AWS_ENDPOINT_URL` exportado, no sobrescribe tus variables (útil para probar contra AWS).
|
||
|
||
### Maven manual (terminal)
|
||
|
||
```bash
|
||
# 1. Levantar Floci (Cognito local)
|
||
docker compose -f docker-compose.local.yml up -d floci
|
||
|
||
# 2. Esperar el bootstrap (genera cognito.local.env)
|
||
# Revisa que exista: docker/floci/generated/cognito.local.env
|
||
|
||
# 3. Cargar variables Cognito en la shell
|
||
set -a && source docker/floci/generated/cognito.local.env && set +a
|
||
|
||
# 4. Compilar y arrancar
|
||
mvn -pl base-admin-web-jar -am -DskipTests install
|
||
mvn -pl base-admin-web-jar spring-boot:run
|
||
```
|
||
|
||
Si Floci ya estaba levantado de antes, basta con el `source` y el `spring-boot:run`.
|
||
|
||
### PostgreSQL local
|
||
|
||
```bash
|
||
SPRING_PROFILES_ACTIVE=postgres ./run-local.sh
|
||
```
|
||
|
||
### PostgreSQL remoto
|
||
|
||
```bash
|
||
SPRING_PROFILES_ACTIVE=postgres \
|
||
SPRING_DATASOURCE_URL=jdbc:postgresql://TU_SERVIDOR:5432/base_admin_web \
|
||
SPRING_DATASOURCE_USERNAME=tu_usuario \
|
||
SPRING_DATASOURCE_PASSWORD=tu_password \
|
||
./run-local.sh
|
||
```
|
||
|
||
---
|
||
|
||
## Arranque manual e IntelliJ IDEA
|
||
|
||
Si abres el proyecto en IntelliJ (o cualquier IDE) sin usar `run-local.sh`, debes levantar Floci y configurar variables de entorno tú mismo. `run-local.sh` automatiza exactamente esos pasos.
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A["Abrir proyecto Maven en IntelliJ"] --> B["Java 25 como Project SDK"]
|
||
B --> C["docker compose up floci"]
|
||
C --> D["Esperar cognito.local.env"]
|
||
D --> E["Configurar Run Configuration"]
|
||
E --> F["Run BaseAdminWebApplication"]
|
||
F --> G["http://localhost:8080/login"]
|
||
```
|
||
|
||
### Requisitos previos
|
||
|
||
| Requisito | Versión / nota |
|
||
|-----------|----------------|
|
||
| JDK | **Java 25** (Temurin recomendado) |
|
||
| Maven | Incluido en el proyecto (wrapper no obligatorio; usa el Maven del IDE) |
|
||
| Docker | Para Cognito local (Floci) en puerto `4566` |
|
||
| IntelliJ | Ultimate o Community (con plugin Spring Boot en Community) |
|
||
|
||
### 1. Importar el proyecto
|
||
|
||
1. **File → Open** y selecciona la carpeta raíz del repo (donde está el `pom.xml` padre).
|
||
2. IntelliJ detecta el proyecto **Maven multi-módulo**. Espera a que termine la indexación e importación.
|
||
3. **File → Project Structure → Project**: SDK = **Java 25**, language level = **25**.
|
||
4. **File → Settings → Build → Build Tools → Maven → Runner**: JRE = **Project SDK (Java 25)**.
|
||
|
||
### 2. Levantar Floci (Cognito local)
|
||
|
||
En una terminal (puede ser la Terminal integrada de IntelliJ):
|
||
|
||
```bash
|
||
docker compose -f docker-compose.local.yml up -d floci
|
||
```
|
||
|
||
La primera vez Floci ejecuta el bootstrap y escribe:
|
||
|
||
```
|
||
docker/floci/generated/cognito.local.env
|
||
```
|
||
|
||
Comprueba que el archivo existe (puede tardar ~30–120 s):
|
||
|
||
```bash
|
||
cat docker/floci/generated/cognito.local.env
|
||
```
|
||
|
||
Si no aparece, revisa los logs:
|
||
|
||
```bash
|
||
docker logs base-admin-web-floci
|
||
```
|
||
|
||
**PostgreSQL local:** si usas el perfil `postgres`, levanta también el servicio:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.local.yml up -d postgres floci
|
||
```
|
||
|
||
### 3. Run Configuration en IntelliJ
|
||
|
||
Crea una configuración **Spring Boot** (o **Application**):
|
||
|
||
| Campo | Valor |
|
||
|-------|-------|
|
||
| **Name** | `BaseAdminWebApplication` |
|
||
| **Main class** | `mx.gob.slp.baseadminweb.jar.BaseAdminWebApplication` |
|
||
| **Module** | `base-admin-web-jar` |
|
||
| **Working directory** | `$PROJECT_DIR$/base-admin-web-jar` |
|
||
| **Active profiles** | `dev` (o `postgres` si aplica) |
|
||
|
||
> **Working directory:** H2 guarda datos en `./data/h2/` relativo al directorio de trabajo. Debe ser `base-admin-web-jar` para que coincida con `mvn spring-boot:run` y no mezclar rutas de BD.
|
||
|
||
#### Variables de entorno (Cognito local)
|
||
|
||
En **Environment variables**, pega el contenido de `docker/floci/generated/cognito.local.env`:
|
||
|
||
```
|
||
COGNITO_USER_POOL_ID=us-east-1_BaseAdminWeb
|
||
COGNITO_REGION=us-east-1
|
||
COGNITO_ISSUER_URI=http://localhost:4566/us-east-1_BaseAdminWeb
|
||
COGNITO_JWK_SET_URI=http://localhost:4566/us-east-1_BaseAdminWeb/.well-known/jwks.json
|
||
COGNITO_ADMIN_CLIENT_ID=<valor del archivo generado>
|
||
COGNITO_SCANNER_CLIENT_ID=<valor del archivo generado>
|
||
COGNITO_ADMIN_GROUP=admins
|
||
COGNITO_SCANNER_GROUP=scanners
|
||
AWS_ENDPOINT_URL=http://localhost:4566
|
||
AWS_DEFAULT_REGION=us-east-1
|
||
AWS_ACCESS_KEY_ID=test
|
||
AWS_SECRET_ACCESS_KEY=test
|
||
```
|
||
|
||
Los `CLIENT_ID` cambian en cada bootstrap; **copia siempre los del archivo generado**, no uses valores fijos de ejemplos antiguos.
|
||
|
||
**Alternativa:** plugin [EnvFile](https://plugins.jetbrains.com/plugin/7861-envfile) → añade `docker/floci/generated/cognito.local.env` como archivo de entorno en la Run Configuration.
|
||
|
||
#### Perfil `postgres` en IntelliJ
|
||
|
||
Además de **Active profiles** = `postgres`, añade en Environment variables:
|
||
|
||
```
|
||
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/base_admin_web
|
||
SPRING_DATASOURCE_USERNAME=postgres
|
||
SPRING_DATASOURCE_PASSWORD=postgres
|
||
```
|
||
|
||
(Y las variables Cognito del paso anterior.)
|
||
|
||
### 4. Ejecutar
|
||
|
||
1. **Build → Build Project** (o `Ctrl+F9`).
|
||
2. Run ▶ en `BaseAdminWebApplication`.
|
||
3. Abre http://localhost:8080/login — usuario `admin` / `Admin123*`.
|
||
|
||
### 5. Desarrollo sin Docker (modo local puro)
|
||
|
||
Si no quieres Floci, desactiva Cognito y usa usuarios de la BD:
|
||
|
||
| Variable | Valor |
|
||
|----------|-------|
|
||
| `APP_COGNITO_ENABLED` | `false` |
|
||
|
||
No hace falta `AWS_ENDPOINT_URL` ni levantar Docker. Los usuarios `admin` y `scanner` se crean al arrancar vía `InitialDataLoader`.
|
||
|
||
El login API devuelve JWT local (HS256); **refresh no está disponible** en este modo.
|
||
|
||
### 6. Checklist de problemas frecuentes
|
||
|
||
| Síntoma | Causa probable | Solución |
|
||
|---------|----------------|----------|
|
||
| Login web falla con Cognito habilitado | Floci no está arriba o faltan env vars | `docker compose up -d floci` + cargar `cognito.local.env` |
|
||
| Login va a AWS real en local | Falta `AWS_ENDPOINT_URL` | Definir `AWS_ENDPOINT_URL=http://localhost:4566` |
|
||
| `Invalid client id` | Client IDs desactualizados | Regenerar con bootstrap y copiar de `cognito.local.env` |
|
||
| H2 vacío o ruta rara | Working directory incorrecto | `$PROJECT_DIR$/base-admin-web-jar` |
|
||
| Error de versión Java | SDK distinto a 25 | Project Structure → SDK Java 25 |
|
||
| Tests en IDE fallan por Cognito | Perfil `test` desactiva Cognito | Ejecutar tests con perfil `test` (ya configurado en `application-test.yml`) |
|
||
|
||
### 7. Comandos útiles desde IntelliJ
|
||
|
||
| Acción | Comando Maven (ventana Maven o terminal) |
|
||
|--------|------------------------------------------|
|
||
| Compilar todo | `mvn -pl base-admin-web-jar -am -DskipTests install` |
|
||
| Tests | `mvn test` |
|
||
| Solo módulo jar | clic derecho en `base-admin-web-jar` → Run Maven → `spring-boot:run` (tras exportar env vars en la shell) |
|
||
|
||
---
|
||
|
||
## Perfiles Spring
|
||
|
||
| Perfil | Base de datos | Cognito | Uso |
|
||
|--------|---------------|---------|-----|
|
||
| `dev` (default) | H2 en archivo `./data/h2/` | Floci (manual o `run-local.sh`) | Desarrollo diario |
|
||
| `postgres` | PostgreSQL | Floci | Desarrollo con BD real |
|
||
| `prod` | Configurable | AWS | Producción |
|
||
| `test` | H2 en memoria `create-drop` | Deshabilitado | `mvn test` |
|
||
|
||
---
|
||
|
||
## Variables de entorno
|
||
|
||
### Aplicación
|
||
|
||
| Variable | Default | Descripción |
|
||
|----------|---------|-------------|
|
||
| `SERVER_PORT` | `8080` | Puerto HTTP |
|
||
| `SPRING_PROFILES_ACTIVE` | `dev` | Perfil Spring |
|
||
| `APP_TITLE` | `Base Admin Web` | Título en vistas |
|
||
|
||
### Cognito
|
||
|
||
| Variable | Local (Floci) | Producción (AWS) |
|
||
|----------|---------------|------------------|
|
||
| `APP_COGNITO_ENABLED` | `true` | `true` |
|
||
| `COGNITO_REGION` | `us-east-1` | tu región |
|
||
| `COGNITO_USER_POOL_ID` | `us-east-1_BaseAdminWeb` | `us-east-1_XXXXX` |
|
||
| `COGNITO_ISSUER_URI` | `http://localhost:4566/...` | `https://cognito-idp.{region}.amazonaws.com/{poolId}` |
|
||
| `COGNITO_JWK_SET_URI` | `http://localhost:4566/.../jwks.json` | `https://cognito-idp.{region}.amazonaws.com/{poolId}/.well-known/jwks.json` |
|
||
| `COGNITO_ADMIN_CLIENT_ID` | generado por Floci | client del pool |
|
||
| `COGNITO_SCANNER_CLIENT_ID` | generado por Floci | client del pool |
|
||
| `COGNITO_ADMIN_GROUP` | `admins` | `admins` |
|
||
| `COGNITO_SCANNER_GROUP` | `scanners` | `scanners` |
|
||
| `AWS_ENDPOINT_URL` | `http://localhost:4566` | **no definir** |
|
||
|
||
### Base de datos
|
||
|
||
| Variable | Descripción |
|
||
|----------|-------------|
|
||
| `SPRING_DATASOURCE_URL` | JDBC URL |
|
||
| `SPRING_DATASOURCE_USERNAME` | Usuario BD |
|
||
| `SPRING_DATASOURCE_PASSWORD` | Contraseña BD |
|
||
| `SPRING_JPA_HIBERNATE_DDL_AUTO` | `update` por defecto |
|
||
|
||
### JWT local (solo `APP_COGNITO_ENABLED=false`)
|
||
|
||
| Variable | Descripción |
|
||
|----------|-------------|
|
||
| `APP_JWT_SECRET` | Secreto HS256 (mín. 32 caracteres) |
|
||
| `APP_JWT_EXPIRATION_HOURS` | Expiración del token |
|
||
|
||
### Usuarios semilla (modo local sin Cognito)
|
||
|
||
| Variable | Default |
|
||
|----------|---------|
|
||
| `APP_ADMIN_USERNAME` / `APP_ADMIN_PASSWORD` | `admin` / `Admin123*` |
|
||
| `APP_SCANNER_USERNAME` / `APP_SCANNER_PASSWORD` | `scanner` / `Scanner123*` |
|
||
|
||
---
|
||
|
||
## Objetivo de esta base
|
||
|
||
Esta base deja resuelto lo mínimo para arrancar nuevos proyectos internos:
|
||
|
||
- Autenticación Cognito (local y AWS) con fallback a BD local
|
||
- Panel web con Metronic y sesión HTTP para administradores
|
||
- API stateless con JWT para escaneo móvil o externo
|
||
- App Flutter de referencia para escaneo QR
|
||
- Módulo de códigos pase con alta, listado, QR y API de escaneo
|
||
- Estructura modular Maven limpia
|
||
- Soporte rápido para H2 y PostgreSQL
|
||
- Floci para desarrollo sin depender de AWS
|
||
|
||
El dashboard se mantiene deliberadamente sencillo como punto de partida para futuras integraciones. |