- Node.js ≥ 20 (tested on 24.x)
- pnpm ≥ 9
- A dedicated Telegram account for forwarding — not your main one. gramjs shares the session across the whole account, and Telegram readily classifies a userbot as spam, so keep it isolated.
pnpm install
cp .env.example .env
pnpm db:migrate # apply DB migrations (idempotent)Fill in .env (at minimum TG_API_ID, TG_API_HASH, WEB_PASSWORD, SESSION_SECRET),
then mint a session string for the forwarding account:
pnpm tg:login # interactive: phone → code → 2FA → prints session string
# paste it into .env as TG_SESSION_STRING
pnpm dev # boots server + web in parallelMTProto separates the application from the account:
TG_API_ID+TG_API_HASHidentify the application (like an OAuthclient_id/client_secret), minted once at https://my.telegram.org. They survive any change of forwarding account.TG_SESSION_STRINGis the result of logging in (phone → code → 2FA): "this application, signed in as this account." It's the variable part.
gramjs is a library, not an official client, so it has no api_id of its own — Telegram
requires every developer to register their own application. (The Bot API would fold both
into a single bot_token, but bots can't read channels without admin rights, which is
why tg-feed uses a userbot/MTProto instead.)
Before opening a PR, make sure these pass — CI runs all of them:
pnpm lint # ESLint
pnpm format # Prettier (or pnpm format:check)
pnpm typecheck # tsc --noEmit in every workspace
pnpm test # Vitest across all workspaces
pnpm build # server (tsc) + web (Vite)A pre-commit hook runs lint-staged (ESLint + Prettier on staged files) automatically.
- TypeScript strict, no
any. Useimport typefor type-only imports. apps/server/src/config.tsis the only module that readsprocess.env— everything else imports the parsedconfigobject.- Cross-network types and Zod schemas live in
packages/sharedand are imported by both the server and the web client. Add new DTOs there, not in one app. - Logging uses pino (
apps/server/src/lib/logger.ts); sensitive fields are redacted. Transient/network errors log atwarn, unrecoverable ones aterror.
- Branch off
master. - Keep changes focused; one logical change per PR.
- Ensure all checks above pass.
- Describe what changed and why in the PR body.
Please do not file public issues for security problems — see SECURITY.md.