Architecture: Components
Gateway layer
TDLibListChatsConsumer
- File:
backend/tg_client/dialogs/ws/list_chats/consumers.py - Role:
- WebSocket entry point
- targeted live subject subscription
open_clientsnapshot + replay recovery- command forwarding into owner runtime
- Receives:
- JSON messages from WebSocket client
- live NATS events for subscribed
userbot_idvalues - Emits:
- WebSocket
chat_updateframes - command envelopes through
publish_command() - Depends on:
publish_commandCacheProjectionUpdaterReplayServiceconnect_nats_client
commands.registry
- Files:
backend/tg_client/dialogs/commands/registry.pybackend/tg_client/dialogs/commands/context.py- Role:
- registry of all handler groups
- build per-command context
- dispatch by
payload.command - Interaction:
- called only from owner runtime
- returns
Falsewhen command is unsupported, which leads to<command>_error
Composition root
TdlibFacade
- File:
backend/tg_client/dialogs/tdlib/facade.py - Role:
- assemble APIs, services,
Channel, andMessage - Receives:
- raw TDLib transport object (
tg) userbot_id- Returns:
api.*services.*channelmessage
TdlibBaseClient
- File:
backend/tg_client/dialogs/tdlib/base.py - Role:
- only transport wrapper around
tg.call_method() - serializes byte payloads to base64 for TDLib JSON values
- Returns:
{ok, result, error}- Error model:
- string-only errors, no stable numeric code layer in this wrapper
Application layer
tdlib/api/*
Raw wrappers grouped by TDLib domain:
chats.pydialogs.pymessages.pymembers.pyprofiles.pysettings.pysecurity.pychat_settings.pychat_lists.pyinvites.pystickers.pyfiles.pyemojis.pytopics.py
Rules that are visible in code:
- no business logic should live here
- each method returns transport-shaped
{ok, result, error} - domain grouping is used instead of one-file-per-command
tdlib/services/*
Business logic layer used by handlers.
Examples:
ChatServicefilters and normalizes chat listsDialogServiceorchestratesopen_dialogQueryServicebuilds search resultsMessageCommandServicebuilds TDLib message input payloadsSettingsServiceconverts privacy/session requests into TDLib-compatible payloadsMembershipServicemerges chat/member lookups and enriches recent actions
tdlib/normalizers/*
Typed result builders.
Common patterns in code:
- enrich raw TDLib payloads with app-specific metadata
- unify shapes reused by several handlers
- attach counts, snapshots, user references, member payloads, etc.
Shared typed payload layer
dialogs/domain/*
Current purpose in code:
- reusable message/chat/profile builders
- typed nested payload fragments (
sender,message,reply,forward,reactions,membership,topic,preview) - no direct transport ownership
Key files:
domain/message.pydomain/channel.pydomain/chat_profile.py- component files under
domain/message_*anddomain/channel_* domain/ws_components.py
Runtime & update processing
UpdateRuntimeService
- File:
backend/tg_client/dialogs/services/update_runtime_service.py - Role:
- TDLib update processing inside owner runtime
- calls
UpdateNormalizer - writes projections to
DialogCache - emits live events synchronously
UpdateQueueProcessor
- File:
backend/tg_client/dialogs/services/update_queue.py - Role:
- threaded queue / worker wrapper between TDLib callback thread and runtime processing
- typed degradation / queue control lives here
Storage and auxiliary infrastructure
DialogCache
- File:
backend/tg_client/dialogs/cache/dialog_cache.py - Role:
- dialog page cache
- user/chat/file cache
- per-account snapshot
- recent event replay buffer
- Backing store:
- Django
cache; concrete backend is outside this module and requires environment verification
Media pipeline
services/media_loader.pytdlib/services/file_service.pytdlib/services/custom_emoji_service.pyservices/save_to_cloud.pyservices/file_generation.py
This group covers:
- file lookup in cache/cloud
- fallback Telegram download
- generated file handling for TDLib
- presigned upload/download URLs and storage keys
Persistence layer used by dialogs runtime
- File:
backend/tg_client/models.py - Relevant models:
UserBotCustomEmojiCommandExecution
These models are not full repositories; the dialogs subsystem accesses them directly through services/runtime code.