mirror of
https://github.com/tiennm99/miti99bot-js.git
synced 2026-05-14 13:52:59 +00:00
e2e3112eb5
Phase 08: Complete documentation pass for MongoDB Atlas migration. - Create docs/cost-tracking.md: Cost monitoring, upgrade triggers, monthly checklist - Create docs/project-changelog.md: Full migration summary with phase breakdown - Update docs/architecture.md section 8: Describe dual-write era, MongoDB store layers - Update docs/code-standards.md: Add Persistence section for storage factory patterns - Update docs/codebase-summary.md: Reflect MongoDB as primary, update test count (733) - Update README.md: Storage section now describes MongoDB + dual-write during migration - Update CLAUDE.md: Architecture section references MongoDB instead of KV/D1 - Update tests/fakes/fake-mongo.js: Document frozen surface (Phase 02-08 API) Verified: - All 733 tests passing - Lint + secret-leak check pass - npm run register:dry succeeds - Auto-pause concern satisfied: trading (17:00), lolschedule (01:00), drift-verifier (hourly) all write to Mongo - Roadmap verified migration NOT listed (future-only per user feedback) Post-Phase-07 cutover: dual-write collapses, KV/D1 deleted, MongoDB becomes sole backend.
5.4 KiB
5.4 KiB
Code Standards
Language & Runtime
- JavaScript (ES modules,
"type": "module"in package.json) - No TypeScript — JSDoc typedefs for type contracts (see
kv-store-interface.js,registry.js) - Cloudflare Workers runtime — Web APIs only, no Node.js built-ins, no
nodejs_compat - grammY for Telegram bot framework
Formatting (Biome)
Enforced by npm run lint / npm run format:
- 2-space indent
- Double quotes
- Semicolons: always
- Trailing commas: all
- Line width: 100 characters
- Imports: auto-sorted by Biome
Run npm run format before committing.
JSDoc & Type Definitions
- Central typedefs location:
src/types.js— all module-level typedefs live here (Env, Module, Command, Cron, ModuleContext, SqlStore, KVStore, Trade, Portfolio, etc.). - When to add JSDoc: Required on exported functions, types, and public module interfaces. Optional on internal helpers (< 5 lines, obviously self-documenting).
- Validation: ESLint (
eslint src) enforces valid JSDoc syntax. Runnpm run lintto check. - No TypeScript: JSDoc +
.jsfiles only. Full type info available to editor tooling without a build step. - Example:
/** * Validate a trade before insertion. * * @param {Trade} trade * @returns {boolean} */ function isValidTrade(trade) { return trade.qty > 0 && trade.priceVnd > 0; }
File Organization
- Max 200 lines per code file. Split into focused submodules when approaching the limit.
- Module code lives in
src/modules/<name>/— one folder per module. - Shared utilities in
src/util/. - DB layer in
src/db/. - Tests mirror source structure:
tests/modules/<name>/,tests/db/,tests/util/.
Naming Conventions
- Files: lowercase, hyphens for multi-word (
stats-handler.js,fake-kv-namespace.js) - Directories: lowercase, single word preferred (
trading/,util/) - Functions/variables: camelCase
- Constants: UPPER_SNAKE_CASE for frozen config objects (e.g.
CURRENCIES) - Command names: lowercase + digits + underscore, 1-32 chars, no leading slash
Module Conventions
Every module default export must have:
export default {
name: "modname", // === folder name === import map key
commands: [...], // validated at load time
init: async ({ db, sql, env }) => { ... }, // optional
crons: [...], // optional scheduled jobs
};
- Store module-level
dbandsqlreferences in closure variables, set duringinit - Never access
env.KV,env.DB, orenv.MONGODB_URIdirectly — always use the prefixeddb(KVStore) orsql(SqlStore) frominit sqlisnullwhen no relational store is bound — always guard withif (!sql) return- Command handlers receive grammY
ctx— usectx.matchfor command arguments,ctx.from.idfor user identity - Reply with
ctx.reply(text)— plain text or Telegram HTML - Cron handlers receive
(event, { db, sql, env })— same context asinit
Persistence Layer
All data persistence flows through storage factories:
createStore(moduleName, env)— returns aKVStoreinterface for key-value data (simple state, settings, JSON blobs). Implementation:MongoKVStore(primary) with optional dual-write to Cloudflare KV during migration.createSqlStore(moduleName, env)— returns aSqlStoreinterface for relational data (trading ledger, aggregates, scans). Implementation:MongoTradesStore(MongoDB native queries and inserts). D1 is read-only during migration.- Modules NEVER instantiate
MongoClientdirectly. All MongoDB access goes throughMongoKVStoreorMongoTradesStorefactories.
Post-migration (after Phase 07 cutover), the dual-write layer collapses and Cloudflare KV/D1 are deleted; createStore returns MongoKVStore directly.
Error Handling
- Load-time failures (bad module, command conflicts, missing env): throw immediately — fail loud at deploy, not at runtime.
- Handler-level errors (API failures, bad user input): catch and reply with user-friendly message. Never crash the handler — grammY logs unhandled rejections but the user sees nothing.
- KV failures: best-effort writes (wrap in try/catch), guard reads with
?.and null coalescing. getJSONswallows corrupt JSON and returns null — modules must handle null gracefully.
Testing
- Framework: Vitest
- Style: Pure-logic unit tests. No workerd, no Telegram integration, no network calls.
- Fakes:
tests/fakes/providesfake-kv-namespace.js,fake-bot.js,fake-modules.js. Inject via parameters, notvi.mock. - External APIs: Stub
global.fetchwithvi.fn()returning canned responses. - Coverage:
npx vitest run --coverage(v8 provider, text + HTML output).
Commit Messages
Conventional commits:
feat: add paper trading module
fix: handle null price in sell handler
docs: update architecture for trading module
refactor: extract stats handler to separate file
test: add portfolio edge case tests
Security
- Secrets live in Cloudflare Workers secrets (runtime) and
.env.deploy(local, gitignored). Never commit secrets. .dev.varsis gitignored — local dev only.- grammY validates webhook secret on every update. No manual header parsing.
- Module KV prefixing is a code-review boundary, not a cryptographic one.
- Private commands are discoverability control, not access control.
- HTML output in
/helpusesescapeHtmlto prevent injection.