roleping-bot/CLAUDE.md
devilreef 1eb2200fbe feat: config management
fuck it we're vibecoding now
2025-11-28 13:41:13 +06:00

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