117 lines
6 KiB
Markdown
117 lines
6 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
A Telegram bot built with GramIO that enables role-based mentions in group chats. Users can create custom roles, join/leave them, and mention all role members at once using @mentions or commands.
|
|
|
|
## Development Commands
|
|
|
|
- `pnpm dev` - Run bot in development mode with hot reload
|
|
- `pnpm start` - Run bot in production mode
|
|
- `pnpm drizzle-kit generate --config=src/shared/database/config.ts` - Generate database migrations after schema changes
|
|
- `pnpm drizzle-kit migrate --config=src/shared/database/config.ts` - Apply pending migrations to database
|
|
- `pnpm drizzle-kit studio --config=src/shared/database/config.ts` - Open Drizzle Studio for database inspection
|
|
|
|
## Architecture
|
|
|
|
### Core Components
|
|
|
|
**Bot Entry Point** (`src/index.ts` → `src/bot/index.ts`)
|
|
- Bot initialization uses GramIO framework
|
|
- Commands are auto-loaded from `src/bot/commands/` using `@gramio/autoload`
|
|
- Two middleware handlers in `src/bot/index.ts`:
|
|
1. Message handler for @mention syntax (e.g., `@rolename`) - triggers role mentions
|
|
2. Command handler for bare commands (e.g., `/rolename`) - also triggers role mentions
|
|
- Bot username is captured on startup to properly handle commands with @botname suffix
|
|
|
|
**Database** (PostgreSQL with Drizzle ORM)
|
|
- Schema defined in `src/shared/database/schema.ts`
|
|
- Three tables: `roles` (id, slug, aliases, chatId), `role_members` (id, roleId, userId), and `chat_configs` (id, chatId, roleManagePermission, roleMentionPermission)
|
|
- Configuration in `src/shared/database/config.ts`
|
|
- Path aliases use `@/*` mapping to `./src/*`
|
|
|
|
**Services** (`src/shared/services/`)
|
|
- `RoleService` - All role and role member database operations
|
|
- `MentionService` - Handles mentioning all members of a role
|
|
- Chunks members into groups of 5 to avoid hitting Telegram's limits
|
|
- Builds mention entities using GramIO's `mention()` helper
|
|
- Sends multiple messages if role has >5 members, with pagination indicators
|
|
- `ChatConfigService` - Manages per-chat permission configuration
|
|
- Lazy initialization via `getOrCreate()` - configs created on first access
|
|
- Defaults: `all_admins` for role management, `everyone` for mentions
|
|
- `PermissionService` - Centralized permission checking logic
|
|
- `canManageRoles()` - Checks if user can add/delete roles based on chat config
|
|
- `canMentionRoles()` - Checks if user can trigger role mentions based on chat config
|
|
|
|
**Commands** (`src/bot/commands/`)
|
|
- Admin commands require chat admin permissions (checked via `isChatAdmin()`)
|
|
- `/roleadd <name>` - Create new role (permission configurable, updates bot commands dynamically)
|
|
- `/roledel` - Delete role (permission configurable)
|
|
- `/join <name>` - Join a role (always available to everyone)
|
|
- `/leave <name>` - Leave a role (always available to everyone)
|
|
- `/myroles` - List your roles
|
|
- `/roles` - List all roles in chat
|
|
- `/config` - View and configure permissions (any admin can view, owner can change via inline buttons)
|
|
- `/reload` - Refresh admin cache (any admin)
|
|
|
|
**Role Triggering**
|
|
- Roles can be triggered two ways:
|
|
1. Via @mention in any message (e.g., "hey @developers")
|
|
2. Via bare command (e.g., "/developers" or "/developers@botname")
|
|
- Both methods call `MentionService.mentionAll()`
|
|
|
|
**Utilities**
|
|
- `src/bot/utilities/perms.ts` - Permission checking utilities
|
|
- `isChatAdmin()` - Checks if user is admin (uses 1-hour cache)
|
|
- `isChatOwner()` - Checks if user is chat creator/owner
|
|
- `getAdminInfo()` - Returns detailed admin info with granular permissions
|
|
- `hasAdminPermission()` - Checks specific Telegram admin permissions (can_promote_members, can_change_info, can_manage_chat)
|
|
- `refreshAdminCache()` - Clears admin cache for a specific chat
|
|
- Admin cache: 1-hour TTL to reduce Telegram API calls, falls back to stale data on error
|
|
- Handles hidden admins including anonymous admin bot ID 1087968824
|
|
- `src/bot/utilities/constants.ts` - Role name validation regex and reserved command names
|
|
- `src/shared/utilities/chunk.ts` - Array chunking utility for member batching
|
|
|
|
### Important Patterns
|
|
|
|
**Permission System**
|
|
- Chat owners can configure permissions via `/config` command with inline keyboard navigation
|
|
- Role management options: `everyone`, `all_admins`, `admin_can_promote_members`, `admin_can_change_info`, `admin_can_manage_chat`, `only_owner`
|
|
- Role mention options: `everyone`, `all_admins`, `only_owner`
|
|
- Permissions checked via `PermissionService` which consults `chat_configs` table
|
|
- Join/leave functionality always available to everyone (no configuration)
|
|
- Admin cache with 1-hour TTL reduces Telegram API calls - use `/reload` to manually refresh
|
|
|
|
**Role Name Validation**
|
|
- Must match `ROLE_NAME_REGEX`: 4-32 characters, letters only
|
|
- Cannot use `RESERVED_NAMES` (built-in command names)
|
|
|
|
**Chat Scope**
|
|
- All roles are scoped to `chatId` - same role name can exist in different chats
|
|
- Bot only works in groups/supergroups, not private chats
|
|
|
|
**Dynamic Command Registration**
|
|
- When admin creates/deletes roles, bot updates chat-specific command list via `setMyCommands()` with scope type 'chat'
|
|
- This allows autocomplete for role names in that specific chat
|
|
|
|
**Environment Variables**
|
|
- Required: `DATABASE_URL`, `BOT_TOKEN`
|
|
- Optional: `NODE_ENV` (defaults to 'production')
|
|
- Loaded via Node's `loadEnvFile()` from `.env` file
|
|
|
|
### Database Migrations
|
|
|
|
After modifying `src/shared/database/schema.ts`, generate and apply migrations using drizzle-kit with the explicit config path:
|
|
- `pnpm drizzle-kit generate --config=src/shared/database/config.ts`
|
|
- `pnpm drizzle-kit migrate --config=src/shared/database/config.ts`
|
|
|
|
The migration output directory is `./drizzle/`.
|
|
|
|
**Current Schema:**
|
|
- `roles` - Role definitions with slug, aliases, and chatId
|
|
- `role_members` - User memberships in roles
|
|
- `chat_configs` - Per-chat permission configuration (lazy-initialized)
|
|
- Enums: `role_manage_permission` and `role_mention_permission`
|
|
- Default values ensure backwards compatibility with existing chats
|