# Operational Notes This document covers runtime behaviors, limits, and maintenance considerations for operating a cg.cx instance. --- ## Telegram API Rate Limits The bot does **not** implement explicit request throttling for Telegram API calls. It relies on Teloxide's default behavior and the Telegram Bot API flood-control semantics. - **Forwarding / posting messages** — Subject to standard Bot API rate limits (roughly ~30 messages/second in groups, lower in smaller chats). Rapid approval of many submissions may trigger `RetryAfter` errors; the bot currently does not back off explicitly. - **Banning / restricting members** — `banChatMember` and `restrictChatMember` have aggressive per-chat limits. Issuing many punishment commands in quick succession may result in temporary API rejections. - **Message deletion** — `deleteMessage` is limited to ~300 deletions per chat per 24 hours for bots. The automatic service-message cleanup (see below) contributes to this budget. **Operational recommendation:** If running in high-traffic groups, monitor bot logs for `RetryAfter` or `429` errors and consider spacing out bulk operations. --- ## System Message Deletion Limits The bot automatically deletes service messages in groups and channels to reduce noise. In `handle_message_inner`, the following 17 message types are detected and deleted in non-private chats: - `new_chat_members` - `left_chat_member` - `new_chat_title` - `new_chat_photo` - `delete_chat_photo` - `group_chat_created` - `supergroup_chat_created` - `channel_chat_created` - `migrate_to_chat_id` - `migrate_from_chat_id` - `pinned_message` - `video_chat_scheduled` - `video_chat_started` - `video_chat_ended` - `video_chat_participants_invited` - `message_auto_delete_timer_changed` - `proximity_alert_triggered` **Limitations:** - Some service messages (e.g., `channel_chat_created`) **cannot be deleted by bots** and will silently fail. The code handles this with `let _ = bot.delete_message(...).await;`. - Deletion failures do not crash the bot or block subsequent message processing. --- ## Storage & Directories Encrypted content is organized into the following directories (configured in `config/default.toml` under `[storage.paths]`): | Directory | Purpose | |-----------|---------| | `data/media` | Image, video, and audio files (`image/*`, `video/*`, `audio/*`). | | `data/documents` | All other file types (archives, binaries, etc.). | | `data/text` | Plain text uploads (`text/*` MIME types). | | `data/temp` | Temporary files during encryption and upload processing. | | `data/logs` | Rolling log output from the bot and server. | **Directory creation:** Both the bot and server call `storage.ensure_dirs().await` at startup, creating missing directories automatically. --- ## Rolling Log Files Both the bot (`crates/cgcx-bot/src/main.rs`) and the server (`crates/cgcx-server/src/main.rs`) use `tracing-appender` for daily log rotation: ```rust tracing_appender::rolling::Builder::new() .rotation(tracing_appender::rolling::Rotation::DAILY) .filename_prefix(log_prefix) .max_log_files(config.logging.max_files) .build(log_dir) ``` - **Rotation:** Daily. - **Retention:** `max_files` (default: `7`). - **Paths:** - Bot: `data/logs/cgcx-bot.log` (or configured `logging.file_path`) - Server: `data/logs/cgcx-server.log` - **Format:** Plain text, ANSI colors disabled for file output. - **Fallback:** If the rolling appender fails to initialize, the process falls back to console-only logging. --- ## SQLite WAL Mode Every database connection is opened with: ```sql PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000; ``` **Implications:** - **WAL (Write-Ahead Logging)** allows readers to proceed without blocking on writers, which is important because the bot and server may share the same SQLite file. - A `busy_timeout` of 5000 ms reduces "database is locked" errors under concurrent load. - WAL produces companion files (`db.sqlite-wal`, `db.sqlite-shm`) in the same directory as the database. These are safe to leave in place during normal operation and are automatically checkpointed by SQLite. --- ## Background Task Intervals | Task | Interval | Description | |------|----------|-------------| | **Punishment expiration** | 60 seconds | Bot task that queries `punishments` for expired timed bans/mutes and lifts them. | | **Orphan cleanup** | 24 hours | Server task that runs `FilePipeline::cleanup_orphans()` to remove files belonging to deleted/blacklisted content (only if `keep_content = false`). | **Note:** The orphan sweeper skips its first tick on startup to avoid immediate load spikes. --- ## Frontend Chunk Size Warning The frontend build uses Vite with its default configuration. During `npm run build`, Vite may emit warnings such as: ``` (!) Some chunks are larger than 500 kBs after minification. ``` - This is a **non-blocking** warning; the build completes successfully. - The warning typically comes from large vendor dependencies (e.g., PDF.js, syntax highlighters). - No custom `chunkSizeWarningLimit` is configured; the default Vite behavior is accepted. --- ## HTTP Rate Limiting (Server) The Axum server uses `tower-governor` for per-IP rate limiting: | Route Group | Config Key | Default | Burst | |-------------|-----------|---------|-------| | General API (`/api/health`, `/api/content/...`) | `rate_limiting.requests_per_minute` | 60 | 10 | | Password verification (`POST /api/content/:cxid/verify-password`) | `rate_limiting.password_attempts_per_minute` | 4 | 3 | - Exceeding the general limit returns `429 Too Many Requests`. - The password endpoint has a separate, stricter limit to mitigate brute-force attacks.