STACK_PERFIL - Documentación para Desarrolladores
Descripción General
Stack core de perfiles de usuario MAS10. Gestiona el ciclo de vida completo del perfil: registro OAuth, CRUD, datos físicos/nutricionales, avatar (3 tamaños con background removal), resumen estadístico, trayectoria deportiva, ubicación con PostGIS, tips con tracking de acceso, figuritas (sticker borders), versión de app, idiomas, términos y condiciones, y calendario Google.
Arquitectura
STACK_PERFIL/
├── perfil.yaml # Template SAM
├── build_perfil.sh
├── layer/
│ ├── database_perfil/ # Lógica de dominio pesada
│ │ └── database.py # Queries complejos (CTEs, window functions)
│ ├── querys_perfil/
│ │ └── query.py
│ ├── response_formatter_perfil/
│ │ └── response_formatter.py
│ ├── s3_perfil/
│ │ └── s3.py # Avatares 3 tamaños, PDFs
│ └── utils_perfil/
│ └── utils.py
└── services/
├── check-version/ # Verificación semántica de versión
├── coach-athletes/ # Atletas del entrenador
├── e-mail/ # Envío SMTP (⚠️ credenciales hardcoded)
├── languages/ # GET idiomas, PUT cambiar idioma
├── like-note/ # Toggle like con contadores feed
├── location/ # CRUD con PostGIS + clustering Lambda
├── next-play-by-user/ # Próximo partido
├── profile/ # GET (512MB), PUT (1024MB), DELETE
├── register/ # POST registro OAuth (512MB)
├── sticker-border/ # Bordes de figuritas
├── summary/ # Estadísticas del usuario (CTEs complejos)
├── terms-and-conditions/ # Aceptar TyC
├── tips/ # Tips con access tracking
├── tocke/ # Token Google Calendar
├── tournament-history/ # Historial de ediciones
└── trajectory/ # Trayectoria deportiva
Runtime y Configuración
| Propiedad | Valor |
|---|---|
| Python | 3.13 |
| Arquitectura | ARM64 |
| Timeout default | 30s |
| Memoria default | 128MB |
| Auth | Cognito JWT (mayoría) |
Funciones con configuración especial:
| Función | Timeout | Memoria | Notas |
|---|---|---|---|
| profile GET | 30s | 512MB | Carga completa de perfil |
| profile PUT | 30s | 1024MB | Avatar processing (3 tamaños) + background removal |
| register POST | 30s | 512MB | OAuth + DynamoDB + PostgreSQL |
| summary GET | 30s | 256MB | CTEs complejos de estadísticas |
Pipeline de Avatar
PUT /profile (actualización con avatar):
- Recibe imagen como Base64 o URL
- Genera 3 versiones:
- Original: Tamaño completo
- 50px: Thumbnail para listas
- 100px: Thumbnail para cards
- Invoca Lambda de background removal (async)
- Sube las 3 versiones a S3
- Actualiza URLs en PostgreSQL
- Sync con DynamoDB (tabla
Profiles{ENV})
# Flujo de avatar
blob = utils.get_blob(body['avatar'])
s3.upload(blob, f"avatars/{user_id}/original")
s3.upload_resized(blob, f"avatars/{user_id}/50", 50)
s3.upload_resized(blob, f"avatars/{user_id}/100", 100)
aws.execute_lambda("background-removal", {"key": f"avatars/{user_id}/original"}, "Event")
Sistema de Registro
POST /register:
- Recibe datos OAuth (Google/Apple/Email)
- Verifica si usuario ya existe en PostgreSQL
- Si existe → retorna perfil existente
- Si no existe:
- Crea en PostgreSQL (userprofile)
- Crea en DynamoDB (
Profiles{ENV}) - Si tiene avatar provider → descarga y sube a S3
- Retorna perfil con flag
is_new
Tabla userprofile (campos principales):
id, email, first_name, last_name, username, avatar, avatar_50, avatar_100,
position, dominant_foot, height, weight, date_of_birth, gender,
type_user (athlete|coach|seer|webuser), language, provider,
description, phone, created_at, updated_at
Resumen Estadístico (Summary)
GET /summary:
Usa CTEs (Common Table Expressions) complejos para agregar:
- Goles, asistencias, tarjetas amarillas/rojas
- Partidos jugados, ganados, empatados, perdidos
- Puntos totales
- Agrupado por año y torneo
- Soporta
userprofileyteam
WITH player_stats AS (
SELECT ... FROM tournament_match_player
WHERE user_id = %(id)s AND year = %(year)s
GROUP BY tournament_id
),
team_stats AS (
SELECT ... FROM tournament_match
WHERE ... GROUP BY ...
)
SELECT * FROM player_stats
JOIN team_stats USING (tournament_id)
Trayectoria (Trajectory)
GET /trajectory:
Carrera deportiva con agrupación inteligente:
- Por año → Por equipo → Estadísticas
- Detecta cambios de equipo en el mismo año
- Soporta
userprofile(jugador) yteam(equipo)
Sistema de Ubicación
CRUD /location/:
- POST: Crea ubicación con PostGIS (
ST_MakePoint(long, lat))- Dispara Lambda de re-clustering async
- GET: Consulta por ID, perfil, o coordenadas
- PUT: Actualiza campos
- DELETE: Elimina ubicación
Clustering Lambda:
Después de crear/actualizar ubicación, se invoca Lambda de clustering que:
- Re-calcula clusters geográficos
- Actualiza tabla de recomendaciones del sistema de followers
Like Note
POST /like-note:
- Toggle: si no hay like, lo crea; si ya hay, lo elimina
- Actualiza contador en tabla
feed_aggregate - No envía notificación push (solo counter update)
Tips con Access Tracking
GET /tips:
- Retorna tips por categoría
- Registra acceso del usuario al tip (
tip_accesstable) - Permite tracking de qué tips ha visto cada usuario
⚠️ Issues Conocidos
Credenciales SMTP hardcoded
e-mail/post.py tiene credenciales de Gmail hardcoded:
# ❌ Inseguro
smtp_user = "notificaciones@mas10.com"
smtp_pass = "xxxxx" # Hardcoded
# ✅ Debería usar AWS Secrets Manager
secret = aws.get_secret_aws("email_credentials")
Tablas de Base de Datos
PostgreSQL:
userprofile— Perfil completo del usuariophysical_data— Datos físicos (peso, altura, IMC)nutrition_data— Datos nutricionaleslocation— Ubicaciones con geometría PostGIStip— Tips del sistematip_access— Tracking de acceso a tipssticker_border— Bordes de figuritas disponiblesterms_conditions— Versiones de TyCterms_conditions_user— Aceptaciones por usuariolanguage— Idiomas disponiblesfeed_aggregate— Contadores de likes/engagement
DynamoDB:
Profiles{ENV}— Cache de perfiles (sync bidireccional)
Sync PostgreSQL ↔ DynamoDB
El perfil se mantiene sincronizado en ambas BDs:
- Escritura: PUT /profile actualiza PostgreSQL primero, luego DynamoDB
- Registro: POST /register crea en ambas
- Delete: DELETE /profile elimina/anonimiza en ambas
- Lectura: GET /profile lee de PostgreSQL (source of truth)
Build y Deploy
cd STACK_PERFIL
sudo bash ./build_perfil.sh 1 -d # Dev local
sudo bash ./build_perfil.sh 2 -d # Dev deploy
sudo bash ./build_perfil.sh 2 -q # QA deploy
sudo bash ./build_perfil.sh 2 -p # Prod deploy