Plataforma de datos de punta a punta para una red de pagos con tarjeta. Trabaja con dos fuentes de datos, ambas ficticias:
- Una base de datos ficticia (
sample_data/mastercard_db_ficticia.json: bancos emisores, comercios, tarjetas y 1.500 transacciones de septiembre). Se carga en un PostgreSQL (RDS) que hace de "core bancario" y se replica a S3 con AWS DMS, que además captura cada cambio nuevo (CDC). - Un simulador en Python (
generator.py) que imita los archivos de autorizaciones que enviaría un adquirente, con errores de calidad y patrones de fraude inyectados a propósito para poner a prueba el pipeline.
Las ordena en tres capas sobre S3 siguiendo la arquitectura medallion y las entrega listas para el negocio:
- Bronze guarda el dato tal como llegó, cifrado e inmutable.
- Silver lo limpia, valida y deduplica, manda a cuarentena lo que no cumple las reglas y tokeniza el número de tarjeta: ningún analista ve un PAN.
- Gold produce los productos de datos: KPIs por comercio, la liquidación de intercambio entre bancos y alertas de fraude con la precisión de cada regla medida contra fraudes confirmados.
Se consume con Athena (SQL), un dashboard de Power BI, una API REST y archivos de liquidación que cada banco emisor descarga de su propia carpeta. Todo es infraestructura como código (Terraform + CloudFormation), con IAM de mínimo privilegio, gobierno de datos con Lake Formation y CI/CD en GitHub Actions vía OIDC (sin access keys). Está desplegado y verificado en una cuenta real de AWS (ver Verificado en AWS).
⚠️ Todos los datos son sintéticos: bancos, comercios, tarjetas, tipos de cambio y tasas de intercambio son inventados.
| Requisito | Dónde se ve en el proyecto |
|---|---|
| S3 | 7 buckets (una capa por bucket), KMS, versionado, ciclo de vida, TLS obligatorio — s3.tf |
| Glue | Data Catalog (3 bases + partition projection), job PySpark 5.0 que calcula tablas de Gold (segmentos y tendencias) y antes valida Silver con Glue Data Quality — glue_job.tf, gold_card_analytics.py |
| DMS | Réplica full load + CDC de PostgreSQL (core bancario) a Bronze en Parquet — dms.tf, adaptador en silver.py |
| Athena | Workgroup con tope de costo, 12 consultas guardadas — sql/ |
| Lambda | 4 funciones: ingesta, bronze→silver, silver→gold, API — handlers.py |
| IAM | Un rol por identidad, políticas acción por acción, permissions boundary, 25 comprobaciones automáticas — iam.tf, docs/iam.md |
| CloudWatch | Métricas de negocio y calidad (EMF), alarmas, dashboard, Logs Insights — observability.tf |
| CloudFormation | Bootstrap: estado de Terraform, OIDC GitHub, rol de despliegue, boundary — bootstrap.yaml |
| CloudTrail | Trail con eventos de datos sobre Bronze + alertas de accesos denegados y cambios de permisos — cloudtrail.tf |
| Step Functions | Orquestación con reintentos y backoff — orchestration.tf |
| EventBridge | Scheduler horario del pipeline + regla de fallas de Glue → SNS |
| Lake Formation | LF-Tags (layer, sensitivity), analista sólo Gold, analista de riesgo Silver+Gold — lakeformation.tf |
| EC2 | Instancia de carga del core (IMDSv2, sin SSH, Session Manager) — core_db.tf |
| VPC | Subredes privadas/pública, endpoint S3, flow logs, security groups mínimos — network.tf |
| Medallion | Bronze (crudo) → Silver (canónico, tokenizado, cuarentena) → Gold (productos de datos) |
| SQL avanzado | Ventanas, z-score, percentiles, cohortes, ROLLUP/GROUPING, FILTER — sql/advanced/; Spark SQL en el job de Glue |
| Python / Shell | Paquete payments_lake, 30 tests; scripts PowerShell/bash en infra/command/ |
| Git | GitHub Actions: tests, terraform validate, cfn-lint, ShellCheck, deploy con OIDC |
| Observabilidad | Dashboard CloudWatch, alarmas de calidad de datos y de seguridad, X-Ray, presupuesto, y registro estructurado de cada despliegue (PC y GitHub) con alarma si falla — docs/observabilidad-despliegues.md |
| QuickSight / Power BI | Dashboard de Power BI conectado a Athena por ODBC con el rol de analista (powerbi/Dashboard_lake.pbix, se abre con datos), datasets de QuickSight en Terraform — docs/powerbi.md, docs/quicksight.md |
Desplegado y probado en una cuenta real (sa-east-1, 21-10-2026). Cada prueba se ejecutó contra los recursos desplegados:
| Prueba | Resultado |
|---|---|
| Despliegue con Terraform (197 recursos) + bootstrap con CloudFormation | ✅ |
| Pipeline Step Functions: Ingest → Bronze → Silver → Gold | ✅ SUCCEEDED |
| DMS full load + CDC desde PostgreSQL (RDS) | ✅ 1525 transacciones (1500 + 25 por CDC), updates tardíos aplicados |
| Job de Glue (PySpark + Glue Data Quality) | ✅ SUCCEEDED, reglas DQ en verde |
| Athena: 12 consultas guardadas | ✅ |
| Lake Formation: analista lee Gold, no lee Silver ni Bronze | ✅ |
| Intercambio B2B: el emisor EM001 lee sus liquidaciones, no las de EM005; sin ExternalId no entra | ✅ |
API de Gold: 5 endpoints, 401 sin API key |
✅ |
| Power BI por ODBC con el rol de analista: el navegador muestra sólo Gold | ✅ |
| IAM: 25 comprobaciones con el simulador de políticas | ✅ |
| Registro de cada despliegue en CloudWatch + S3 | ✅ incluida la causa de cada fallo |
Los 10 problemas que aparecieron al desplegar por primera vez, con su causa y su corrección, están en docs/antes-de-desplegar.md.
Diagrama editable en draw.io: docs/img/arquitectura.drawio (abrir en app.diagrams.net → Abrir desde → Este dispositivo).
flowchart LR
subgraph Fuentes
A[Simulador Python<br/>de adquirentes, con PAN]:::src
subgraph VPC
EC2[EC2 carga<br/>+ CDC simulado] --> RDS[(RDS PostgreSQL<br/>core bancario)]:::src
DMS[AWS DMS<br/>full load + CDC]
end
end
subgraph Lakehouse["AWS sa-east-1"]
EB[EventBridge<br/>Scheduler] --> SF[Step Functions]
SF --> L1[λ ingest] --> B[(S3 Bronze<br/>crudo · versionado)]
RDS --> DMS --> B
SF --> L2[λ bronze→silver]
B --> L2 --> S[(S3 Silver<br/>canónico · tokenizado)]
L2 --> Q[(Cuarentena)]
SF --> L3[λ silver→gold]
S --> L3 --> G[(S3 Gold)]
S --> GJ[Glue PySpark<br/>+ Data Quality] --> G
L3 --> X[(S3 Exchange<br/>liquidaciones por emisor)]
LF{{Lake Formation<br/>LF-Tags}} -.-> S & G
G --> API[API Gateway + λ]
G --> AT[Athena]
end
X -->|rol IAM por emisor| BANK[Emisores]
AT --> QS[QuickSight / Power BI]
API --> DASH[Dashboard Streamlit<br/>Lightsail]
CT[CloudTrail] -.-> B
CW[CloudWatch<br/>métricas · alarmas · dashboard] -.-> SF
classDef src fill:#fde68a,stroke:#b45309
| Capa | Bucket | Contenido | Quién accede |
|---|---|---|---|
| Bronze | paylake-dev-bronze-<cuenta> |
transactions/ (simulador), dms/core/<tabla>/ (réplica DMS), core_snapshot/ (extracto JSON) |
ingest, DMS y bronze→silver. Ningún humano |
| Silver | paylake-dev-silver-<cuenta> |
transactions/source_system=…/txn_date=…, quarantine/, dq_source_reconciliation/, dim_* |
pipeline; analista de riesgo vía Lake Formation |
| Gold | paylake-dev-gold-<cuenta> |
KPIs, liquidación de intercambio, alertas y desempeño de reglas de fraude, corredores, segmentos de tarjetas (Glue) | API, analistas vía Lake Formation, QuickSight |
| Exchange | paylake-dev-exchange-<cuenta> |
outbound/issuer_id=…/settlement_date=…/settlement.csv + _manifest.json |
cada emisor, sólo su prefijo |
- Ingesta multi-fuente: el simulador de adquirentes (con errores inyectados a propósito) y el core bancario, que llega
por DMS (CDC) o, si DMS está apagado, como extracto JSON (
sample_data/). - Silver: esquema canónico único, tipado, deduplicación, 10+ reglas de calidad, cuarentena con motivo, enriquecimiento.
El PAN se tokeniza (HMAC-SHA256) y nunca sale de Bronze en claro; la cuarentena lo enmascara (
510510******1234). Los totales que declara el core se reconcilian contra Silver (6/6 métricas cuadran). - Gold: KPIs por comercio, liquidación de intercambio emisor↔adquirente, alertas de fraude (5 reglas) y su precision/recall contra fraudes confirmados, corredores transfronterizos; segmentación de tarjetas y tendencias en Glue.
- Intercambio de datos: archivos de liquidación por emisor con manifiesto (SHA-256, totales), rol IAM por emisor con ExternalId y API REST sobre Gold.
src/payments_lake/ # paquete Python: mismo código en local y en Lambda
glue/jobs/ # job PySpark de Glue (Data Quality + Spark SQL)
scripts/core_db/ # carga y CDC simulado del core bancario (PostgreSQL)
sample_data/ # extracto core ficticio
sql/ · sql/advanced/ # consultas Athena (se publican como Named Queries)
infra/account/ # Terraform: personas y sus llaveros (paylake-admins, paylake-consultores); estado en S3
infra/bootstrap/ # CloudFormation: estado remoto, OIDC GitHub, rol de despliegue, boundary
infra/platform/ # Terraform: el lakehouse completo (iam.tf concentra todas las identidades)
infra/command/ # comandos de cada actualización: bootstrap · deploy · check_iam · destroy
dashboard/ # Streamlit + despliegue a Lightsail
docs/ # antes de desplegar, IAM, observabilidad de despliegues, QuickSight, Power BI
tests/ # 30 tests
python -m venv .venv; .venv\Scripts\activate
pip install -r requirements-dev.txt
pytest -q
$env:PYTHONPATH="src"; python -m payments_lake.pipeline demo --days 3
pip install -r dashboard/requirements.txt; streamlit run dashboard/app.pyPrimera vez: seguir docs/antes-de-desplegar.md (cuenta, identidad de administrador con Terraform desde CloudShell, credenciales, chequeo previo y problemas conocidos).
Requisitos: AWS CLI y Terraform ≥ 1.10. La identidad de administrador también se crea con Terraform, desde
AWS CloudShell (que ya está autenticado): bash infra/command/cloudshell_admin.sh y luego aws configure en tu PC.
Todos los comandos viven en infra/command/:
./infra/command/preflight.ps1 # antes de empezar: detecta bloqueos
./infra/command/bootstrap.ps1 -AlertEmail tu@correo.com # una vez (CloudFormation)
./infra/command/deploy.ps1 -RunPipeline # cada cambio: tests → plan → apply → pipeline → check_iam
./infra/command/destroy.ps1 # al terminarDespués, cada push a main lo despliega GitHub Actions con OIDC. Variables opcionales del repo:
ENABLE_DMS, ENABLE_QUICKSIGHT, QUICKSIGHT_USER_ARN, ALERT_EMAIL.
| Pieza | Costo aproximado (sa-east-1) |
|---|---|
| Lambda, Step Functions, S3, Athena, Glue Catalog, IAM, Lake Formation | centavos |
| Job de Glue (diario, 2 DPU × ~3 min) | ~USD 0,05 por ejecución |
| KMS (1 llave) | ~USD 1 / mes |
RDS db.t4g.micro + DMS dms.t3.small + EC2 t4g.micro (enable_dms) |
~USD 2–3 / día |
QuickSight (enable_quicksight) |
prueba gratuita de 30 días |
Una semana con todo encendido ronda USD 15–20 (estimación). aws_budgets_budget avisa por email al 80 % de
monthly_budget_usd (25 por defecto). ./infra/command/destroy.ps1 -PauseOnly detiene la ejecución horaria.
- Lambda + pandas para el pipeline horario, Glue/Spark para la analítica diaria: con este volumen Lambda es más barato y simple; el job de Glue muestra el camino de escala sobre la misma capa Silver.
- DMS tiene prioridad sobre el extracto JSON: ambas son la misma fuente (
source_system=core) por distinto canal; Silver aplica los cambios CDC (OpI/U/D, gana el últimodms_ts). - Idempotencia: Silver y Gold se recalculan por ventana con
overwrite_partitions; reprocesar da el mismo resultado (tests). - Lake Formation sobre Silver/Gold, IAM sobre Bronze: los humanos nunca consultan Bronze, así que basta IAM; las capas consultables se gobiernan por etiquetas y heredan permisos al crear tablas nuevas.
- CloudFormation para el bootstrap, Terraform para el resto: Terraform no puede crear el bucket donde guarda su estado.
- Las reglas de fraude tienen baja precisión a propósito:
fraud_rule_performancepermite medirlas y calibrarlas con datos etiquetados, como se hace con un motor de fraude real.
