Files
tiennm99 3f03521e84 feat(scripts): phase 07 — reverse-backfill scripts + delete guard
Pre-execution prerequisites for the Phase 07 cutover. Stage 2 of the
cutover keeps DUAL_WRITE=0 for ~6 days; if anything regresses during
that window the operator MUST be able to roll back to KV/D1 with the
last N days of Mongo-only writes recovered. Pre-building these scripts
(per code-reviewer #4) eliminates "draft a backfill under outage
pressure" — the anti-pattern of writing untested code at 4am.

Reverse-backfill
- scripts/backfill-mongo-to-kv.js: full-scan Mongo collection per module,
  PUT each doc back to CF KV via REST. expiresAt → expirationTtl (clamped
  to 60s minimum per CF KV); already-expired docs are skipped (won't
  resurrect dead state). 50 ops/sec throttle. --dry-run + --module flags.
- scripts/backfill-mongo-to-d1.js: full-scan trading_trades, build INSERT
  SQL preserving legacy_id where present (round-trips D1 autoincrement IDs
  preserved by phase-05 forward backfill). Sequential int generation for
  any docs without legacy_id. Pipes through wrangler d1 execute.
- scripts/lib/migration-helpers.js: cfKvPut helper added.

Delete guard (debugger #12)
- scripts/wrangler-delete-guard.sh: interactive CONFIRM wrapper around
  wrangler kv namespace delete + wrangler d1 delete. Exits 3 when stdin
  is not a tty so it cannot run in CI. Documented: never run in CI.

package.json: backfill:mongo:kv[:dry] + backfill:mongo:d1[:dry] scripts
wired.

Tests: 697 → 733 (+36).
- 7 cfKvPut tests (REST URL, querystring, body, expiration_ttl param).
- 10 reverse-KV TTL math tests (expired sentinel, future seconds, no-TTL,
  CF 60s minimum clamp).
- 9 reverse-D1 SQL construction tests (escaping, legacy_id preservation,
  sequential generation).

Lint clean. No Worker code touched. Stage 1 cutover, 7-day soak,
snapshots, and Stage 3 cleanup (delete CFKVStore + simplify factories +
edit package.json deploy chain) remain operator-driven and will be
committed separately after binding deletion.
2026-04-26 09:29:14 +07:00

49 lines
2.3 KiB
JSON

{
"name": "miti99bot",
"version": "0.1.0",
"description": "Telegram bot with plug-n-play module system, deployed to Cloudflare Workers.",
"private": true,
"type": "module",
"engines": {
"node": ">=20.6"
},
"scripts": {
"dev": "wrangler dev",
"build": "npm run build:wordle-data && npm run build:semantle-words",
"build:wordle-data": "node scripts/build-wordle-data.js",
"build:semantle-words": "node scripts/build-semantle-words.js",
"scrape:loldle-data": "node scripts/scrape-loldle-data.js",
"fetch:ddragon-data": "node scripts/fetch-ddragon-data.js",
"deploy": "npm run build && wrangler deploy && npm run db:migrate && npm run register",
"db:migrate": "node scripts/migrate.js",
"register": "node --env-file-if-exists=.env.deploy scripts/register.js",
"register:dry": "node --env-file-if-exists=.env.deploy scripts/register.js --dry-run",
"backfill:kv": "node --env-file-if-exists=.env.deploy scripts/backfill-kv-to-mongo.js",
"backfill:kv:dry": "node --env-file-if-exists=.env.deploy scripts/backfill-kv-to-mongo.js --dry-run",
"backfill:d1": "node --env-file-if-exists=.env.deploy scripts/backfill-d1-to-mongo.js",
"backfill:d1:dry": "node --env-file-if-exists=.env.deploy scripts/backfill-d1-to-mongo.js --dry-run",
"backfill:mongo:kv": "node --env-file-if-exists=.env.deploy scripts/backfill-mongo-to-kv.js",
"backfill:mongo:kv:dry": "node --env-file-if-exists=.env.deploy scripts/backfill-mongo-to-kv.js --dry-run",
"backfill:mongo:d1": "node --env-file-if-exists=.env.deploy scripts/backfill-mongo-to-d1.js",
"backfill:mongo:d1:dry": "node --env-file-if-exists=.env.deploy scripts/backfill-mongo-to-d1.js --dry-run",
"verify:mongo": "node --env-file-if-exists=.env.deploy scripts/verify-mongo-parity.js",
"wipe:mongo": "node --env-file-if-exists=.env.deploy scripts/wipe-mongo.js",
"analyze:soak": "node scripts/analyze-soak.js",
"burst:synthetic": "node scripts/synthetic-burst.js",
"lint": "biome check . && eslint src && node scripts/check-secret-leaks.js",
"format": "biome format --write .",
"test": "vitest run"
},
"dependencies": {
"grammy": "^1.30.0",
"mongodb": "^6.21.0"
},
"devDependencies": {
"@biomejs/biome": "^1.9.0",
"eslint": "^10.2.0",
"eslint-plugin-jsdoc": "^62.9.0",
"vitest": "^4.1.4",
"wrangler": "^4.84.0"
}
}