--- description: Overall project architecture and context for duty-teller globs: - "**" --- # Project — duty-teller A Telegram bot for team duty shift calendar management and group reminders, with a Telegram Mini App (webapp) for calendar visualization. ## Architecture ``` ┌──────────────┐ polling ┌──────────────────────┐ │ Telegram │◄────────────►│ python-telegram-bot │ │ Bot API │ │ (handlers/) │ └──────────────┘ └──────────┬───────────┘ │ ┌──────────────┐ HTTP ┌──────────▼───────────┐ │ Telegram │◄────────────►│ FastAPI (api/) │ │ Mini App │ initData │ + static webapp │ │ (webapp-next/) │ auth └──────────┬───────────┘ └──────────────┘ │ ┌──────────▼───────────┐ │ SQLite + SQLAlchemy │ │ (db/) │ └──────────────────────┘ ``` - **Bot:** python-telegram-bot v22, async polling mode. - **API:** FastAPI served by uvicorn in a daemon thread alongside the bot. - **Database:** SQLite via SQLAlchemy 2.x ORM; Alembic for migrations. - **Frontend:** Next.js (TypeScript, Tailwind, shadcn/ui) static export at `/app`; source in `webapp-next/`. ## Key packages | Package | Role | |---------|------| | `duty_teller/handlers/` | Telegram bot command and message handlers | | `duty_teller/api/` | FastAPI app, REST endpoints, Telegram initData auth, ICS feeds | | `duty_teller/db/` | ORM models, repository (CRUD), session management, Pydantic schemas | | `duty_teller/services/` | Business logic (import, duty pin) — receives Session | | `duty_teller/importers/` | Duty schedule file parsers | | `duty_teller/i18n/` | Bilingual translations (ru/en), `t()` function | | `duty_teller/utils/` | Date helpers, user utilities, HTTP client | | `duty_teller/cache.py` | TTL caches with pattern-based invalidation | | `duty_teller/config.py` | Environment-based configuration | | `webapp-next/` | Telegram Mini App (Next.js, Tailwind, shadcn/ui; build → `out/`) | ## API endpoints | Method | Path | Auth | Purpose | |--------|------|------|---------| | GET | `/health` | None | Health check | | GET | `/api/duties` | initData | Duties for date range | | GET | `/api/calendar-events` | initData | External calendar events | | GET | `/api/calendar/ical/team/{token}.ics` | Token | Team ICS feed | | GET | `/api/calendar/ical/{token}.ics` | Token | Personal ICS feed | | GET | `/app` | None | Static Mini App (HTML/JS/CSS) | ## Deployment - **Docker:** Multi-stage build (`Dockerfile`), `docker-compose.prod.yml` for production. - **Entrypoint:** `entrypoint.sh` runs `alembic -c pyproject.toml upgrade head`, then starts `python main.py` as `botuser`. - **Data:** SQLite DB persisted via Docker volume at `/app/data`. - **Health:** `curl -f http://localhost:8080/health` every 30 s. ## CI/CD (Gitea Actions) ### Lint & test (`.gitea/workflows/ci.yml`) Triggered on push/PR to `main` and `develop`: 1. **Ruff:** `ruff check duty_teller tests` 2. **Pytest:** `pytest tests/ -v` (80% coverage gate) 3. **Bandit:** `bandit -r duty_teller -ll` (security scan) ### Docker build & release (`.gitea/workflows/docker-build.yml`) Triggered on `v*` tags: 1. Build and push image to Gitea registry. 2. Create release with auto-generated notes. ## Key environment variables | Variable | Default | Required | Purpose | |----------|---------|----------|---------| | `BOT_TOKEN` | — | Yes | Telegram bot API token | | `DATABASE_URL` | `sqlite:///data/duty_teller.db` | No | SQLAlchemy database URL | | `MINI_APP_BASE_URL` | — | Yes (prod) | Public URL for the Mini App | | `HTTP_HOST` | `127.0.0.1` | No | FastAPI bind host | | `HTTP_PORT` | `8080` | No | FastAPI bind port | | `ADMIN_USERNAMES` | — | No | Comma-separated admin Telegram usernames | | `ALLOWED_USERNAMES` | — | No | Comma-separated allowed usernames | | `DUTY_DISPLAY_TZ` | `Europe/Moscow` | No | Timezone for duty display | | `DEFAULT_LANGUAGE` | `en` | No | Default UI language (`en` or `ru`) | | `EXTERNAL_CALENDAR_ICS_URL` | — | No | External ICS URL for holidays | | `CORS_ORIGINS` | `*` | No | Comma-separated CORS origins | ## Languages - **Backend:** Python 3.12+ - **Frontend:** Next.js (TypeScript), Tailwind CSS, shadcn/ui; Vitest for tests - **i18n:** Russian (default) and English ## Version control - Git with Gitea Flow branching strategy. - Conventional Commits for commit messages. - PRs reviewed via Gitea Pull Requests.