Mi rol en el proyecto · Primera persona

Lo que hice yo:
arquitectura, nube
e integración

Me enfoqué en la arquitectura del backend, en integrar las partes del equipo y en llevar el sistema a la nube con un despliegue que se actualiza solo con cada cambio.

Hexagonal
la arquitectura que diseñé
Docker
contenedoricé todo
CI/CD
pipeline automático en GitHub Actions
Cloud Run
desplegado en GCP, keyless

así lo armé, paso a paso
Mi rol en el equipo

Arquitectura, integración y despliegue

El proyecto fue un trabajo de equipo: un compañero hizo el backend de auth, otro el frontend y otro la base de datos. Mi parte fue la que conecta todo — diseñar la estructura, integrar las piezas y armar el camino del código hasta producción.

Diseñé la arquitectura

Definí la estructura hexagonal del backend para que cada uno pudiera trabajar su parte sin pisarse.

Integré el trabajo del equipo

Conecté el frontend con el backend: login con JWT y sincronización de datos reales.

Llevé todo a la nube

Contenedoricé los servicios y armé el despliegue automático en GCP Cloud Run.

Cuidé la calidad

Detecté un merge que rompía el sistema y blindé el pipeline para que no vuelva a pasar.

1 · Lo que diseñé

Arquitectura hexagonal

Elegí esta arquitectura por una razón concreta: aislar la lógica de negocio de los detalles técnicos. Así la base de datos o el framework son piezas que se enchufan, no algo que contamina el código central.

Infraestructura — detalles que se enchufan
Rutas REST (Flask)
Repositorio SQLite
Repositorio Supabase
↓ conecta por interfaces (puertos) ↓
Dominio — el corazón, no depende de nada
Socio, Usuario, Pagoentidades + reglas
Puertos (interfaces)contratos abstractos

Esto aplica el Principio de Inversión de Dependencias (la "D" de SOLID): el dominio define el contrato, la infraestructura lo cumple. Por eso puedo cambiar de SQLite a Supabase sin tocar la lógica.

2 · Contenedores

Docker

Empaqueté cada servicio en su propia imagen de Docker. La app se lleva su entorno adentro (Python, dependencias, configuración), así corre igual en mi notebook que en la nube.

Dos imágenes

Un Dockerfile para el backend y otro para el frontend. Cada uno define cómo se construye y arranca.

Docker Compose

Un docker-compose.yml levanta los dos servicios juntos con un comando, conectados en red y con la base persistente.

# Levanto todo el sistema con un solo comando
docker compose up --build

# Backend en :5001 · Frontend en :5000 · base persistente
3 · Automatización

CI/CD con GitHub Actions

Configuré dos flujos de trabajo (workflows) que se disparan solos con cada push a la rama main. La idea: que pasar de "código nuevo" a "en producción" no dependa de que yo me acuerde de hacer pasos a mano.

Workflow de CI

Corre los tests y verifica que la aplicación arranca. Si algo falla, frena ahí — no deja avanzar código roto.

Workflow de Deploy

Construye las imágenes, las sube al registro y las despliega en Cloud Run. Todo sin intervención manual.

Push a main

Subo un cambio al repositorio.

CI valida

GitHub corre los tests y el chequeo de arranque en un servidor limpio.

Build & Push

Se construyen las imágenes Docker etiquetadas con el hash del commit y se suben a Artifact Registry.

Deploy a Cloud Run

Se despliega la nueva versión. Si arranca sana, queda viva; si no, Cloud Run mantiene la anterior.

4 · Identidad y permisos

IAM + Workload Identity Federation

Para que GitHub pueda desplegar en mi proyecto de Google Cloud, necesita autenticarse. Lo resolví sin descargar ninguna clave secreta — usando federación de identidades.

¿Qué es IAM?

Identity and Access Management: el sistema de Google Cloud que decide quién puede hacer qué. Creé una cuenta de servicio (una identidad no-humana) y le di solo los permisos justos: subir imágenes al registro y desplegar en Cloud Run. Principio de menor privilegio.

Service AccountRoles mínimosArtifact Registry WriterCloud Run Admin

¿Cómo se conecta sin clave? (WIF)

GitHub genera un token de identidad (OIDC) firmado. Configuré Google Cloud para confiar en ese token solo para mi repositorio. Google lo intercambia por un permiso temporal que actúa como la cuenta de servicio. No hay ninguna clave JSON que se pueda filtrar.

# Autenticación KEYLESS contra Google Cloud
- uses: google-github-actions/auth@v3
  with:
    workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
    service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
    token_format: access_token   # token temporal, no una clave fija

Por qué importa: el método viejo era bajar un archivo de clave y guardarlo como secreto. Si se filtraba, te entraban a la nube. Con WIF no existe esa clave: el permiso dura minutos y solo se emite para mi repo.

5 · Imágenes

Artifact Registry

Es el "depósito" de imágenes Docker dentro de Google Cloud. El pipeline construye cada imagen, la etiqueta con el hash del commit y la sube ahí. Cloud Run después tira de ese depósito para desplegar.

# Construyo y subo la imagen del backend, versionada por commit
docker build -f backend/Dockerfile -t $REGISTRY/$PROJECT/sistema-socios/backend:$SHA .
docker push $REGISTRY/$PROJECT/sistema-socios/backend:$SHA

Etiquetar con el hash del commit (:$SHA) me da trazabilidad: cada imagen en la nube corresponde exactamente a una versión del código. Si algo falla, sé qué commit se desplegó.

6 · Despliegue

Cloud Run — serverless

Es donde corren mis contenedores en producción. Le doy una imagen y él se encarga del resto: la ejecuta, la expone con HTTPS, y la escala según la demanda — incluso a cero cuando nadie la usa, así no pago de más.

Sin servidores

No administro máquinas. Google maneja el sistema operativo, los parches y el escalado.

Escala automática

De 0 a N instancias según el tráfico. Paga por uso real.

Puerto 8080

El contenedor escucha el puerto que Cloud Run le indica por la variable PORT.

# Despliego el backend a Cloud Run
gcloud run deploy backend \
  --image $REGISTRY/$PROJECT/sistema-socios/backend:$SHA \
  --region us-central1 \
  --platform managed \
  --port 8080 \
  --set-env-vars "SUPABASE_URL=...,SUPABASE_KEY=..."
7 · Gestión de secretos

Cómo manejo las credenciales

Las claves (Supabase, la firma de los tokens, etc.) nunca van en el código. Hoy las guardo como GitHub Actions Secrets y se inyectan como variables de entorno al momento de desplegar.

Lo que uso hoy — GitHub Secrets

Los secretos viven cifrados en la configuración del repositorio. El workflow los lee con ${{ secrets.X }} y se los pasa a Cloud Run con --set-env-vars. Nunca aparecen en el código ni en los logs.

SUPABASE_URLSUPABASE_KEYSECRET_KEYWIF_PROVIDER

El siguiente paso — Secret Manager

Google Cloud tiene un servicio dedicado: Secret Manager. Guarda secretos versionados, con permisos por IAM y auditoría de quién los lee. Cloud Run los monta directo con --set-secrets, sin pasar por variables de entorno en el deploy.

Por qué sería mejor: rotación de claves centralizada, control de acceso fino y registro de auditoría. Es la evolución natural de mi setup actual.

Caso de Mejora: hoy uso GitHub Secrets + variables de entorno. Secret Manager es la mejora que entiendo y que aplicaría en una versión productiva real.