{"id":50614472,"url":"https://github.com/dary1337/dstgbottemplate","last_synced_at":"2026-06-06T07:02:05.661Z","repository":{"id":359552743,"uuid":"1246093415","full_name":"dary1337/dsTgBotTemplate","owner":"dary1337","description":"Discord + Telegram bots in one TypeScript codebase on MongoDB — schema-validated (zod), with real migrations, structured logging and a Docker deploy guide","archived":false,"fork":false,"pushed_at":"2026-05-22T12:23:30.000Z","size":120,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T17:21:30.132Z","etag":null,"topics":["boilerplate","bot-template","discord-bot","discord-js","mongodb","telegraf","telegram-bot","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dary1337.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T21:40:17.000Z","updated_at":"2026-05-22T12:23:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dary1337/dsTgBotTemplate","commit_stats":null,"previous_names":["dary1337/dstgbottemplate"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dary1337/dsTgBotTemplate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dary1337%2FdsTgBotTemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dary1337%2FdsTgBotTemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dary1337%2FdsTgBotTemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dary1337%2FdsTgBotTemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dary1337","download_url":"https://codeload.github.com/dary1337/dsTgBotTemplate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dary1337%2FdsTgBotTemplate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33972398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boilerplate","bot-template","discord-bot","discord-js","mongodb","telegraf","telegram-bot","typescript"],"created_at":"2026-06-06T07:02:04.563Z","updated_at":"2026-06-06T07:02:05.655Z","avatar_url":"https://github.com/dary1337.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![ds-tg-bot-template](docs/cover.png)\n\n# ds-tg-bot-template\n\nDiscord **and** Telegram bots in one TypeScript codebase, backed by MongoDB. One process,\nboth platforms, a shared data layer that zod validates (types, runtime checks, and a\ngenerated MongoDB validator), with tracked migrations. Each bot runs isolated, so one\ncrashing doesn't take the other down.\n\n![Node 22](https://img.shields.io/badge/node-22_LTS-339933?logo=node.js\u0026logoColor=white)\n![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript\u0026logoColor=white)\n![License: MIT](https://img.shields.io/badge/license-MIT-blue)\n\n**Stack:** Node 22, TypeScript (ESM, strict), discord.js, Telegraf, MongoDB (raw driver),\nZod, Pino, Docker.\n\nThe core is small on purpose: both bots start, connect to Mongo, run migrations, and\nanswer a `/ping`. Anything opinionated (role panels, broadcasts, admin menus, cron jobs,\nmulti-bot) lives in [`examples/`](examples) as copy-in code.\n\n## Get your tokens\n\nYou need at least one (both are free):\n\n- **Telegram:** message [@BotFather](https://t.me/BotFather), send `/newbot`, put the\n  token in `TG_BOT_TOKEN`.\n- **Discord:** [Developer Portal](https://discord.com/developers/applications) → New\n  Application → **Bot** → put the token in `DS_BOT_TOKEN`. Invite the bot via\n  **OAuth2 → URL Generator** with scopes `bot` + `applications.commands`.\n\n## Quick start\n\nNo MongoDB installed? Use Docker, it runs the database for you.\n\n**Docker (recommended):**\n\n```bash\ncp .env.sample .env        # add a token first\ndocker compose up --build\n```\n\nBuilds the bot, starts MongoDB, runs migrations, launches both bots. `Ctrl+C` to stop,\n`-d` to run in the background.\n\n**Local Node (you already have MongoDB):**\n\n```bash\nnpm install\ncp .env.sample .env        # MONGO_URI already points at local Mongo\nnpm run dev\n```\n\n## Stuck?\n\n[Open an issue](../../issues) with the log output. It's usually a bad token (the app says\nso on startup) or MongoDB not running (use Docker).\n\n## Scripts\n\n```bash\nnpm run dev          # watch mode\nnpm run lint\nnpm run format:check # `npm run format` to fix\nnpm run typecheck    # src, tests and examples\nnpm test\nnpm run build\n```\n\nDeploying to a VPS (Docker, no PM2): [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).\n\n## Project layout\n\n```\nsrc/\n  index.ts              bootstrap: env -\u003e db -\u003e schema -\u003e migrations -\u003e bots\n  config/env.ts         zod-validated environment\n  logger/logger.ts      pino logger (stdout + rotating files)\n  db/\n    db.ts               connect, typed collections, syncSchema\n    collection.ts       defineCollection() helper\n    schema/             one zod schema + indexes per collection\n    repositories/       data access built on the schema types\n    migrations/runner.ts runs tracked migrations\n  _migrations/          NNN_name.ts migration files\n  ds-bot/               Discord: client init, slash commands\n  tg-bot/               Telegram: init, admin-only middleware, commands\nexamples/               copy-in features\n```\n\n## The schema layer\n\nA collection is defined once:\n\n```ts\n// src/db/schema/admins.ts\nexport const adminSchema = z.object({ platform: z.enum(['telegram', 'discord']), userId: z.string() /* ... */ });\nexport type Admin = z.infer\u003ctypeof adminSchema\u003e;\nexport const adminsCollection = defineCollection({\n    name: 'admins',\n    schema: adminSchema,\n    indexes: [{ key: { platform: 1, userId: 1 }, unique: true }],\n});\n```\n\nRegister it in `src/db/schema/index.ts` and add a typed accessor in `buildCollections`\n(`src/db/db.ts`). On startup `syncSchema` creates the indexes and applies a MongoDB\n`$jsonSchema` validator generated from the same zod schema, so the database rejects bad\ndocuments even on writes that bypass the repositories (which validate too). Adding a\nfield is a one-file change.\n\n## Migrations\n\nFiles live in `src/_migrations/` as `NNN_snake_case.ts`. Each exports an async `up`\n(and optional `down`), gets the raw `Db` handle, and is recorded in the `migrations`\ncollection so it runs once. Use them for data changes (backfills, renames); for index\nchanges just edit the schema. See [examples/mongo-migrations](examples/mongo-migrations).\n\n`001_seed_admins.ts` seeds the first Telegram admins from `SEED_TG_ADMIN_IDS` on first run.\n\n## Why raw MongoDB (not Mongoose / Prisma)\n\n- One source of truth: a zod schema gives the TypeScript type, runtime validation, and\n  the MongoDB `$jsonSchema` validator. Mongoose adds a second schema to keep in sync,\n  Prisma a third (its DSL + codegen).\n- Validation lives in the database, not only in app code.\n- Plain driver queries, no ORM abstraction, lightest footprint.\n\nWant Mongoose anyway? [examples/mongoose-model](examples/mongoose-model) shows how to use\nit for one collection without touching the rest.\n\n## Environment\n\nAt least one bot token is required.\n\n| Variable | Required | Description |\n| --- | --- | --- |\n| `MONGO_URI` | yes | MongoDB connection string (default `mongodb://127.0.0.1:27017`) |\n| `MONGO_DB_NAME` | yes | Database name (default `ds-tg-bot-template`) |\n| `DS_BOT_TOKEN` | one of | Discord bot token |\n| `TG_BOT_TOKEN` | one of | Telegram bot token |\n| `SEED_TG_ADMIN_IDS` | no | Comma-separated Telegram user IDs seeded as admins |\n| `LOG_LEVEL` | no | `fatal\\|error\\|warn\\|info\\|debug\\|trace\\|silent` (default `info`) |\n| `LOG_DIR` | no | Log directory (default `logs`) |\n\n`DB_URI` / `DB_NAME` work as aliases for `MONGO_URI` / `MONGO_DB_NAME`.\n\n## Examples\n\n[`examples/`](examples) has copy-in features: role panel, broadcasts, moderation queue,\nwelcome + analytics, language roles, cooldowns, i18n, multi-bot, migrations, and more.\nEach folder has a short README and notes where its files go.\n\n## License\n\nMIT, see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdary1337%2Fdstgbottemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdary1337%2Fdstgbottemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdary1337%2Fdstgbottemplate/lists"}