# Architecture High-level architecture of Duty Teller: components, data flow, and package relationships. ## Components - **Bot** — [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) v22 (Application API). Handles commands and group messages; runs in polling mode. - **FastAPI** — HTTP server: REST API (`/api/duties`, `/api/calendar-events`, `/api/calendar/ical/{token}.ics`) and static miniapp at `/app`. Runs in a separate thread alongside the bot. - **Database** — SQLAlchemy ORM with Alembic migrations. Default backend: SQLite (`data/duty_teller.db`). Stores users, duties (with event types: duty, unavailable, vacation), group duty pins, calendar subscription tokens. - **Duty-schedule import** — Two-step admin flow: handover time (timezone → UTC), then JSON file. Parser produces per-person date lists; import service deletes existing duties in range and inserts new ones. - **Group duty pin** — In groups, the bot can pin the current duty message; time/timezone for the pinned text come from `DUTY_DISPLAY_TZ`. Pin state is restored on startup from the database. ## Data flow - **Telegram → bot** User/group messages → handlers → services or DB. Handlers use `duty_teller.services` (e.g. import, group duty pin) and `duty_teller.db` (repository, session). Messages use `duty_teller.i18n` for Russian/English. - **Miniapp → API** Browser opens `/app`; frontend calls `GET /api/duties` and `GET /api/calendar-events` with date range. FastAPI dependencies: DB session, Telegram initData validation (`require_miniapp_username`), date validation. Data is read via `duty_teller.db.repository`. - **Import** Admin sends JSON file via `/import_duty_schedule`. Handler reads file → `duty_teller.importers.duty_schedule.parse_duty_schedule()` → `DutyScheduleResult` → `duty_teller.services.import_service.run_import()` → repository (`get_or_create_user_by_full_name`, `delete_duties_in_range`, `insert_duty`). - **Personal calendar ICS** `GET /api/calendar/ical/{token}.ics` uses the secret token only (no Telegram auth); repository resolves user by token and returns duties; `personal_calendar_ics.build_personal_ics()` produces ICS bytes. ## Package layout ```mermaid flowchart LR subgraph entry main[main.py / duty-teller] end subgraph duty_teller run[run.py] config[config.py] handlers[handlers] api[api] db[db] services[services] importers[importers] i18n[i18n] utils[utils] end main --> run run --> config run --> handlers run --> api handlers --> services handlers --> db handlers --> i18n api --> db api --> config services --> db services --> importers importers --> . ``` - **handlers** — Telegram command and message handlers; call `services` and `db`, use `i18n` for user-facing text. - **api** — FastAPI app, dependencies (auth, DB session, date validation), calendar ICS builders; uses `db.repository` and `config`. - **db** — Models, session (`session_scope`), repository (CRUD for users, duties, pins, calendar tokens), schemas for API. - **services** — Business logic (import, group duty pin); receive DB session from caller, use `importers` for parsing. - **importers** — Duty-schedule JSON parser; no DB access, returns structured result. - **i18n** — Translations and language detection (ru/en) for bot and API. - **utils** — Shared helpers (dates, user, handover). See [Project layout](../README.md#project-layout) in README for file-level details.