- Replaced the previous webapp with a new Mini App built using Next.js, improving performance and maintainability. - Updated the `.gitignore` to exclude Next.js build artifacts and node modules. - Revised documentation in `AGENTS.md`, `README.md`, and `architecture.md` to reflect the new Mini App structure and technology stack. - Enhanced Dockerfile to support the new build process for the Next.js application. - Updated CI workflow to build and test the Next.js application. - Added new configuration options for the Mini App, including `MINI_APP_SHORT_NAME` for improved deep linking. - Refactored frontend testing setup to accommodate the new structure and testing framework. - Removed legacy webapp files and dependencies to streamline the project.
6.1 KiB
Configuration reference
All configuration is read from the environment (e.g. .env via python-dotenv). Source of truth: duty_teller/config.py and Settings.from_env().
| Variable | Type / format | Default | Description |
|---|---|---|---|
| BOT_TOKEN | string | (empty) | Telegram bot token from @BotFather. Required for the bot to run; if unset, the entry point exits with a clear message. The server that serves the Mini App API must use the same token as the bot; otherwise initData validation returns hash_mismatch. |
| DATABASE_URL | string (SQLAlchemy URL) | sqlite:///data/duty_teller.db |
Database connection URL. Should start with sqlite:// or postgresql://; a warning is logged at startup if the format is unexpected. Example: sqlite:///data/duty_teller.db. |
| MINI_APP_BASE_URL | string (URL, no trailing slash) | (empty) | Base URL of the miniapp (for documentation and CORS). Trailing slash is stripped. Example: https://your-domain.com/app. |
| MINI_APP_SHORT_NAME | string | (empty) | Short name of the Web App in BotFather (e.g. DutyApp). When set, the pinned duty message "View contacts" button uses a direct Mini App link https://t.me/BotName/ShortName?startapp=duty so the app opens on the current-duty view. If unset, the button uses https://t.me/BotName?startapp=duty (user may land in bot chat first). |
| HTTP_HOST | string | 127.0.0.1 |
Host to bind the HTTP server to. Use 127.0.0.1 to listen only on localhost; use 0.0.0.0 to accept connections from all interfaces (e.g. when behind a reverse proxy on another machine). |
| HTTP_PORT | integer (1–65535) | 8080 |
Port for the HTTP server (FastAPI + static webapp). Invalid or out-of-range values are clamped; non-numeric values fall back to 8080. |
| ALLOWED_USERNAMES | comma-separated list | (empty) | Not used for access. Kept for reference only. Access to the miniapp is controlled by roles in the DB (assigned by an admin via /set_role). |
| ADMIN_USERNAMES | comma-separated list | (empty) | Telegram usernames treated as admin fallback when the user has no role in the DB. If a user has a role in the DB, only that role applies. Example: admin1,admin2. |
| ALLOWED_PHONES | comma-separated list | (empty) | Not used for access. Kept for reference only. |
| ADMIN_PHONES | comma-separated list | (empty) | Phones treated as admin fallback when the user has no role in the DB (user sets phone via /set_phone). Comparison uses digits only. Example: +7 999 123-45-67. |
| MINI_APP_SKIP_AUTH | 1, true, or yes |
(unset) | If set, /api/duties and /api/calendar-events are allowed without Telegram initData. Dev only — never use in production. The process exits with an error if this is set and HTTP_HOST is not localhost (127.0.0.1). |
| INIT_DATA_MAX_AGE_SECONDS | integer (≥ 0) | 0 |
Reject Telegram initData older than this many seconds. 0 = disabled. Invalid values fall back to 0. Example: 86400 for 24 hours. |
| CORS_ORIGINS | comma-separated list | * |
Allowed origins for CORS. Leave unset or set to * for allow-all. In production, set an explicit list (e.g. https://your-domain.com) instead of * to avoid allowing arbitrary origins. Example: https://your-domain.com. |
| EXTERNAL_CALENDAR_ICS_URL | string (URL) | (empty) | URL of a public ICS calendar (e.g. holidays). If set, those days are highlighted on the duty grid; users can tap "i" on a cell to see the event summary. Empty = no external calendar. |
| DUTY_DISPLAY_TZ | string (timezone name) | Europe/Moscow |
Timezone for the pinned duty message in groups. Example: Europe/Moscow, UTC. |
| DUTY_PIN_NOTIFY | 0, false, or no to disable |
1 (enabled) |
When the pinned duty message is updated on schedule, the bot sends a new message, unpins the old one and pins the new one. If enabled, pinning the new message sends a Telegram notification (“Bot pinned a message”). Set to 0, false, or no to pin without notification. The first pin (e.g. when the bot is added to the group or on /pin_duty) is always silent. |
| DEFAULT_LANGUAGE | en or ru (normalized) |
en |
Single source of language for the whole deployment: bot messages, API error texts, and Mini App UI all use this value. No auto-detection from Telegram user, browser, or Accept-Language. Values starting with ru are normalized to ru; anything else becomes en. |
| LOG_LEVEL | DEBUG, INFO, WARNING, or ERROR |
INFO |
Logging level for the backend (Python logging) and for the Mini App console logger (window.__DT_LOG_LEVEL). Use DEBUG for troubleshooting; in production INFO or higher is recommended. |
Roles and access
Access to the calendar miniapp and admin actions is determined by roles stored in the database (table roles, link users.role_id). Roles: user (miniapp access) and admin (miniapp + /import_duty_schedule, /set_role). An admin assigns roles with /set_role @username user|admin (or by replying to a message with /set_role user|admin). If a user has no role in the DB, they are treated as admin only if they are listed in ADMIN_USERNAMES or ADMIN_PHONES (env fallback). ALLOWED_USERNAMES and ALLOWED_PHONES are not used for access.
Quick setup
- Copy
.env.exampleto.env. - Set
BOT_TOKENto the token from BotFather. - Set
ADMIN_USERNAMES(and optionallyADMIN_PHONES) so that at least one admin can use the bot and assign roles via/set_role.
For Mini App URL and production deployment notes (reverse proxy, initData), see the README Setup and Docker sections.
Production: HTTPS
In production the application must be served over HTTPS (e.g. behind a reverse proxy such as nginx or Caddy with TLS). Without HTTPS, the Telegram Mini App initData and the calendar subscription token are sent in the clear; an attacker on the same network could capture them and gain access to the calendar or impersonate the user. Deploy the HTTP server behind a proxy that terminates TLS and forwards requests to the app.