Onboarding Unificado — PrivaSteward
docs/ONBOARDING.md (setup y repo),
transafety/docs/guides/onboarding_junior_devs.md (metodología IA)
y el análisis real del grafo Graphify (2026-06-09).
0. Lectura obligatoria antes de tocar código
Lee en este orden antes de escribir una sola línea:
| # | Archivo | Por qué |
|---|---|---|
| 1 | CLAUDE.md (raíz) | Documento maestro: stack, módulos, protocolos, contexto legal. ~600 líneas. Leerlo completo. |
| 2 | docs/ARQUITECTURA_TECNICA.md | Diagramas y componentes técnicos |
| 3 | docs/GUIA_DESARROLLO.md | Setup del entorno, comandos, convenciones |
| 4 | docs/FUNCIONALIDADES.md | Manual funcional de los 15 módulos |
| 5 | docs/PENDIENTES.md | Roadmap priorizado con contexto legal |
| 6 | docs/CONVENCIONES_CLAUDE.md | Reglas para sesiones con Claude Code |
| 7 | docs/decisions/ | Decision logs de arquitectura (ADRs) |
1. Qué es PrivaSteward
Plataforma web de Transafety Ltda. para gestionar el cumplimiento de la Ley 21.719 de Protección de Datos de Chile (vigente 1-dic-2026). Permite a organizaciones documentar, controlar y demostrar su cumplimiento normativo.
Stack
| Componente | Tecnología |
|---|---|
| Backend | Python 3.11 + Flask 3.0 |
| ORM | SQLAlchemy 2.0 |
| DB | SQLite (dev) / PostgreSQL (QA/Prod) |
| Frontend | HTML5 + Bootstrap 5 + Jinja2 |
| Testing | pytest + pytest-cov + Playwright (E2E) |
| Infra | AWS ECS Fargate + RDS + ALB + SES |
| CI/CD | Manual (build → push ECR → update ECS) |
1.1 Flask — el backend
Flask es un micro-framework web para Python. "Micro" no significa limitado, sino que no impone estructura: no trae ORM, ni autenticación, ni plantillas prefijadas. Tú decides qué agregas. Esto lo hace ideal para proyectos que crecen con disciplina propia.
En PrivaSteward, Flask es el núcleo que:
- Recibe cada petición HTTP y la dirige al blueprint correspondiente (una forma de agrupar rutas por módulo).
- Ejecuta los decoradores de seguridad (
@permission_required,@login_required) antes de llegar a la lógica. - Retorna HTML renderizado (vía Jinja2) o JSON (vía
jsonify) según la ruta. - Se inicializa a través del patrón Application Factory (
create_app()ensrc/app/__init__.py), que permite crear instancias distintas para desarrollo, testing y producción sin cambiar código.
1.2 Bootstrap 5 — el frontend visual
Bootstrap es una biblioteca CSS (y JavaScript) de código abierto creada por Twitter. Provee un sistema de grids responsivos, componentes visuales predefinidos (botones, tablas, modales, alertas, formularios) y utilidades de espaciado, color y tipografía. Su objetivo es que no tengas que escribir CSS desde cero para hacer una interfaz usable y consistente.
En PrivaSteward se usa Bootstrap 5 en todos los templates. Cuando ves clases como
class="btn btn-primary" o class="table table-striped" en los archivos
.html, esas son clases de Bootstrap que ya traen estilo incorporado. Modificar la apariencia
de un componente generalmente significa cambiar o agregar clases de Bootstrap, no escribir CSS custom.
https://getbootstrap.com/docs/5.3/. La mayoría de las veces existe.
1.3 Jinja2 — el motor de plantillas
Jinja2 es el motor de plantillas de Python que usa Flask. Permite escribir archivos HTML con "agujeros" que se rellenan con datos dinámicos cuando el servidor construye la respuesta.
Las tres construcciones que más verás en src/app/templates/:
| Sintaxis Jinja2 | Para qué sirve | Ejemplo |
|---|---|---|
{{ variable }} | Mostrar un valor | {{ user.name }} → Gonzalo |
{% if / for %} | Lógica de control | {% for req in requests %}...{% endfor %} |
{% extends / block %} | Herencia de templates | {% extends "base.html" %} — reutiliza navbar y footer |
El template base (templates/base.html) contiene el layout común (sidebar, navbar, scripts de Bootstrap).
Cada módulo extiende ese base con {% extends "base.html" %} y solo define su contenido propio
dentro de {% block content %}...{% endblock %}.
1.4 SQLAlchemy — ORM
SQLAlchemy es el ORM (Object-Relational Mapper) de Python. Traduce clases Python
a tablas de base de datos y viceversa. En vez de escribir SQL crudo, defines modelos como
class User(BaseModel) y SQLAlchemy genera las queries. En desarrollo se usa SQLite (un archivo
local, sin servidor); en QA y producción, PostgreSQL.
1.5 Docker y la infraestructura AWS
¿Qué es Docker?
Docker es una herramienta que empaqueta una aplicación junto con todo lo que necesita
para funcionar — Python, las dependencias de requirements.txt, las variables de entorno base,
el comando de arranque — dentro de una unidad llamada contenedor. El contenedor es idéntico
sin importar dónde se ejecute: en tu laptop, en el servidor de QA o en producción en AWS.
La analogía más útil: imagina que en vez de entregar una receta (el código fuente) que cada cocinero tiene que interpretar con sus propios ingredientes y utensilios, entregas una comida ya preparada en un tupper sellado. El resultado es siempre el mismo.
Los dos conceptos que debes distinguir:
| Concepto | Qué es | Analogía |
|---|---|---|
| Imagen Docker | Una "fotografía" inmutable de la aplicación con todo incluido. Se construye con
docker build a partir del Dockerfile en la raíz del proyecto. |
El molde para fabricar el tupper |
| Contenedor | Una instancia en ejecución de una imagen. Se puede iniciar, detener o destruir sin afectar la imagen original. | El tupper ya fabricado y corriendo |
El archivo Dockerfile en la raíz del proyecto describe cómo construir la imagen de
PrivaSteward: parte de una imagen base de Python, copia el código, instala las dependencias y define
el comando de arranque (gunicorn apuntando a create_app()).
PrivaSteward corre íntegramente en Amazon Web Services. Los cuatro servicios que debes conocer:
| Servicio | Nombre completo | Qué hace en este proyecto |
|---|---|---|
| ECS Fargate | Elastic Container Service (modo serverless) | Ejecuta los contenedores Docker de PrivaSteward sin que tengas que administrar servidores. Tú defines cuánta CPU/memoria necesita el contenedor; Fargate lo arranca, lo monitorea y lo reinicia si muere. El flujo de deploy es: construir imagen Docker → subirla a ECR → decirle a ECS que use la nueva imagen. |
| ECR | Elastic Container Registry | Repositorio privado de imágenes Docker en AWS. Equivale a Docker Hub pero dentro de tu cuenta AWS. Cada deploy genera una imagen nueva y la empuja aquí antes de que ECS la use. |
| RDS | Relational Database Service |
Base de datos PostgreSQL administrada. AWS se encarga de backups automáticos, parches de seguridad,
failover y réplicas. El código de PrivaSteward nunca se conecta a un servidor de base de datos propio;
se conecta a la instancia RDS via la variable de entorno DATABASE_URL.
|
| ALB | Application Load Balancer | Recibe todo el tráfico HTTPS externo y lo distribuye entre los contenedores ECS activos. También termina el SSL (el certificado TLS vive aquí, no en el contenedor). Es el único punto de entrada público al sistema. |
| SES | Simple Email Service |
Servicio de envío de correo transaccional. PrivaSteward lo usa para notificaciones de ARCOP+,
confirmaciones de consentimiento, alertas de incidente y cualquier email que dispare
EmailService. Es más confiable y barato que un servidor SMTP propio.
|
AWS: ECS detecta imagen nueva → reemplaza contenedor corriendo → ALB apunta al nuevo
Base de datos: RDS sigue corriendo sin interrupciones
Email: SES no requiere deploy
15 módulos y su estado
| # | Módulo | Descripción | Estado |
|---|---|---|---|
| 1 | auth | Autenticación, usuarios, roles, 2FA | 100% |
| 2 | rat | Registro de Actividades de Tratamiento | 100% |
| 3 | arcop | Derechos ARCO+ (interno) | 100% |
| 4 | arcop_public | Portal público ARCOP (sin login) | 100% |
| 5 | consent | Gestión de consentimientos | 100% |
| 6 | consent_campaigns | Campañas masivas de consentimiento | 80% |
| 7 | policy | Gestor de políticas con versionado | 100% |
| 8 | incident | Gestión de incidentes/brechas | 90% |
| 9 | dashboard | Métricas, matriz de calor, scores | 100% |
| 10 | dpia | Evaluaciones de impacto (EIPD) | 90% |
| 11 | dp_roles | Roles y responsabilidades (DPO) | 80% |
| 12 | third_parties | Gestión de terceros/encargados | 100% |
| 13 | information_assets | Activos de información y respaldos | 100% |
| 14 | reports | Generación de reportes | 90% |
| 15 | guardian_portal | Portal de apoderados/titulares | 100% |
2. Arquitectura real (datos del grafo — 7.887 nodos, 10.757 aristas)
graphify sobre el código real.
Más confiable que cualquier diagrama manual.
2.1 God Nodes — las abstracciones más acopladas
Estos son los nodos con más conexiones. Tocarlos tiene el mayor radio de impacto.
Úsalos con cuidado y siempre corre
graphify affected "<nodo>" --depth 2 antes de modificarlos.
2.2 Flujo de una request típica
└─ Blueprint (src/app/routes/<módulo>.py)
├─ @permission_required() ← decorators.py, 15 blueprints
├─ get_tenant_scoped_or_404() ← middleware/tenant.py, 129 conexiones
├─ <Módulo>Service ← services/<módulo>_service.py
│ └─ EmailService (si notifica) ← services/email_service.py
├─ AuditLog.log(...) ← models/audit_log.py
└─ render_template(...) ← templates/<módulo>/
2.3 Patrón Service — cómo está organizada la lógica
| Blueprint | Service | Métodos clave |
|---|---|---|
arcop.py | ARCOPService |
create_request, create_acknowledgment, create_response, extend_deadline, get_statistics, approve_request |
consent.py | ConsentService |
create_template, grant_consent, renew_consent, export_consents_csv, get_statistics_by_course |
third_parties.py | (directo) | create, edit, activate, suspend, terminate, create_contract, due_diligence |
2.4 Multitenancy — lo más importante para no romper datos
Model.query.filter_by(id=x) directamente en un blueprint.
Usa siempre get_tenant_scoped_or_404(Model, id).get_tenant_scoped_or_404() es el guard de multitenancy: cualquier query
que toque datos de un tenant pasa por aquí. Saltárselo crea una brecha de datos entre organizaciones.
2.5 Ciclos de import detectados (advertencia)
src/app/__init__.py↔src/app/extensions.pysrc/app/__init__.py↔ varios blueprints (policies.py,admin.py,guardians.py, …)- Ciclos 1-archivo en:
consent.py,notification_service.py,consent_campaign_service.py
3. Setup del entorno (una vez)
# 1. Clonar
git clone https://github.com/gveraTrnsfty/LeydeProtecciondeDatos.git
cd LeydeProtecciondeDatos
# 2. Entorno virtual
python -m venv venv
# Windows PowerShell:
.\venv\Scripts\Activate.ps1
# Linux/Mac:
source venv/bin/activate
# 3. Dependencias
pip install -r src/requirements.txt
# 4. Variables de entorno (SQLite funciona sin config adicional)
cp .env.example .env # Linux/Mac
copy .env.example .env # Windows
# 5. Hooks de calidad
pip install pre-commit && pre-commit install
# 6. Levantar
python src/run.py # → http://localhost:5000
Tests antes de cualquier commit
pytest tests/unit/ -v --tb=short # obligatorio
pytest tests/integration/ -v # para cambios en servicios
pytest --cov=src/app --cov-report=html # cobertura
Accesos que necesitas
- GitHub: colaborador en
gveraTrnsfty/LeydeProtecciondeDatos .envconfigurado con tus valores locales- AWS CLI (solo si haces deploys):
aws configure - QA URL:
https://qa.leydeprotecciondatos.cl/
4. Flujo Git (no negociable)
develop ← integración. Solo PR desde feature/.
feature/xxx ← tu trabajo diario.
git checkout develop && git pull origin develop
git checkout -b feature/mi-tarea
# ...trabajar...
git commit -m "feat(arcop): agregar endpoint GET /api/arcop/requests"
git push origin feature/mi-tarea
# → abrir PR a develop en GitHub
Conventional Commits obligatorio
| Tipo | Cuándo usarlo |
|---|---|
feat(módulo) | Nueva funcionalidad |
fix(módulo) | Corrección de bug |
refactor(módulo) | Reestructuración sin cambio funcional |
test(módulo) | Agregar o mejorar pruebas |
docs(módulo) | Documentación |
chore(módulo) | Mantenimiento, dependencias |
security(módulo) | Correcciones de seguridad |
perf(módulo) | Mejoras de rendimiento |
Alcances válidos: auth rat arcop consent policy incident dashboard dpia dp_roles api db deploy
Reglas duras
- Estás trabajando directo en
mainodevelop - Intentas commitear con tests rojos
- Hardcodeas credenciales
- El cambio afecta más de 5 archivos sin aprobación previa
- Cada PR significativo debe actualizar
CLAUDE.mdydocs/PENDIENTES.md
5. Trabajar con el agente IA (Claude Code)
5.0 Política de uso de IA — obligatorio leer
| Cliente autorizado | Cómo acceder | Cuándo usarlo |
|---|---|---|
| Claude Code CLI |
Terminal: claude (requiere autenticación con cuenta corporativa).Instalar: npm install -g @anthropic-ai/claude-code y luego claude login
con las credenciales que te entregó la empresa.
|
Trabajo técnico dentro del repositorio: editar código, correr tests, analizar el grafo, hacer refactors. Es el modo principal para desarrolladores. |
| App de Escritorio Claude |
Descarga desde claude.ai/download e inicia sesión con la cuenta corporativa.
|
Consultas más conversacionales: redactar documentación, entender conceptos legales, planificar una tarea antes de abrirla en el CLI. |
5.1 Regla base: micro-sesiones y carga bajo demanda
- Un chat nuevo por cada tarea no relacionada (evita context rot).
- No pegues archivos enteros. Deja que el agente use
Read,Grep,Glob. - Al cambiar de sesión: el agente genera
resumen_traspaso.mdcon lo logrado y lo pendiente.
5.2 Graphify — navega el código sin quemar tokens
El grafo está construido en graphify-out/ (7.887 nodos, commit c799a5b9). Invócalo con /graphify en Claude Code.
| Comando | Para qué | Cuándo usarlo |
|---|---|---|
graphify explain "ARCOPService" |
Mapa de un símbolo: métodos, quién lo importa, qué usa | Antes de tocar un service por primera vez |
graphify affected "ConsentTemplate" --depth 2 |
Radio de impacto si cambias algo | Antes de modificar un model o service |
graphify path "auth.py" "EmailService" |
Camino entre dos conceptos | Para entender cómo llega un flujo de A a B |
graphify query "<pregunta>" |
Búsqueda BFS amplia | Para preguntas de arquitectura ⚠️ puede aterrizar en .md |
# Actualizar el grafo (sin costo LLM)
graphify update .
Read directamente.
5.3 Skills disponibles
5.4 Thinking levels — razonamiento extendido del modelo
¿Qué significa que un LLM "piense"?
Los modelos de lenguaje como Claude generan respuestas token a token. Normalmente el modelo produce la respuesta directamente. Con extended thinking (razonamiento extendido), el modelo primero genera un bloque de razonamiento interno — una especie de borrador mental donde puede explorar alternativas, detectar contradicciones y corregir su propio razonamiento — antes de producir la respuesta final que el usuario ve.
Este proceso es análogo a pedirle a un experto que "piense en voz alta antes de responder" en lugar de dar la primera respuesta que se le ocurra. Para tareas simples no cambia nada. Para tareas complejas — un bug sutil de concurrencia, diseñar la arquitectura de un módulo nuevo, interpretar un artículo legal — puede ser la diferencia entre una respuesta superficial y una correcta.
Los tres niveles de thinking
En Claude Code se controlan con --thinking low|medium|high (o en la UI con el selector
de razonamiento). Cada nivel determina cuántos tokens internos de "pensamiento" puede usar el modelo
antes de responder:
| Nivel | Tokens internos aprox. | Cuándo usarlo | Costo relativo |
|---|---|---|---|
| low | ~1.000 – 5.000 | La gran mayoría de tareas: leer código, refactors mecánicos, escribir tests unitarios, corregir un typo, explicar una función, generar un migration, responder preguntas de documentación. El 80–90% de las interacciones del día a día. | Bajo |
| medium | ~5.000 – 15.000 | Tareas con algo de complejidad estructural: diseñar un nuevo endpoint que integra varios servicios, analizar el impacto de un cambio en un god node, debug de un comportamiento inesperado con varios archivos implicados. | Moderado |
| high | ~15.000 – 38.000+ | Problemas genuinamente difíciles: bugs de concurrencia o race conditions, decisiones arquitectónicas de alto impacto, interpretar ambigüedad legal para mapearla a código, refactors que cruzan 10+ archivos, análisis de seguridad adversarial. Úsalo con criterio: no porque el problema "sea importante" sino porque involucra razonamiento multi-paso donde un error en el paso 2 invalida todo lo siguiente. | Alto |
low
El nivel low cubre correctamente la abrumadora mayoría de las tareas de desarrollo
cotidiano. Subir a medium o high cuando no hay una razón técnica concreta
solo incrementa el costo de tokens y el tiempo de respuesta sin mejorar el resultado. Pregúntate:
"¿necesita el modelo explorar múltiples hipótesis antes de responder?"
Si la respuesta es no, quédate en low.
high puede generar 30.000 tokens internos que se suman a la factura aunque nunca los
veas en pantalla. En un proyecto con muchas sesiones diarias, esto escala rápido. Reserva high
para los momentos donde realmente importa.
Ejemplos concretos en PrivaSteward
| Tarea | Nivel recomendado | Por qué |
|---|---|---|
Escribir test unitario para ARCOPService.create_request | low | Mecánico, el modelo ya conoce el patrón |
Agregar campo nuevo al formulario de rat | low | Cambio localizado, patrón repetitivo |
Diseñar cómo agregar notificaciones push sin romper EmailService | medium | Requiere razonar sobre acoplamiento entre servicios |
Depurar por qué get_tenant_scoped_or_404() devuelve datos de otro tenant en un edge case | high | Bug de multitenancy con múltiples hipótesis posibles, alto riesgo |
| Decidir arquitectura del módulo de auditoría para cumplir Art. 14 ter | high | Decisión irreversible con implicaciones legales y técnicas |
5.5 Worktrees — humano y agente trabajando en paralelo
¿Qué es un worktree?
Normalmente cuando usas Git, tienes una sola carpeta de trabajo asociada a tu repositorio.
Si quieres cambiar de rama, haces git checkout otra-rama y los archivos de tu carpeta cambian.
No puedes estar en dos ramas a la vez en la misma carpeta.
Un git worktree te permite tener múltiples carpetas de trabajo distintas del mismo
repositorio, cada una en una rama diferente, al mismo tiempo. Comparten la misma historia de Git
(el mismo .git/ interno) pero tienen sistemas de archivos separados. Es como abrir el mismo
proyecto en dos ventanas del explorador, cada una mostrando una rama distinta, sin interferir entre sí.
¿Por qué es útil con agentes IA?
Cuando le das una tarea larga a Claude Code, el agente puede tardar varios minutos modificando archivos. Sin worktrees, mientras el agente trabaja en tu carpeta principal, tú no puedes tocar esos archivos sin crear conflictos. Con un worktree:
- El agente trabaja en
../privasteward-agente/en su propia ramafeature/tarea-del-agente. - Tú sigues trabajando en
LeydeProtecciondeDatos/en tu propia rama sin ninguna interferencia. - Cuando el agente termina, revisas el diff, haces merge o cherry-pick, y borras el worktree.
Comandos
# 1. Crear el worktree para el agente (crea carpeta hermana + nueva rama)
git worktree add ../privasteward-agente feature/tarea-del-agente
# 2. El agente trabaja en ../privasteward-agente
# Tú sigues trabajando en LeydeProtecciondeDatos/ normalmente
# 3. Ver todos los worktrees activos
git worktree list
# 4. Cuando terminas: eliminar el worktree y la rama (si ya hiciste merge)
git worktree remove ../privasteward-agente
git branch -d feature/tarea-del-agente
feature/tarea-del-agente, tú no puedes hacer checkout de esa misma rama en tu carpeta principal
hasta que el worktree sea eliminado.
5.6 Definition of Done para una tarea con agente
flake8 src/ --max-line-length=120→ sin errorespytest tests/unit/→ verde- Calibración explícita: qué validó empíricamente vs qué asume
6. Contexto legal — artículos clave de la Ley 21.719
| Artículo | Tema | Módulo PrivaSteward |
|---|---|---|
| Art. 4–11 | Derechos ARCO+ (acceso, rectificación, supresión, oposición, portabilidad) | arcop |
| Art. 12 | Consentimiento | consent |
| Art. 13 | Bases de licitud (6 bases legales) | rat |
| Art. 14 ter | Deber de información (12 campos) | rat + policies |
| Art. 14 quinquies | Deber de seguridad | rat (medidas) |
| Art. 14 sexies | Reporte de brechas (72h) | incident |
| Art. 15 ter | EIPD (Evaluación de Impacto) | dpia |
| Art. 16 | Datos sensibles | rat (categorías) |
| Art. 16 quater | Datos de menores | rat + consent |
| Art. 27–28 | Transferencias internacionales | rat (transfers) |
| Art. 35 | Sanciones (hasta 20.000 UTM) | dashboard |
| Art. 49 | Modelo de Prevención de Infracciones | dp_roles, policies |
7. Tu primera tarea — checklist
- Leí CLAUDE.md, ARQUITECTURA_TECNICA.md, PENDIENTES.md
- Entorno levantado:
python src/run.pyresponde en :5000 pytest tests/unit/pasa en mi máquina- Corrí:
graphify explain "<el servicio que voy a tocar>" - Corrí:
graphify affected "<el servicio o model>" --depth 2 - Creé rama
feature/desde develop actualizado - Definí ALCANCE explícito (archivos a crear / modificar / NO tocar)
- Implementé SOLO lo aprobado, con test por cada función nueva
- flake8 + pytest verdes + grep de credenciales limpio
- Commit Conventional + PR a develop + decision log si hay decisión de diseño
8. Estructura del proyecto
LeydeProtecciondeDatos/
├── CLAUDE.md # Documento maestro
├── Dockerfile / docker-compose.yml
├── .env.example
├── pyproject.toml / .pre-commit-config.yaml
│
├── src/app/
│ ├── __init__.py # create_app() — 64 importadores
│ ├── extensions.py # db, login_manager, limiter, mail, csrf
│ ├── decorators.py # @permission_required — 15 blueprints lo importan
│ ├── middleware/tenant.py # get_tenant_scoped_or_404() — 129 conexiones ⚠️
│ ├── models/ # 25+ modelos SQLAlchemy (BaseModel como base)
│ ├── routes/ # 15+ blueprints Flask
│ ├── services/ # Lógica de negocio (EmailService es transversal)
│ ├── forms/ # Formularios WTForms
│ ├── templates/ # 150+ templates Jinja2
│ ├── static/ # CSS, JS, imágenes
│ └── api/ # Endpoints REST
│
├── tests/
│ ├── unit/ # 30+ archivos
│ ├── integration/
│ ├── e2e/ # Playwright
│ └── security/
│
├── config/ # development / qa / production / testing
├── docs/ # 70+ archivos de documentación
├── scripts/ # Seeds, utilidades, datasets de demo
├── migrations/ # Migraciones Alembic
└── graphify-out/ # Grafo de conocimiento (no commitear cambios aquí)
9. Contacto
| Lead | Gonzalo Vera — gonzalovera1978@gmail.com |
| Comunicación | Definir canal con el equipo (Slack, Teams, etc.) |
| Decision logs | docs/decisions/YYYY-MM-DD-descripcion.md |
| Metodología IA completa | transafety/docs/guides/onboarding_junior_devs.md y metodologia_agentes_2026.md |