CI/CD
CÉNIT corre en Cloudflare Workers vía @opennextjs/cloudflare
(no Vercel). El pipeline está repartido en seis workflows de GitHub
Actions, cada uno con un rol acotado: build + bundle budget, deploy a
Workers, migraciones de Supabase, deploy del sitio de docs, validación
de la línea Docs: en PRs, y tests + lint.
Workflows
Sección titulada «Workflows»cloudflare-build.yml
Sección titulada «cloudflare-build.yml»Corre en cada PR que toca paths de build (app/**, lib/**,
package.json, wrangler.toml, open-next.config.ts, etc.) y en
push a main.
- Ejecuta
opennextjs-cloudflare build+wrangler deploy --dry-runcontracenit-dev. - Mide el tamaño gzip del bundle y falla si excede el budget de
.github/cloudflare-build-baseline.json. - Valida que las versiones de
@opennextjs/cloudflareywranglerpineadas en el lockfile matcheen el baseline. - No deploya — solo gate de PR.
cloudflare-deploy.yml
Sección titulada «cloudflare-deploy.yml»Tres targets:
- PR previews → Worker
cenit-pr-${PR_NUM}. Auto-deploy enopened/synchronize/reopened. Auto-cleanup enclosed. - Staging → Worker
cenit-staging. Auto en cada push amain. - Producción → Worker
cenit-prod. Trigger: push de tagv*. Gated por el GitHub Environmentcf-production(reviewer + timer de 5 min).
Sentry releases se taggean con el nombre del tag en producción y con el SHA en staging.
migrations.yml
Sección titulada «migrations.yml»Aplica migraciones de Supabase via scripts/db-migrate.sh. Idempotente
— cada archivo queda registrado con su sha256 en
_cenit_meta.schema_migrations.
- Staging (
db-stagingenv) → push amain. - Producción (
db-productionenv, con reviewer) → push de tagv*.
Trigger paths: supabase/migration-*.sql, scripts/db-migrate.sh y
el propio workflow.
docs-deploy.yml
Sección titulada «docs-deploy.yml»Sitio Astro Starlight → Cloudflare Pages.
- Producción → proyecto
cenit-docs, dominiodocs.cenitams.com. Auto en push amaincon cambios endocs-site/**. - Staging → proyecto
cenit-docs-staging, dominiodocs-staging.cenitams.com. Auto en push astaging.
Token separado (CLOUDFLARE_DOCS_API_TOKEN) con scope Pages:Edit —
least privilege respecto del token de la app.
docs-check.yml
Sección titulada «docs-check.yml»Valida que cada PR tenga una línea Docs: en el body con uno de:
updated, n/a, o follow-up #ISSUE. Sin docs declarados → CI
falla. La regla vive en DOCUMENTATION_PLAN.md § 6 y la plantilla en
.github/PULL_REQUEST_TEMPLATE.md.
test.yml
Sección titulada «test.yml»Lint + unit tests + integration (Vitest + Playwright + Postgres
matrix). Path-filter ignora cambios doc-only (**.md, .llm/**,
docs/**). Nightly cron a las 06:00 UTC corre la matrix completa
PG15+PG17 si hubo actividad en main en las últimas 24h.
Release flow
Sección titulada «Release flow»1. PR mergeado a main → staging auto-deploy (app + docs + migrations)2. Verificación manual en staging3. git tag v1.2.3 -m "release notes" && git push origin v1.2.34. Reviewer aprueba cf-production y db-production5. Producción deploya (app + migrations)El docs site no participa del tag flow — se deploya con cada push
a main directamente.
Dominios
Sección titulada «Dominios»- App:
cenitams.com(legacycenitapp.comredirige 302). - Docs:
docs.cenitams.com(staging:docs-staging.cenitams.com).
Variables de entorno / secrets
Sección titulada «Variables de entorno / secrets»# Workers (app)CLOUDFLARE_API_TOKEN # Workers:EditCLOUDFLARE_ACCOUNT_IDCLOUDFLARE_HYPERDRIVE_LOCAL_* # stubs para emulación local en deploy
# Pages (docs)CLOUDFLARE_DOCS_API_TOKEN # Pages:Edit + User:Read
# DBSTAGING_DATABASE_URL # session-pooler (port 6543, sslmode=require)PRODUCTION_DATABASE_URLIntegraciones
Sección titulada «Integraciones»- Sentry — el SHA del build se exporta como release.
- Multi-tenant — migraciones que cambian RLS pasan por el flow de migrations gateado.
Gotchas
Sección titulada «Gotchas»- Path filter
middleware.tshardcodeado —cloudflare-build.ymllistamiddleware.tsen supaths:filter. Si el archivo se renombra aproxy.ts(la convención que Next.js 16 documenta como sucesor), el workflow dejará de dispararse en cambios a ese archivo y los builds quedarán mudos. Actualizar el filter en el mismo PR que el rename.
Limitaciones / roadmap
Sección titulada «Limitaciones / roadmap»- Sin rollback automático de migrations —
db-migrate.shaplica forward-only. Rollback requiere migration nueva que revierta. - Concurrency en migrations —
concurrency: cancel-in-progress: falseevita cancelar una migración en vuelo, pero si dos tags pushean en sucesión cercana, la cola puede crecer. - PR preview workers no comparten DB con la app real — apuntan al mismo Supabase staging. Cuidado al testear destructive ops.