Some checks failed
CI / lint-and-test (push) Failing after 23s
- Added *.egg-info/ to .gitignore to prevent egg metadata from being tracked. - Updated virtual environment instructions in CONTRIBUTING.md and README.md to use .venv for consistency. - Revised mkdocs.yml to include a placeholder for the repository URL when publishing. - Cleaned up pyproject.toml by removing unnecessary pylint configuration. - Enhanced import-format.md and runbook.md documentation for clarity on user roles and health check endpoints.
84 lines
4.9 KiB
Markdown
84 lines
4.9 KiB
Markdown
# Runbook (operational guide)
|
||
|
||
This document covers running the application, checking health, logs, common errors, and database operations.
|
||
|
||
## Starting and stopping
|
||
|
||
### Local
|
||
|
||
- **Start:** From the repository root, with virtualenv activated:
|
||
```bash
|
||
python main.py
|
||
```
|
||
Or after `pip install -e .`: `duty-teller`
|
||
- **Stop:** `Ctrl+C`
|
||
|
||
### Docker
|
||
|
||
- **Dev** (code mounted; no rebuild needed for code changes):
|
||
```bash
|
||
docker compose -f docker-compose.dev.yml up --build
|
||
```
|
||
Stop: `Ctrl+C` or `docker compose -f docker-compose.dev.yml down`.
|
||
|
||
- **Prod** (built image; restarts on failure):
|
||
```bash
|
||
docker compose -f docker-compose.prod.yml up -d --build
|
||
```
|
||
Stop: `docker compose -f docker-compose.prod.yml down`.
|
||
|
||
On container start, `entrypoint.sh` runs Alembic migrations then starts the app as user `botuser`. Ensure `.env` (or your orchestrator’s env) contains `BOT_TOKEN` and any required variables; see [configuration.md](configuration.md).
|
||
|
||
## Health check
|
||
|
||
- **HTTP:** The FastAPI app exposes **`GET /health`**, which returns `{"status": "ok"}` with 200 when the app is up. Use it for readiness checks and in Docker `HEALTHCHECK`.
|
||
- Alternatively, open the interactive API docs at **`GET /docs`** (e.g. `http://localhost:8080/docs`) or call a lightweight API endpoint with valid auth.
|
||
|
||
## Logs
|
||
|
||
- **Local:** Output goes to stdout/stderr; redirect or use your process manager’s logging (e.g. systemd, supervisord).
|
||
- **Docker:** Use `docker compose logs -f` (with the appropriate compose file) to follow application logs. Adjust log level via Python `logging` if needed (e.g. environment or code).
|
||
|
||
## Common errors and what to check
|
||
|
||
### "hash_mismatch" (403 from `/api/duties` or Miniapp)
|
||
|
||
- **Cause:** The server that serves the Mini App (e.g. production host) uses a **different** `BOT_TOKEN` than the bot from which users open the Mini App (e.g. test vs production bot). Telegram signs initData with the bot token; if tokens differ, validation fails.
|
||
- **Check:** Ensure the same `BOT_TOKEN` is set in `.env` (or equivalent) on the machine serving `/api/duties` as the one used by the bot instance whose menu button opens the Miniapp.
|
||
|
||
### Miniapp "Open in browser" or direct link — access denied
|
||
|
||
- **Cause:** When users open the calendar via “Open in browser” or a direct URL, Telegram may not send `tgWebAppData` (initData). The API requires initData (or `MINI_APP_SKIP_AUTH` in dev).
|
||
- **Action:** Users should open the calendar **via the bot’s menu button** (e.g. ⋮ → "Calendar") or a **Web App inline button** so Telegram sends user data.
|
||
|
||
### 403 "Open from Telegram" / no initData
|
||
|
||
- **Cause:** Request to `/api/duties` or `/api/calendar-events` without valid `X-Telegram-Init-Data` header. The API returns 403 without initData; the only bypass is `MINI_APP_SKIP_AUTH=1` (dev only, insecure).
|
||
- **Check:** Ensure the Mini App is opened from Telegram (menu or inline button). For local dev without Telegram, use `MINI_APP_SKIP_AUTH=1` in `.env`.
|
||
|
||
### Mini App URL — redirect and broken auth
|
||
|
||
- **Cause:** If the Mini App URL is configured **without** a trailing slash (e.g. `https://your-domain.com/app`) and the server redirects `/app` → `/app/`, the browser can drop the fragment Telegram sends, breaking authorization.
|
||
- **Action:** Configure the bot’s menu button / Web App URL **with a trailing slash**, e.g. `https://your-domain.com/app/`. See README “Mini App URL”.
|
||
|
||
### User not in allowlist (403)
|
||
|
||
- **Cause:** Miniapp access is determined by **roles in the database** (see `can_access_miniapp_for_telegram_user` in the repository). If the user has no role in the DB, the app falls back to `ADMIN_USERNAMES` and `ADMIN_PHONES`. A 403 means the user has neither a role granting access nor a match in the admin allowlist.
|
||
- **Check:** Assign a role with `/set_role @username user` or `admin` (admin-only command), or add the user to `ADMIN_USERNAMES` / their phone to `ADMIN_PHONES` in [configuration.md](configuration.md). Ensure at least one admin exists via env so they can use `/set_role`.
|
||
|
||
## Database and migrations
|
||
|
||
- **Default DB path (SQLite):** `data/duty_teller.db` (relative to working directory when using default `DATABASE_URL=sqlite:///data/duty_teller.db`). In Docker, the entrypoint creates `/app/data` and runs migrations there.
|
||
- **Migrations (Alembic):** From the repository root:
|
||
```bash
|
||
alembic -c pyproject.toml upgrade head
|
||
```
|
||
Config: `pyproject.toml` → `[tool.alembic]`; script location `alembic/`; metadata and URL from `duty_teller.config` and `duty_teller.db.models.Base`.
|
||
- **Rollback:** Use with care; test in a copy of the DB first. Example to go back one revision:
|
||
```bash
|
||
alembic -c pyproject.toml downgrade -1
|
||
```
|
||
Always backup the database before downgrading.
|
||
|
||
For full list of env vars (including `DATABASE_URL`), see [configuration.md](configuration.md). For reverse proxy and Mini App URL details, see the main [README](../README.md).
|