Files
duty-teller/docs/architecture.md
Nikolay Tatarinov c390a4dd6e feat: implement admin panel functionality in Mini App
- Added new API endpoints for admin features: `GET /api/admin/me`, `GET /api/admin/users`, and `PATCH /api/admin/duties/:id` to manage user duties.
- Introduced `UserForAdmin` and `AdminDutyReassignBody` schemas for handling admin-related data.
- Updated documentation to include Mini App design guidelines and admin panel functionalities.
- Enhanced tests for admin API to ensure proper access control and functionality.
- Improved error handling and localization for admin actions.
2026-03-06 09:57:26 +03:00

4.6 KiB

Architecture

High-level architecture of Duty Teller: components, data flow, and package relationships.

Components

  • Botpython-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 (built from webapp-next/, Next.js static export). 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. When the duty changes on schedule, the bot sends a new message, unpins the previous one and pins the new one; if DUTY_PIN_NOTIFY is enabled (default), pinning the new message triggers a Telegram notification for members. The first pin (bot added to group or /pin_duty) is always silent.

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.

  • Admin panel (Mini App)
    Admins see an "Admin" link on the calendar (when GET /api/admin/me returns is_admin: true). The admin page at /app/admin lists duties for the current month and allows reassigning a duty to another user. It uses GET /api/admin/users (admin-only) for the user dropdown and PATCH /api/admin/duties/:id with { user_id } to reassign. All admin endpoints require valid initData; /users and PATCH /duties additionally require the user to have the admin role (require_admin_telegram_id). PATCH error messages (e.g. duty not found, user not found) use the request Accept-Language header for i18n. The reassign dropdown shows only users with role user or admin (role_id 1 or 2 per migration 007).

  • Import
    Admin sends JSON file via /import_duty_schedule. Handler reads file → duty_teller.importers.duty_schedule.parse_duty_schedule()DutyScheduleResultduty_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

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 in README for file-level details.