Producto
Producto (/app/releases, antes “App Releases” — la migración 242 solo
renombra la card del home y el menú, el slug sigue siendo releases) reúne dos
vistas del trabajo que entra a los distintos repos de la compañía: un
changelog unificado de todas las apps y una vista de Actividad con
series de PRs/commits por repo. Vive dentro del módulo app-releases del
backend (apps/backend/src/app-releases/).
Changelog unificado
Al entrar a/app/releases lo primero es un feed cronológico con entradas de
todos los repos, no solo uno. Un chip de filtro por proyecto (Todos por
defecto) permite acotar a un repo concreto — al elegir uno, la vista recupera
las funciones que antes eran el comportamiento por defecto: estado en tiendas
(solo app móvil), hitos de versión, filtro “solo sin comunicar” y el flujo de
anuncio a Slack. En la vista Todos, cada tarjeta lleva un badge de color con
el nombre del repo (misma paleta que los gráficos de Actividad,
activity/repo-colors.ts) para que se distinga de un vistazo. Arriba, un strip
resume el pulso de la semana (“Esta semana: N PRs a producción · M repos
activos”), leído del mismo endpoint que la vista Actividad; si el sync todavía
no corrió para ningún repo, el strip se oculta en vez de mostrar un cero
engañoso.
El gating de siempre se mantiene: usuarios no-admin solo ven entradas
published; las acciones de admin (editar, publicar, borrar) siguen disponibles
entrada a entrada en cualquiera de las dos vistas. GET /app-releases/changelog
acepta project como filtro opcional — sin él devuelve entradas de todos
los proyectos (con el campo project en cada una), cambio non-breaking: los
consumidores que ya mandan project (app móvil incluida) siguen funcionando
igual.
Dos métricas distintas (vista Actividad)
Cómo se cuenta un “release” no es igual en todos los repos: se modela por
proyecto con
release_metric (merged_prs para gitflow, commits para repos
que empujan directo a master sin release PRs, como vivla-api) más
default_branch y throughput_branch. Cuando throughput_branch es NULL, la
rama de producción es el único stream y el evento cuenta como both (release y
throughput a la vez).
Proyectos rastreados
La banderaactivity_tracked (independiente de is_active, que gobierna la
visibilidad en el changelog) marca qué repos entran al sync — sin lista
hardcodeada en el script, se lee de la tabla app_releases_projects. Sembrados
por las migraciones 179 y 242:
Los 10 repos rastreados son también, desde la migración
242,
is_active = true — visibles en el changelog unificado (aunque la mayoría
todavía no tiene entradas manuales/AI-generadas).
Modelo de datos (migración 179)
app_releases_activity_events— un registro por PR mergeado o commit (external_id= número de PR o SHA, único por proyecto → sync idempotente). Se guardan eventos individuales (no pre-agregados) para que semana/mes/quarter sean todos unGROUP BYsobremerged_at.- Columnas nuevas en
app_releases_projects: la config por proyecto (default_branch,throughput_branch,release_metric,activity_tracked), el estado del sync (activity_sync_status∈never/ok/error,activity_last_synced_at,activity_sync_error) y el LOC (loc_total,loc_by_language,loc_measured_at).
Endpoints
Los GET son solo Auth0 (lectura del dashboard); los POST aceptan además
x-api-key para el cron de Windmill. El sync es per-proyecto con try/catch:
un repo que el token no puede leer no bloquea al resto (queda con
activity_sync_status = 'error' y se pinta como fallo visible en el banner,
nunca como un 0 silencioso).
Autenticación con GitHub
GitHubService (app-releases/ai-agent/github.service.ts) se autentica como
GitHub App cuando están las tres variables GITHUB_APP_ID,
GITHUB_APP_INSTALLATION_ID y GITHUB_APP_PRIVATE_KEY (la clave privada puede
llegar con \n escapados desde Railway); si no, cae al PAT
APP_RELEASES_GITHUB_TOKEN. Sin ninguna de las dos, la integración queda
deshabilitada.
Automatización (Windmill)
Dos scripts de referencia enapps/windmill/f/vivla_tools/reports/, ambos
guardados por Auth0OrApiKeyGuard (usan f/vivla_tools/api_key[_dev|_prod]):
Mientras
release_loc_refresh no esté de alta, el LOC que se ve es el
sembrado por la migración 179 (exacto, medido el 21-jul-2026) — correcto, solo
no se refresca solo. micaela y vivla-intelligence (migración 242) todavía
no tienen LOC sembrado. El banner de la vista marca un proyecto como
desfasado si su último sync tiene más de 9 días (varias corridas diarias
perdidas antes de alertar).