Documentation menu
Getting started
New in v2.0
Feature deep dives
Reference
Dependencies
Dependency & structure atlas
Dependency graph of AutoTelegramForward: every module, resolved import, keystone ranking, cross-subsystem traffic and cycle, derived from the checkout.
Verified against the checkout built for v2.2.4 · updated 20 Oct 2026
On this page
524 modules, 1,869 resolved imports, 8 subsystems and 6 import cycles — counted from this checkout, not from memory. Every node on the map links back to its file on GitHub, so a claim about coupling here can be checked in one click.
How to read the map
One node = one unit of dependency
Python, Dart, Rust and TypeScript nodes are files; Go nodes are packages (a Go file is never a unit of dependency on its own). The legend on the canvas says which is which, per language.
One edge = one resolved import
Edges come from parsing import/from … import, Go import blocks, use/mod statements and relative ES imports, then resolving each specifier against the file index. Anything that resolves outside the repository (a third-party package) is intentionally not drawn.
Size = lines, colour = subsystem
A node grows with the square root of its line count, so a 3,000-line service does not swallow the canvas. Node size is a scale, not a score: coupling is what fan-in and fan-out measure.
The graph
524 modules, laid out by subsystem, relaxed so that linked modules sit near each other — which is why the visual clusters below line up with the architecture rather than with the directory listing. Hover to trace a module's neighbourhood, click to inspect its imports and its dependents.
core/domain/entities.py
view on GitHub ·module (file) · python · 1,842 lines ·106 dependents · 4 imports
Subsystem core. Click any node in the map to inspect its imports and its dependents, and to follow the module back to its source file.
Keystone modules
Ranked by coupling — two points per dependent, one per import — with generated stubs and tests excluded, because a file that 40 other files import is a file nobody can change casually. The top entry alone carries 106 dependents.
Cross-subsystem traffic
Every import that crosses a subsystem boundary. Inside one subsystem the count is deliberately omitted: the interesting question is never "how coupled is the core to itself", it is "which subsystems know about each other".
| From | To | Import links | Signal |
|---|---|---|---|
core | atfcli | 51 | Test suite only — no production import exists |
core | atf.py | 1 | Test suite only — no production import exists |
atf.py | core | 1 | 1 runtime import — shared contract |
atf.py | atfcli | 1 | 1 runtime import — shared contract |
Cycles
Import cycles are found with Tarjan's strongly-connected-components pass over the resolved graph, so this list is exhaustive for the edges the sweep could resolve — not a sample. 6 groups of modules import each other.
5 modules
core/domain/branding.py → core/domain/content_policy.py → core/domain/entities.py → core/domain/media_filter.py → core/domain/services.py
6 modules
atfcli/application/use_cases/__init__.py → atfcli/application/use_cases/admin.py → atfcli/application/use_cases/backup.py → atfcli/application/use_cases/delivery.py → atfcli/application/use_cases/logs.py → atfcli/application/use_cases/sessions.py
5 modules
atfcli/__init__.py → atfcli/api.py → atfcli/cli.py → atfcli/infrastructure/http/gateways.py → atfcli/infrastructure/http/transport.py
9 modules
web/frontend/src/App.tsx → web/frontend/src/panels/AiPanel.tsx → web/frontend/src/panels/DevopsPanel.tsx → web/frontend/src/panels/FiltersPanel.tsx → web/frontend/src/panels/PvPanel.tsx → web/frontend/src/panels/QueuePanel.tsx → web/frontend/src/panels/RulesPanel.tsx → web/frontend/src/panels/SessionsPanel.tsx → web/frontend/src/panels/SimulatorPanel.tsx
Largest modules
Size is not a defect, but it is where a defect hides best. The largest authored module is api/internal/handlers at 11,376 lines with 1 dependents.
| Module | Subsystem | Lines | In / out |
|---|---|---|---|
api/internal/handlers | api | 11,376 | 1 / 5 |
core/infrastructure/telegram/pro_bot_ui.py | core | 10,464 | 44 / 28 |
core/proto/autoforward_pb2_grpc.py | core | 3,333 | 4 / 2 |
api/internal/ratelimit | api | 2,785 | 2 / 1 |
core/infrastructure/persistence/sqlite_repositories.py | core | 2,338 | 59 / 7 |
core/infrastructure/grpc_server/servicers.py | core | 2,154 | 12 / 14 |
web/frontend/src/components/TaskOverviewModal.tsx | web-frontend | 2,152 | 1 / 5 |
web/frontend/src/App.tsx | web-frontend | 2,131 | 9 / 26 |
core/domain/entities.py | core | 1,842 | 106 / 4 |
core/infrastructure/persistence/postgres_repositories.py | core | 1,793 | 12 / 4 |
mobile/lib/core/models.dart | mobile | 1,761 | 18 / 2 |
mobile/lib/features/rules/rule_editor_screen.dart | mobile | 1,470 | 2 / 12 |
Language mix
| Language | Nodes | Source files | Lines | Share |
|---|---|---|---|---|
python | 324 | 324 | 92,431 | |
go | 8 | 77 | 29,711 | |
typescript | 60 | 60 | 25,597 | |
dart | 55 | 55 | 23,577 | |
astro | 75 | 75 | 14,160 | |
proto | 1 | 1 | 1,032 | |
rust | 1 | 1 | 252 |
Python carries 92,431 of those lines across 324 files, which is what "the engine is the product" looks like in numbers.
Loosely coupled ends
Modules with no resolved import in either direction, with package markers (__init__.py), tests and entrypoints already excluded. 1 remains — a module nobody imports and that imports nobody is either an entrypoint or dead weight, and this is the list where that question gets asked.
website · 52 lines
Next: the same components, but as live connections — the 3D connection map draws the 23 links that cross process boundaries, which imports cannot describe. Back to the atlas overview