No description
  • Go 96.9%
  • Shell 2%
  • Just 0.6%
  • Dockerfile 0.5%
Find a file
2026-06-06 22:17:39 +05:00
.gitea/workflows ci: make sqlite backups work from runner 2026-06-06 21:33:46 +05:00
.githooks fix(githooks): fix scope 2026-06-06 22:15:14 +05:00
.github ci: harden pipeline and deploy flow 2026-06-06 21:01:05 +05:00
cmd/bot graceful shutdown, rate limiter, session persistence on callback miss, sqlite wal mode, deep copy Subjects in Session.clone, app tests, ci fmt check and auto-deploy 2026-05-14 16:10:53 +05:00
internal feat(app): add inline group and subgroup controls 2026-06-04 00:06:59 +05:00
scripts ci: make sqlite backups work from runner 2026-06-06 21:33:46 +05:00
.air.toml add developer tooling: justfile, air, golangci-lint, pre-commit hooks and gitea ci 2026-05-14 14:31:58 +05:00
.dockerignore improve ci pipeline, add login rate limit, fuzz tests, storage integration tests, pprof endpoint, stream notify users, add schedule cache, add dockerignore 2026-05-21 21:30:58 +05:00
.env.example fix: remove hardcoded endpoint fallbacks 2026-06-03 14:44:41 +05:00
.gitattributes init: ktk-schedule 2026-05-09 11:21:56 +05:00
.gitignore chore: harden ci and deployment 2026-06-01 15:51:04 +05:00
.golangci.yml migrate golangci-lint to v2, fix CI compatibility with Go 1.26 2026-05-21 21:38:12 +05:00
docker-compose.yml ci: publish image and notify deploys 2026-06-01 15:59:12 +05:00
docker-entrypoint.sh add entrypoint to fix volume permissions for non-root user 2026-05-14 16:30:36 +05:00
Dockerfile ci: make sqlite backups work from runner 2026-06-06 21:33:46 +05:00
go.mod chore: update go to 1.26.4 and bump all dependencies 2026-06-03 17:22:50 +05:00
go.sum chore: update go to 1.26.4 and bump all dependencies 2026-06-03 17:22:50 +05:00
Justfile chore: update go to 1.26.4 and bump all dependencies 2026-06-03 17:22:50 +05:00
LICENSE chore(license): update license 2026-06-06 19:56:33 +05:00
README.en.md fix(readme): fix license style 2026-06-06 22:17:39 +05:00
README.md fix(readme): fix license style 2026-06-06 22:17:39 +05:00

ktk-schedule


English

Telegram bot for the KTK workspace. Authenticates users, stores credentials in encrypted SQLite, renders schedules directly in Telegram, and sends morning notifications.

Built for daily production use: HTTP timeouts, retry wrappers, rate limiting, circuit breaker, persistent cache, Docker health checks, graceful shutdown.

Features

Area What it does
Schedule Week view, specific dates, today, week switching, day selection
Groups Personal group, other group, subgroup selection, both subgroups mode
Teachers Teacher sign-in and schedule retrieval
Academic data Lesson time, room, type, current status, grades, attendance
Files Homework attachments, uploaded files, day-based download
Notifications Morning schedule delivery via NOTIFY_TIME and TIMEZONE
Reliability Bounded HTTP reads, retries, rate limiting, circuit breaker, cache
Operations /health, /health/extended, optional /debug/pprof, Docker, Forgejo CI/CD
Security AES-GCM password storage, private /login, .env secrets, SQLite WAL

Quick Start

cp .env.example .env

Minimum required variables:

BOT_TOKEN=123456:your-token-from-botfather
CREDENTIALS_SECRET=random-string-at-least-32-characters

Generate a secret:

openssl rand -base64 32

Run locally:

go run ./cmd/bot

Run with Docker:

docker compose up --build -d
docker compose logs -f

Bot Commands

Command Purpose
/start Show available commands
/my_id Show your Telegram ID
/login username password Sign in to the workspace
/schedule Open the current week schedule
/schedule 01.09 Schedule for a date in the current academic year
/schedule 2026-09-01 Schedule for an exact date
/notify_on / /notify_off Enable or disable morning notifications
/announce text Send an owner announcement to all users
reply /announce Broadcast the replied-to message
/stats Show bot statistics (owner only)

/login deletes the user message immediately after receipt — credentials never stay in the chat.

Schedule Output

📅 01.06.2026

1 пара [70 мин] — ОП.12 ИКГ
⏰ 08:00-09:10
🔬 Практическое занятие
👤 Бухтоярова Елена Леонидовна
🏫 Кабинет: 301

2 пара [70 мин] — ОП.02 ДМЭМЛ
⏰ 09:20-10:30
📚 Лекция
👤 Сапожникова Елена Владимировна
🏫 Кабинет: 41

After /schedule, inline navigation is available for days, weeks, files, groups, and subgroups.

Architecture

flowchart LR
    T[Telegram] --> A[internal/app]
    A --> K[internal/ktk]
    A --> S[internal/storage]
    A --> TG[internal/tg]
    S --> C[internal/credentials]
    K --> W[Workspace API]
    S --> DB[(SQLite)]
    A --> H[/health/]
Path Responsibility
cmd/bot Entry point, config loading, logging, graceful shutdown
internal/app Telegram handlers, sessions, notifications, cache, rate limit, health server
internal/ktk Workspace client, parsing, formatting, files, endpoint discovery
internal/storage SQLite, migrations, users, encrypted credentials, schedule cache
internal/credentials AES-GCM encryption and legacy plaintext migration
internal/config .env loading and validation
internal/tg Inline keyboards and compact callback payloads
.gitea/workflows CI/CD, image build, deploy, backup, rollback

Package boundaries are intentional: Telegram orchestration in internal/app, workspace logic in internal/ktk, persistence in internal/storage.

Configuration

All variables are documented in .env.example. Required:

Variable Description
BOT_TOKEN Telegram bot token from @BotFather
CREDENTIALS_SECRET AES-GCM secret, at least 32 characters
OWNER_TELEGRAM_ID Owner Telegram ID for /announce and /stats
KTK_BASE_URL Workspace base URL (default https://workspace.ktk-45.ru)
KTK_DEVICE_NAME Device name sent with sign-in requests
DEFAULT_GROUP_ID Default group after first sign-in
DEFAULT_SUBGROUP Default subgroup: 1 or 2
NOTIFY_TIME Morning notification time, HH:MM format
TIMEZONE Time zone, e.g. Asia/Yekaterinburg
DATABASE_PATH Path to the SQLite file
HEALTH_ADDR Health server address, default 127.0.0.1:8080
PPROF_ENABLED Enable /debug/pprof on the health server

Development

Required: Go 1.26.4+, just, golangci-lint, govulncheck. Hot reload uses air.

just setup       # configure .githooks
just setup-air   # install air
just setup-lint  # install golangci-lint
just setup-vuln  # install govulncheck

Common commands:

just dev         # hot reload (air)
just run         # run normally
just test        # go test -count=1 ./...
just race        # tests with -race
just lint        # golangci-lint run
just vuln        # govulncheck ./...
just build       # build ./ktk-schedule
just check       # full local verification before handoff
just ci-check    # CI-level verification
just backup      # backup SQLite from Docker volume
just clean       # remove binary, database, and logs

Operations

Docker Compose starts the service with a persistent SQLite volume:

docker compose up --build -d
docker compose logs -f

Health endpoints:

Endpoint Purpose
/health Basic process health check
/health/extended Extended diagnostics
/debug/pprof Profiling, only when PPROF_ENABLED=true

Do not expose the health server or pprof publicly without access control.

Forgejo CI/CD runs quality checks, builds the Docker image, publishes it to the registry, and deploys to the VDS. A compressed SQLite backup is created before deployment; if the new container fails health checks, the pipeline attempts a rollback to the previous image.

License

BSD 3-Clause License