Adds a proactive daily heartbeat, since the existing Telegram flows
(docs-monitor, pulse) only notify on change/error/weekly schedule and never
confirm "everything's fine." Runs at 14:00 UTC (10:00 AM EDT) and reports:
- Dashboard site health (reuses the existing /api/health-check endpoint)
- Unresolved Sentry issues from the last 24h across all 3 Sentry projects
(aitmpl-workers, aitmpl-dashboard, aitmpl-cli)
Does NOT poll the other 3 workers' /status endpoints directly — Cloudflare
blocks Worker-to-Worker fetches over the public *.workers.dev hostname
within the same account (error 1042, confirmed via wrangler dev --remote).
Their health is covered by their own Sentry Cron Monitor check-ins instead.
Also adds a /status endpoint to aitmpl-crons (cloudflare-workers/crons/index.js)
for consistency with the other workers, even though it isn't polled here.
Verified end-to-end: manual /trigger call returns a clean report and
successfully delivers to Telegram (message_id confirmed). Sentry summary
section requires SENTRY_AUTH_TOKEN + SENTRY_ORG_SLUG secrets (pending —
degrades gracefully to "not configured" until set).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds free-tier Sentry error reporting to close the biggest observability
gap: automated cron/worker failures were previously invisible (aitmpl-crons
had no error handling at all). Uses a dependency-free fetch()-based Sentry
envelope client (cloudflare-workers/*/sentry.js, dashboard error-tracking.ts,
cli-tool error-reporting.js) instead of the official SDKs, to keep the
zero-dependency worker style and avoid Cloudflare Pages SSR friction.
- Cloudflare Workers: report failures + Cron Monitor check-ins in crons,
pulse, and docs-monitor (complementing, not replacing, existing Telegram
alerts). Also drops the pulse Vercel collector (VERCEL_API/collectVercel),
since the dashboard no longer deploys to Vercel.
- Dashboard: captureApiError() wired into claude-code-check, health-check,
and the three track-* endpoints.
- CLI: opt-in only crash reporting (CCT_ERROR_REPORTING=true), always
deferring to the existing CCT_NO_TRACKING/CCT_NO_ANALYTICS/CI opt-outs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* migrate: Vercel → Cloudflare Pages + Workers para reducir costos ($110 → ~$0-5/mes)
- Cambia adaptador Astro de @astrojs/vercel a @astrojs/cloudflare (mode: 'directory')
- Agrega dashboard/wrangler.toml con nodejs_compat para compatibilidad total
- Crea cloudflare-workers/crons/ Worker que reemplaza los cron jobs de Vercel
(claude-code-check cada 30min, health-check cada 1h en vez de cada 15min)
- Actualiza CI/CD: Vercel CLI → wrangler pages deploy (requiere CLOUDFLARE_API_TOKEN y CLOUDFLARE_ACCOUNT_ID en GitHub Secrets)
- Elimina crons duplicados del proyecto legacy aitmpl (root vercel.json)
- Quick win: agrega Cache-Control headers a components.json (86400s), plugins.json,
trending-data.json y claude-jobs.json para cortar el costo de bandwidth de $53
Próximos pasos manuales (ver PR description):
1. Crear proyecto en Cloudflare Pages
2. Agregar secrets de Cloudflare en GitHub
3. Migrar env vars de Vercel a Cloudflare Dashboard
4. Deployar cloudflare-workers/crons con wrangler
5. Apuntar dominios a Cloudflare Pages
* fix: nodejs_compat_v2 + react-dom/server.node alias para Cloudflare Workers
- Cambia compatibility_flags de nodejs_compat a nodejs_compat_v2
- Agrega alias vite react-dom/server → react-dom/server.node para evitar
MessageChannel error en module init time en Cloudflare Workers runtime
- Agrega ssr.noExternal para bundlear react-dom y aplicar el alias
* fix: revert compatibility_flags a nodejs_compat (estándar)
nodejs_compat_v2 no es el flag primario. El fix real del MessageChannel
error fue el alias vite react-dom/server → react-dom/server.node,
no el cambio de flag.
* fix: inject Cloudflare Pages runtime env into process.env via middleware
Add Astro middleware that copies context.locals.runtime.env (Cloudflare
Pages secrets) into process.env before each request, so API routes can
use process.env.X as a unified pattern without changing the call sites.
Also add || process.env.X fallbacks to all API routes/libs that were
using import.meta.env exclusively (build-time only in Vite).
Verified on staging: track-download-supabase, health-check,
claude-code-check, collections, github/token all return correct responses.