- docs/using-d1.md and docs/using-cron.md for module authors - architecture, codebase-summary, adding-a-module, code-standards, deployment-guide refreshed - CLAUDE.md module contract shows optional crons[] and sql in init - docs/todo.md tracks manual follow-ups (D1 UUID, first deploy, smoke tests)
4.5 KiB
Deployment Guide
Prerequisites
- Node.js ≥ 20.6
- Cloudflare account with Workers + KV + D1 enabled
- Telegram bot token from @BotFather
wranglerCLI authenticated:npx wrangler login
Environment Setup
1. Cloudflare D1 Database (Optional but Recommended)
If your modules need relational data or append-only history, set up a D1 database:
npx wrangler d1 create miti99bot-db
Copy the database ID from the output, then add it to wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "miti99bot-db"
database_id = "<paste-id-here>"
After this, run migrations to set up tables:
npm run db:migrate
The migration runner discovers all src/modules/*/migrations/*.sql files and applies them.
2. Cloudflare KV Namespaces
npx wrangler kv namespace create miti99bot-kv
npx wrangler kv namespace create miti99bot-kv --preview
Paste returned IDs into wrangler.toml:
[[kv_namespaces]]
binding = "KV"
id = "<production-id>"
preview_id = "<preview-id>"
3. Worker Secrets
npx wrangler secret put TELEGRAM_BOT_TOKEN
npx wrangler secret put TELEGRAM_WEBHOOK_SECRET
TELEGRAM_WEBHOOK_SECRET — any high-entropy string (e.g. openssl rand -hex 32). grammY validates it on every webhook update via X-Telegram-Bot-Api-Secret-Token.
4. Local Dev Config
cp .dev.vars.example .dev.vars # for wrangler dev
cp .env.deploy.example .env.deploy # for register script
Both are gitignored. Fill in matching token + secret values.
.env.deploy also needs:
WORKER_URL— the*.workers.devURL (known after first deploy)MODULES— comma-separated, must matchwrangler.toml[vars].MODULES
Deploy
Cron Configuration (if using scheduled jobs)
If any of your modules declare crons, they MUST also be registered in wrangler.toml:
[triggers]
crons = ["0 17 * * *", "0 2 * * *"] # list all cron schedules used by modules
The schedule string must exactly match what modules declare. For details on cron expressions and examples, see docs/using-cron.md.
First Time
npx wrangler deploy # learn the *.workers.dev URL
# paste URL into .env.deploy as WORKER_URL
npm run db:migrate # apply any migrations to D1
npm run register:dry # preview payloads
npm run deploy # deploy + register webhook + commands
Subsequent Deploys
npm run deploy
This runs wrangler deploy, npm run db:migrate, then scripts/register.js (setWebhook + setMyCommands).
What the Register Script Does
scripts/register.js imports the same registry the Worker uses, builds it with a stub KV to derive public commands, then calls two Telegram APIs:
setWebhook— points Telegram atWORKER_URL/webhookwith the secret tokensetMyCommands— pushes public command list to Telegram's/menu
Dry Run
npm run register:dry
Prints both payloads (webhook secret redacted) without calling Telegram.
Secret Rotation
- Generate new secret:
openssl rand -hex 32 - Update Cloudflare:
npx wrangler secret put TELEGRAM_WEBHOOK_SECRET - Update
.env.deploywith same value - Redeploy:
npm run deploy(register step re-calls setWebhook with new secret)
Both values MUST match — mismatch causes 401 on every webhook.
Adding/Removing Modules
When changing the active module list:
- Update
MODULESinwrangler.toml[vars] - Update
MODULESin.env.deploy - If adding: ensure module exists in
src/modules/index.jsimport map npm run deploy
Removing a module from MODULES makes it inert — its KV data remains but nothing loads it.
Rollback
Cloudflare Workers supports instant rollback via the dashboard or:
npx wrangler rollback
To disable a specific module without rollback, remove its name from MODULES and redeploy.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 401 on all webhooks | Secret mismatch between CF secret and .env.deploy |
Re-set both to same value, redeploy |
| Bot doesn't respond to commands | MODULES missing the module name |
Add to both wrangler.toml and .env.deploy |
command conflict at deploy |
Two modules register same command name | Rename one command |
missing env: X from register |
.env.deploy incomplete |
Add missing variable |
--env-file not recognized |
Node < 20.6 | Upgrade Node |
/help missing a module |
Module has no public or protected commands | Add at least one non-private command |