-
Notifications
You must be signed in to change notification settings - Fork 0
Home
type: Feature Catalog title: Matplobbot Full Feature Wiki description: Full feature map for the bot, website, API, scheduler, worker, and delivery pipeline. resource: /wiki.md tags: [features, architecture, api, bot, operations] status: stable generated: { by: codex/gpt-5, at: "2026-08-11T00:47:31+03:00" } sources:
- id: okf-spec resource: https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md title: Open Knowledge Format v0.2 specification
This page is a full feature map of the project: bot, website, API, scheduler, worker, and delivery pipeline.
This document is an OKF concept inside the documentation bundle. It is kept as the global project wiki source and is mirrored to GitHub Wiki by the existing wiki sync workflow.
| Feature | Entry point | Purpose |
|---|---|---|
| Onboarding and language | /start |
First-run flow, language selection, and guided intro |
| Help and command menu | /help |
Discover commands and open feature entry points |
| Library browser and search |
/matp_all, /matp_search, /favorites
|
Browse matplobblib, search, and manage favorites |
| GitHub notes browser and search |
/lec_all, /lec_search
|
Browse and search linked GitHub Markdown notes |
| Unified global search | /search |
Search library and linked GitHub from one screen |
| Search presets | /search_presets |
Save and rerun search configurations |
| Schedule discovery | /schedule |
Search group/lecturer/room and view day or week schedule |
| Personal aggregated schedule | /myschedule |
Combined view across active subscriptions with filters |
| Bot calendar sync manager |
/calendar_sync, /start calendar_sync
|
Manage WebCal link, calendar profiles, and schedule subscriptions in Telegram |
| Settings center | /settings |
Personal/group settings, subscriptions, short names, privacy |
| Rendering tools |
/latex, /mermaid
|
Render formulas and diagrams |
| Short-name suggestions | /offershorter |
User suggestion flow with admin moderation |
| Admin commands |
/update, /clear_cache, /send_admin_summary, /set_module, /broadcast_release
|
Maintenance and moderation operations |
| Feature | Entry point | Purpose |
|---|---|---|
| Auth and account sessions |
/login + navbar auth actions |
Sign in via Telegram or password, persist user profile |
| Shared navbar and i18n | main_site_frontend/js/navbar.js |
Cross-page navigation, EN/RU translations, command palette |
| Global dark theme | public website navbar + <head> theme init |
Site-wide light/dark mode, persisted per browser |
| Frontend Tailwind build | npm run build:tailwind |
Production CSS generation for static and FastAPI pages |
| Telegram Mini Apps | Bot Web App buttons + /schedule, /studio
|
Launch schedule and Studio inside Telegram with signed auth |
| PWA install and offline shell |
site.webmanifest, service-worker.js
|
Installable frontend with cached app shell |
| Schedule page | /schedule |
Unified schedule search, filters, calendar nav, offline awareness |
| Calendar sync panel | Schedule page calendar section | Manage private iCal feeds and website sync profiles |
| Stats dashboard |
/stats (admin) |
Live and REST analytics, degradations, drill-downs |
| Studio page | /studio |
Document compile, project files, exports, send to Telegram |
| Runtime API base and popup UX |
runtime_config.js, ui_utils.js
|
Environment-specific API host and unified notifications |
| Feature | Entry point | Purpose |
|---|---|---|
| OpenAPI docs | /docs |
Branded interactive API docs with auth-aware try-it-out |
| API CORS and rate limits | FastAPI env + Redis | CORS origin allowlist and abuse limits for heavy routes |
| Auth API | /api/auth/* |
Registration, login, Telegram auth, profile, preferences |
| Schedule API | /api/schedule/* |
Search entities, fetch schedule windows, fallback counters |
| Stats API | /api/stats/* |
Health, profiles, exports, admin messaging, dashboards |
| Studio API | /api/studio/* |
Project CRUD, compile, assets, zip export, Telegram delivery |
| Calendar API | /api/cal/* |
Authorized calendar config + public iCal feeds |
| WebSocket API | /ws/* |
Live stats, bot-log deprecation notice, user-specific update stream |
| Feature | Entry point | Purpose |
|---|---|---|
| Scheduler jobs | scheduler_app/main.py |
Notifications, cache refresh, diffs, cleanup, summaries |
| Container logging and disk limits | docker-compose*.yml |
Console-only app logs with Docker log rotation |
| Celery worker tasks | shared_lib/tasks.py |
Rendering and compile pipelines |
| Cache and fallback model | Redis + cached_schedules
|
Keep schedule UX available during upstream outages |
| CI, deploy, and wiki sync | GitHub Actions + Jenkins + deploy.sh
|
Validation, publish/build, production deploy, docs sync |
What it does:
- Shows first-start flow with language selector.
- Supports a guided onboarding tour across major bot capabilities.
- Supports language cycling and restart onboarding from settings.
- Adds an optional quick setup step after onboarding to jump directly into schedule subscription setup (
entity + notification time) with a skip option.
How to use:
- Send
/startin private chat. - Pick language.
- Continue onboarding or skip.
- In the quick setup card, either start immediate schedule setup or skip for now.
- Open
/settingsto change language later or restart onboarding.
What it does:
-
/helppresents command-centered navigation. - Supports private and group-aware help behavior.
- Includes route buttons to major flows (
/schedule,/search,/search_presets, etc.).
How to use:
- Send
/help. - Tap a feature button or run command directly from menu.
Commands:
-
/matp_all: interactive browse of indexedmatplobblibmaterials. -
/matp_search: semantic text search in library content. -
/favorites: opens saved favorite materials.
What it does:
- Paginates long result sets.
- Lets users open material by inline result.
- Supports add/remove favorite actions directly from cards.
How to use:
- Send
/matp_allto browse by sections. - Send
/matp_search, then enter query text. - Use inline result buttons to open, star, or unstar items.
- Use
/favoritesto revisit saved items.
Commands:
-
/lec_all: browse linked repositories. -
/lec_search: search Markdown chunks in selected linked repository.
What it does:
- Per-user repository management in settings.
- Markdown viewer for selected file chunks.
- Semantic search over configured repo sources.
How to use:
- Open
/settingsand add a GitHub repo (owner/repo) if none linked. - Send
/lec_allto browse notes. - Send
/lec_search, pick a repository, and enter query.
Command:
/search
What it does:
- Merges search across two source types:
- library (
source_type="lib") - linked GitHub repos (
source_type="repo:owner/name") - Supports source toggles and repo subset toggles.
- Uses Redis-backed session state for pagination and result-open callbacks.
How to use:
- Send
/search. - Toggle sources (Library/GitHub) and optional repos.
- Send query text.
- Page through results and open target item.
- Optionally tap
Save preset.
Command:
/search_presets
Supported kinds:
librarygithubscheduleglobal
What it does:
- Saves query + filters (not static result snapshots).
- Stores presets in
User.settings["search_presets"]. - Lets users run/delete presets from one menu.
How to use:
- Run one of supported search flows and get results.
- Tap
Save preset, send preset name. - Open
/search_presetslater and tap run/delete.
Command:
/schedule
What it does:
- Search by entity type:
- group
- person (lecturer)
- auditorium
- Shows day view and week view.
- Provides inline calendar navigation.
- Supports iCal export from selected schedule entity.
- Supports subscribe flow with schedule delivery time.
How to use:
- Send
/schedule. - Pick search type.
- Enter query and select result.
- Use day/week/calendar controls.
- Use subscribe button to set a daily notification time.
Command:
/myschedule
What it does:
- Aggregates active subscriptions into one personal timeline.
- Includes filter controls:
- include/exclude subscriptions
- include/exclude lesson types
- Supports a dedicated
Consultationlesson type in filters. The built-inOnly examspreset still keeps pre-exam consultations visible. - Includes filter presets:
- built-in (
All lessons,Only exams,Hide auditoriums) - custom named presets saved from current filter state
- Supports iCal export and personal calendar link actions.
- Includes link revocation action for secret calendar URL.
How to use:
- Ensure at least one active schedule subscription.
- Send
/myschedule. - Open
Filtersand apply a built-in preset or save the current filters as a named preset. - Toggle per-type/per-source filters and day/week navigation as needed.
- Export iCal or manage personal calendar link from inline actions.
Commands:
/calendar_sync/start calendar_sync
What it does:
- Opens the Telegram-side manager for the same WebCal sync state used by the website.
- Shows sync enabled/disabled state, selected calendar profile, profile count, active schedule subscription count, and the selected feed URL.
- Lets users open the selected feed, reset the private calendar secret, enable/disable sync, and jump into schedule subscription management.
- Lists built-in and custom calendar profiles, supports selecting and deleting profiles, and creates custom calendar presets from active schedule subscriptions.
- Uses website account preferences linked by Telegram ID, so profiles created in the bot and profiles created on the site share the same
calendar_syncstate.
How to use:
- Send
/calendar_sync, or openhttps://t.me/matplobbot?start=calendar_sync. - Use
Manage Schedule Subscriptionsto toggle, retime, delete, or edit modules for bot schedule subscriptions. - Open
Profiles and presetsto select a built-in feed or create a custom preset from an active subscription. - Use
Open selected feedor copy the shown URL into a calendar app. - Use
Reset Linkif the private URL was exposed.
Command:
-
/settings(private and group admin context)
What it does (private):
- Personal display toggles (short names, markdown mode, latex tuning, module details).
- Manage personal schedule subscriptions (list, page, toggle, set time, delete).
- Manage personal short names (create/toggle/delete).
- Manage linked GitHub repositories.
- Restart onboarding.
- Delete my data action.
What it does (group admin):
- Group subscription controls.
- Group language control.
- Admin summary scheduling controls.
How to use:
- Send
/settings. - Select area (personal, subscriptions, repos, short names, admin/group).
- Apply changes via inline buttons.
Commands:
/latex/mermaid
What it does:
- Sends content to worker-backed render tasks.
- Returns rendered output to chat.
- Builds the worker base image on Node 22 and pins
@mermaid-js/mermaid-clifor stable Mermaid rendering dependencies.
How to use:
- Send
/latexor/mermaid. - Send expression/diagram text.
- Wait for compiled image output.
- After changing Mermaid CLI or Node versions, rebuild
matplobbot-base-workerbefore rebuilding worker services.
Command:
/offershorter
What it does:
- Users suggest a shorter discipline alias.
- Admins receive moderation buttons (approve/decline).
- Decision state is persisted to prevent duplicate moderation actions.
How to use:
- Send
/offershorter. - Enter full discipline and suggested short name.
- Wait for admin decision.
Commands:
/update/clear_cache/send_admin_summary/set_module/broadcast_release
What they do:
- Trigger maintenance/cache/index operations.
- Trigger summary delivery.
- Map discipline to module name with
/set_module Discipline | Module. - Send release announcements/changelog to active users with a hard Telegram rate cap.
How to use:
- Run command from admin account/chat role.
- Follow command-specific format prompts.
Entry points:
- Admin bot command:
/broadcast_release - CLI script:
scripts/broadcast_announcement.py
What it does:
- Builds a plain-text Telegram broadcast from Markdown sources.
- Defaults to
docs/announcement.mdordocs/ANNOUNCEMENT.mdwhen present, plus the current changelog (docs/changelog-from-0.7.1.md, falling back todocs/CHANGELOG.md). - Targets active users: users with recent actions in the configured window and users with active schedule subscriptions.
- Splits long content into Telegram-safe chunks and sends sequentially with a rate cap of 30 messages per second.
- Defaults to dry-run mode; sending requires an explicit
--execute. - Continues after blocked/deleted users and reports failed user IDs/chunks to the admin or CLI output.
How to use the admin command:
- Run
/broadcast_releaseto preview recipients, chunk count, sources, and total Telegram messages. - Optionally narrow the rollout:
/broadcast_release --user-id 123456 --file docs/announcement.md - Send for real only after reviewing the dry run:
/broadcast_release --execute --active-days 180 --rate 25 - For staged delivery, add
--limit 100; for test delivery, repeat--user-id.
How to use the script:
- Dry-run from the repo root:
python scripts/broadcast_announcement.py --print-preview - Test one Telegram account:
python scripts/broadcast_announcement.py --user-id 123456 --execute - Send to active users:
python scripts/broadcast_announcement.py --execute --active-days 180 --rate 25 - Add custom sources with repeated
--fileflags; the script requiresBOT_TOKENonly when--executeis used.
Pages and scripts:
main_site_frontend/login.htmlmain_site_frontend/register.htmlmain_site_frontend/js/auth.js
What it does:
- Supports password login for already issued accounts.
- Disables public password registration by default;
POST /api/auth/registerreturns 403 unlessAUTH_PASSWORD_REGISTRATION_ENABLED=true. - When password registration is explicitly enabled for a controlled environment, it creates only
role="user"accounts, never admin accounts. - Supports Telegram auth handoff.
- Supports Telegram Mini App
initDataauth exchange for in-Telegram launches. - Stores bearer token client-side for API calls.
- Loads
/api/auth/mefor profile and role-aware UI. - Applies shared EN/RU i18n toggle to auth page texts (titles, labels, hints, placeholders, buttons).
- Uses a mobile-optimized auth layout (viewport meta, compact navbar, adaptive spacing for narrow screens).
How to use:
- Open
/login. - Sign in with Telegram for a normal web session, or use an already issued admin username/password.
- Use the navbar
EN/RUswitch to change auth page language. - After login, navigate to schedule/studio/stats by role.
- Enable
AUTH_PASSWORD_REGISTRATION_ENABLED=trueonly for controlled development or migration scenarios, then disable it again.
Files:
bot/config.pybot/keyboards.pybot/handlers/base.pymain_site_frontend/schedule.htmlmain_site_frontend/studio.htmlmain_site_frontend/js/telegram_webapp.jsfastapi_stats_app/auth.pyfastapi_stats_app/routers/auth_router.py
What it does:
- Adds Telegram Web App launch buttons for
/schedule?tg=1and/studio?tg=1to the bot's private reply/help keyboards. - Adds
/studioas a bot command that opens a Web App launch prompt. - Uses
PUBLIC_SITE_URLas the public HTTPS base URL for Telegram Web App buttons. - Disables Telegram Web App buttons and logs a warning when
PUBLIC_SITE_URLdoes not build HTTPS URLs, preventing TelegramBad Request: Only HTTPS links are allowederrors. - Adapts
/scheduleand/studioto Telegram viewport, safe-area, color scheme, and theme parameters. - Exchanges signed Telegram Mini App
initDataat/api/auth/telegram/webapp, rejects stale signatures byauth_date, and stores the returned website JWT. - Replaces any stale local website JWT inside Telegram with a fresh Mini App token on launch.
- Lets Studio wait for Mini App auth before redirecting to
/login.
How to use:
- Set
PUBLIC_SITE_URLto the public website origin, for examplehttps://ivantishchenko.ru. - Start or restart the bot so the reply keyboard and
/studiocommand are refreshed. - In a private Telegram chat, tap
Open ScheduleorOpen Studio. - Use
/schedule?tg=1or/studio?tg=1for direct Mini App testing from Telegram. - Keep
BOT_TOKENconfigured in FastAPI; Mini App signed auth is rejected without it. - Optionally tune
TELEGRAM_WEBAPP_AUTH_MAX_AGE_SECONDSif the default 24-hourauth_datewindow is too strict for your deployment. - For local
http://localhost:8080development, use a public HTTPS tunnel or domain before testing Mini App launch buttons in Telegram; otherwise the bot hides those buttons.
Files:
main_site_frontend/site.webmanifestmain_site_frontend/service-worker.jsmain_site_frontend/offline.htmlmain_site_frontend/js/navbar.js
What it does:
- Makes the static frontend installable with app name, icons, theme colors, start URL, and shortcuts for Schedule and Studio.
- Registers a service worker from shared
navbar.json pages that load the common frontend shell. - Pre-caches the main static pages, shared scripts/styles, icons, Schedule, Stats, Studio assets, and offline fallback.
- Uses no-cache network-first navigation so fresh pages win, then cached pages/offline fallback are used when the network is unavailable.
- Uses network-first for same-origin JS/CSS assets so deployed frontend fixes are not served stale once before appearing on the next reload.
- Avoids intercepting same-origin
/api/*requests so authenticated API calls are not cached by the service worker. - Schedule frontend asset URLs use
?v=20260821-7, Stats usesstats.js?v=19andstats_ux.js?v=2, shared navbar uses?v=20260821-8, and the service worker cache ismpb-site-v26; bump changed asset URLs and the service worker cache when changing cached frontend behavior.
How to use: (or not use)
- Open the public site over HTTPS.
- Use the browser install prompt or mobile
Add to Home Screen. - After the first successful online load, reopen
/scheduleor/studiofrom the installed app. - If the network is unavailable, cached shell pages load and uncached navigations fall back to
/offline.html.
Files:
main_site_frontend/js/navbar.js
What it does:
- Shared top nav across pages.
- EN/RU translation dictionary and runtime text updates.
- Command palette and keyboard shortcuts.
- Sun/moon theme toggle that persists the selected light/dark theme.
- Admin-only nav item for stats page.
How to use:
- Use language switch in navbar.
- Use the sun/moon button to toggle the global theme.
- Open palette/shortcuts from navbar controls.
- Use account menu for logout and profile actions.
Files:
main_site_frontend/index.htmlmain_site_frontend/schedule.htmlmain_site_frontend/studio.htmlmain_site_frontend/login.htmlmain_site_frontend/register.htmlmain_site_frontend/js/theme_bootstrap.jsmain_site_frontend/js/navbar.jsmain_site_frontend/js/studio.js
What it does:
- Initializes the preferred theme in
<head>before page rendering to avoid a light-theme flash. - Uses Tailwind
darkMode: 'class', toggleshtml.dark, and setshtml[data-theme]for CSS-variable driven surfaces. - Persists explicit user choice in
localStorage.theme. - Falls back to the operating system color scheme when no explicit choice exists.
- Updates shared navbar controls, public pages, schedule rendering, auth pages, Studio chrome, and Monaco editor.
- Updates the current page immediately without rerendering authenticated navbar state.
- Emits
mpb-theme-changeso page-level components can react immediately.
How to use:
- Open any public site page.
- Click the sun/moon button next to the language switch.
- Or open the command palette and run
Toggle theme/Переключить тему. - The theme changes immediately; on the next reload the selected theme is applied before the body renders.
Files:
package.jsontailwind.config.jstailwind.input.cssmain_site_frontend/css/tailwind.cssfastapi_stats_app/static/css/tailwind.css
What it does:
- Builds production Tailwind CSS locally instead of loading
cdn.tailwindcss.comin the browser. - Scans static website HTML/JS and FastAPI dashboard templates/JS for utility classes.
- Emits one stylesheet for the nginx-served site and one stylesheet for FastAPI static templates.
- Keeps class-based dark mode enabled for both frontends.
How to use:
- Run
npm installafter cloning or when dependencies change. - Run
npm run build:tailwindafter changing frontend HTML or JS that uses Tailwind utilities. - Serve the static site normally; pages load
/css/tailwind.css. - Serve the FastAPI app normally; templates load
/static/css/tailwind.css.
Files:
main_site_frontend/schedule.htmlmain_site_frontend/js/schedule.jsmain_site_frontend/js/schedule_state.jsmain_site_frontend/js/schedule_api.jsmain_site_frontend/js/schedule_filters.jsmain_site_frontend/js/schedule_render.jsmain_site_frontend/js/schedule_ux.js
What it does:
- Unified search for group/lecturer/auditorium.
- Opens schedules from shareable URLs such as
/schedule?type=group&id=...&name=...&date=2026-05-04. - Keeps a single page state object with entity, date, view mode, selected modules, lesson mode, offline state, and active calendar profile.
- Syncs that state across URL parameters, local/remote preferences, browser history, and visible UI controls.
- Uses a compact schedule shell: entity selector on the left, week navigation in the center, and
Filters and modules+Calendaractions on the right. - Keeps the three global display toggles (
Short names,Full lecturer name,Actions) visible directly under the toolbar instead of burying them in a separate settings block. - Keeps
Changes,Favorite, andCopy linkas a compact utility strip next to the view switcher instead of three large text buttons. - Desktop timetable grid + mobile card view.
- On wide screens,
Tableis now the default Schedule view; URLs omitview=tablebecause table is the canonical desktop mode. - Desktop
Tablehas a sticky summary bar, sticky day headers, a high-priority sticky time column, internal horizontal/vertical scrolling, per-day lesson counts, and compact density-aware timeline cards modeled after the Telegram output hierarchy: kind/module first, discipline as the primary text, room and lecturer as secondary metadata. - Lesson cards include a systematic quick-action strip:
- copy room
- open lecturer schedule
- open room schedule
- download a one-lesson
.ics - show only the lesson module
- hide the lesson module
- Lesson actions are controlled by the shared
Actionstoggle in the filter area, so users can keep cells compact or expose inline quick buttons across the whole schedule. - View density switcher:
-
Cardsfor the current rich card feed -
Compactfor seeing more lessons on one screen -
Tablefor desktop timetable scanning; on narrow/mobile screens it is treated as desktop-only, the page switches to the card feed, and the table button is disabled -
Examsfor an exam-focused feed with exam filtering enabled - Filters and toggles:
- module filters
- module search and selected-module counter in the filter header; the search field keeps focus while the module list rerenders
- schedule module presets saved per schedule entity
- calendar presets can reopen a different schedule entity, lesson mode, and module selection directly on
/schedule - favorite schedules remain lightweight bookmarks for fast reopening from search/local history; they still remember the selected module set when saved from the currently opened schedule
- quick module actions: only this module, all except this module, reset/all
- amber highlighting for modules that are not present in the currently visible period/mode
- all classes / exams-only lesson mode
- short names
- full lecturer name
- lesson actions visibility toggle shared across table/cards views
- display toggles stay available even when the selected schedule has no module split
- full lecturer-name preference applies to both desktop cells and mobile cards
- Optional
Changespanel compares the current schedule with the previous local snapshot for the same entity and respects the current week, module filters, and lesson mode. - The changes panel reports new, cancelled, moved, room-changed, and lecturer-changed lessons plus source parsing time and previous snapshot time.
- Includes copy-to-clipboard actions for room/lecturer.
- When the
Actionstoggle is enabled, lesson cards and timetable cells expose inline quick buttons for room copy, lecturer/room navigation, one-lesson ICS export, and module-only/module-hide actions without opening a per-card accordion. - In desktop
Table, theActionstoggle shows a compact action launcher inside each timetable cell instead of a full six-button strip. This keeps long lesson titles visible while still exposing room/teacher/calendar/module actions from a small overlay menu. - Shows source update timestamp and offline/fallback states.
- Search UX includes recent schedules, favorites, quick type categories, local fuzzy matching, and separate loading/empty/network-error states.
- Offline drawer shows cached schedules, cache update time, and a refresh action for the current schedule. Admin users also see
Refresh full semester, which force-refreshes the whole current semester cache for the selected schedule entity. - The offline drawer is rendered as a floating overlay layer above the schedule grid, so opening cached schedules never pushes the timetable or control rows down.
- Highlights exam-like lessons, including
Семинар+зачетandЭкзамены, with the dedicated exam color instead of the regular seminar color. - Treats
Консультации перед экзаменомas a consultation, not as a mislabeled exam: the page gives it its own consultation badge/color, but still keeps it inExams/exams-onlyviews because it is exam-related. - In desktop
Tableview, lessons whose real begin/end time from the university API no longer fits a single hardcoded slot are rendered proportionally inside the timetable grid instead of disappearing. The card starts and ends inside the matching rows according to the spent fraction of time, and off-slot items get an explicit compact time badge inside the card. - Module filters start collapsed, but once opened they stay open while toggling modules or typing in module search, so users can select several modules without reopening the panel.
- Site-side schedule normalization treats
Военная подготовкаlessons as the selectableВоенная кафедраmodule when the university API provides them as regular lessons withoutmodule, and canonicalizes older military-module labels to that same website label. - Desktop
Tableautomatically scrolls its internal viewport to the earliest visible lesson start time after each render, and the table viewport is sized to the remaining browser height to avoid dead space below the grid. - Persists preference state locally and in account preferences when available.
- Frontend schedule code is being split into focused helper modules:
schedule_state.js,schedule_api.js,schedule_filters.js, andschedule_render.js.
How to use:
- Open
/schedule, or open a direct URL withtype,id,name, and optionaldate. - Use the top-left selector to search for a group, lecturer, or room.
- Pick a result, then switch week context; the URL updates with the current state.
- Use the toggle row for
Short names,Full lecturer name, andActions, then open the filter panel to search modules, toggle them, save a module preset, or applyOnly/Exceptactions from a module chip. - Turn on
Actionswhen you want inline quick buttons directly inside lesson cells/cards for room copy, lecturer/room navigation, one-lesson ICS export, and module-focused filtering. - Use the compact utility strip next to the view switcher:
Changes(Изм.) compares the current schedule with the previous local snapshot,Favoritepins the current entity with its selected module set, andCopy linkshares the exact current view. - Use favorites in search/local history when you want pinned entities that reopen fast without switching calendar presets.
- Pick another non-favorite schedule from search to reset the module filter to all modules available for that schedule.
- Use
Cards,Compact,Table, orExamsto choose display density. The choice is saved and reflected in the URL;Tableis treated as a desktop mode and automatically falls back to cards on phones. - In
Table, read long or off-slot exams by their vertical span inside the grid: the card position shows where the event starts and ends relative to the standard rows, and the compact time chip shows the exact real time when it does not align to the default slot boundaries. On open or after module filtering, the internal table scroll starts at the first visible lesson time for the current week. - Turn on
Actionsif you want quick actions in timetable cells. In desktopTable, each cell shows a compact action launcher that opens the room/teacher/calendar/module menu above the card without hiding the lesson title. - Open the offline drawer to see cached schedules and refresh the current schedule cache. Admin users can also refresh the selected entity's whole semester cache from this drawer; non-admin users do not see that action. It opens above the timetable as an overlay, not as an expanding layout block.
Files:
main_site_frontend/js/calendar_sync.js
What it does:
- Shows eligibility based on Telegram linkage. Bot subscriptions are no longer required for website-owned iCal profiles.
- Opens from the
Calendarbutton in the schedule toolbar;/schedule?calendar=1still opens the panel directly. - On desktop, the panel is embedded as a right rail inside the schedule shell and scrolls internally instead of stretching the full page. On mobile and narrow widths it falls back to a dismissible drawer with backdrop and
Esc/outside-click close. - The desktop rail and shared drawer are wider than before, so the connection flow, summary cards, and preset controls no longer feel cramped in the right column.
- Internal panel sections adapt to the actual rail/drawer width instead of global viewport breakpoints, so tablet drawers and the desktop rail keep compact stacked controls instead of overflowing into wide multi-column layouts.
- Manages profile-based iCal feeds:
- built-in
All classes - built-in
Exams only - custom presets from current schedule page
- Stores custom presets in the signed-in user's website preferences, so each account keeps its own presets across reloads and browser sessions.
- Treats custom website profiles as independent calendar sources. Built-in feeds include both active Telegram subscriptions and saved website profiles.
- Warms the semester schedule cache when a website profile is saved, then the background scheduler keeps these web-only sources refreshed.
- Supports:
- expand/collapse panel state
- collapsed summary with active preset, event count, next event, cache-updated time, and fast actions
- expanded top overview cards for active preset, event count, next event, and last cache update, so everyday status is visible without opening diagnostics
- compact selected-state preset rows for built-in and custom profiles
- separate connection, current-page preset save, preset settings, and diagnostics/management sections ordered by everyday usage priority
- shorter preset description copy in the rail header/settings when the panel is still relatively narrow, so key actions stay above the fold instead of being pushed down by wrapped metadata
- visible selected-module chips for every preset, including the
All modulesstate - custom preset module checklist on the matching schedule page
- copy/reveal/hide URL
- Apple/Google/Outlook setup guidance with persisted target-calendar choice
- preview and download
- enable/disable sync
- rotate secret
- delete custom preset
- edit custom preset name, lesson mode, and saved module set
- switching presets preserves the currently viewed week on
/schedule - custom presets with
All modulesrestore the full module set even if the user previously narrowed the page to a subset - direct bot deep link through
window.__MPB_BOT_DEEPLINK__/https://t.me/matplobbot?start=calendar_sync - Telegram Mini App launch from the bot's
Calendar SyncWeb App button, which opens/schedule?tg=1&calendar=1, signs in with Telegram init data, and opens the right drawer directly. - In Telegram Mini App, the collapsed sync card remains visible while Telegram auth is pending or unavailable, so users can expand it and see the sign-in state instead of the panel disappearing.
- Shows profile health (event count, next event, cache status, source updated, last access).
- Adds the last university-site schedule parsing time to every generated iCal event description.
-
Exams onlycalendar feeds include pre-exam consultations together with exams and pass/fail assessments, while preserving theConsultationevent type label.
How to use:
- Sign in and open
/schedule. - Link the website account to Telegram to generate the private secret link.
- Click
Calendarin the schedule toolbar to open the rail/drawer. - Use the top overview cards and
Connectionsection for the normal flow: confirm the active preset and feed health, then copy the link, open the feed in the target calendar app, or jump to bot management. - In
Presets, switch between built-in feeds and custom website presets. Built-in presets update the current lesson mode, and custom presets also reopen their saved schedule entity/modules on the page while keeping the currently selected week. - Open any group, lecturer, or room schedule and use
Save current viewto create a website-only iCal profile. - In
Profile settings, inspect which modules are included in the selected preset. For custom presets, open the matching schedule from the module notice when needed, then use the checklist to add/remove modules and save the preset. - In
Connection, choose Apple, Google, Outlook, or another calendar app, preview the feed, download ICS, and follow the platform-specific action. - In
Diagnostics and management, inspect cache/source health, reset the secret URL, disable sync, or delete a custom preset. - In Telegram, tap
Open in botor the bot'sCalendar Syncminiapp button to manage the same WebCal feed without relying on Mini App auth. - Open an event in your calendar app to see when Matplobbot last parsed that source from the university site.
Files:
main_site_frontend/stats.htmlmain_site_frontend/js/stats.jsmain_site_frontend/js/stats_ux.js
What it does:
- Uses REST + WebSocket live updates.
- Displays leaderboard, activity, action distributions, and user drill-down.
- Supports pagination and sorting on user profile/action-users tables.
- Supports exports (JSON/CSV/PDF weekly) with date range and timezone.
- Includes partial-degradation state when one widget fails.
- Shows an admin-only
Refresh schedule cacheaction that force-runs the full semester cache remap/refresh workflow from/stats; non-admin accounts never see the button, and the API still enforces admin access. - Owns page-specific EN/RU translations for static labels, dynamic REST/WebSocket statuses, module-management statuses, mobile filters, and empty states. Language changes are applied through the shared navbar i18n API without requiring a page reload.
How to use:
- Sign in as admin.
- Open
/stats. - Open a user profile from tables/charts.
- Export user actions in needed format and filter window.
- Use
Refresh schedule cacheafter semester id changes to remap cached schedule entities and refresh current-semester data immediately.
Files:
main_site_frontend/studio.htmlmain_site_frontend/js/studio.js
What it does:
- Quick compile mode for text payloads.
- Project mode for multi-file workspaces.
- Supports create/edit/rename/delete files, upload assets, compile, export ZIP.
- Supports sending compiled project PDF directly to linked Telegram account.
- Follows the global website theme and switches Monaco between
vs-lightandvs-dark.
How to use:
- Open
/studio. - Pick quick mode or create project.
- Edit content, compile, inspect result.
- Toggle the site theme from the navbar or command palette when needed.
- Optionally export ZIP or send compiled PDF to Telegram.
Files:
main_site_frontend/js/runtime_config.jsmain_site_frontend/js/ui_utils.js
What it does:
- Resolves API base in this order:
window.__MPB_API_BASE__<meta name="mpb-api-base">- fallback
/api - Shared popup helper
window.mpbPopup(message, options)replaces raw browser alerts.
How to use:
- Set runtime override before scripts when needed:
<script>
window.__MPB_API_BASE__ = "https://api.ivantishchenko.ru/api";
</script>- Use popup helper from JS modules:
window.mpbPopup("Saved", { type: "success" });Entry point:
/docs/redoc
Feature details:
- Swagger UI is branded for Matplobbot instead of using the stock FastAPI styling.
- ReDoc is available as a styled read-only API reference for schema browsing and sharing.
- The info block includes auth instructions for both username/password login and Telegram-issued JWTs.
- JSON endpoints expose concrete request/response schemas, shared error schemas, validation-error examples, and rate-limit response metadata.
- ZIP/PDF/iCal routes document their content types explicitly.
- Operation descriptions use Markdown sections for auth behavior, schedule fallback semantics, admin exports, Studio compile outputs, and calendar feed behavior.
- Protected HTML pages are excluded from the schema so the docs stay API-focused.
How to use:
- Open
/docs. - For password auth, click
Authorizeand enter website credentials; Swagger UI will fetch a token from/api/auth/login. - For Telegram auth, call
/api/auth/telegram, copyaccess_token, then paste that JWT intoAuthorize. - Use the schema panels to inspect payload fields before trying schedule, stats, studio, or calendar endpoints.
- Open
/redocwhen you need a cleaner reference view with grouped tags, Markdown descriptions, and response schema examples.
Source:
fastapi_stats_app/config.pyfastapi_stats_app/rate_limit.pyfastapi_stats_app/main.pyfastapi_stats_app/routers/schedule_router.pyfastapi_stats_app/routers/studio_router.pyfastapi_stats_app/routers/stats_router.py
What it does:
- Loads CORS allowed origins from
FASTAPI_CORS_ALLOWED_ORIGINS, withCORS_ALLOWED_ORIGINSas a compatibility fallback. - Accepts comma, semicolon, or newline separated origins; if unset, the public
ivantishchenko.ruorigins remain the default allowlist. - Applies Redis fixed-window limits to heavy API routes:
-
GET /api/schedule/searchby client IP. -
POST /api/studio/compile,POST /api/studio/projects/{project_id}/compile, andPOST /api/studio/projects/{project_id}/send_telegramby authenticated website user. -
GET /api/stats/users/{user_id}/export_actions?format=weekly_pdfby authenticated admin. - Returns
429withRetry-Afterwhen a bucket is exhausted. - Fails open by default if Redis is briefly unavailable, so the API keeps serving traffic; set
FASTAPI_RATE_LIMIT_FAIL_OPEN=falseto fail closed with503.
How to use:
- Set
FASTAPI_CORS_ALLOWED_ORIGINS=https://example.com,https://api.example.comin the FastAPI environment when deploying under new domains. - Keep Redis reachable from
mpb-fastapi-stats; the limiter uses the shared Redis backend. - Tune limits with
FASTAPI_RATE_LIMIT_SCHEDULE_SEARCH_LIMIT,FASTAPI_RATE_LIMIT_STUDIO_COMPILE_LIMIT, andFASTAPI_RATE_LIMIT_STATS_PDF_EXPORT_LIMIT. - Tune windows with
FASTAPI_RATE_LIMIT_SCHEDULE_SEARCH_WINDOW_SECONDS,FASTAPI_RATE_LIMIT_STUDIO_COMPILE_WINDOW_SECONDS, andFASTAPI_RATE_LIMIT_STATS_PDF_EXPORT_WINDOW_SECONDS. - Use
FASTAPI_RATE_LIMIT_ENABLED=falseonly for controlled local debugging or load testing. - If Redis latency is expected to be high, adjust
FASTAPI_RATE_LIMIT_REDIS_TIMEOUT_SECONDS; the default is intentionally short to avoid tying up request handlers.
Router:
/api/auth/*
Endpoints:
-
POST /api/auth/register(disabled by default; controlled byAUTH_PASSWORD_REGISTRATION_ENABLED) POST /api/auth/loginPOST /api/auth/telegramPOST /api/auth/telegram/webappGET /api/auth/mePOST /api/auth/logoutPUT /api/auth/preferences
How to use:
- Authenticate with login or Telegram endpoint.
- For Telegram Mini Apps, send raw
window.Telegram.WebApp.initDataas{ "init_data": "..." }to/telegram/webapp. - Pass bearer token to protected endpoints.
- Store/update user preferences through
/preferences.
Router:
/api/schedule/*
Endpoints:
GET /api/schedule/searchGET /api/schedule/cached_list-
GET /api/schedule/fallback_counters(admin) GET /api/schedule/data/{type}/{id}-
POST /api/schedule/cache/{type}/{id}/refresh_semester(admin) -
POST /api/schedule/cache/refresh_all_semester(admin)
Feature details:
- Search aliases:
-
lecturer->person -
teacher->person -
room->auditorium - Search terms must contain at least 2 non-whitespace characters; shorter terms return
422. - For mixed entity types with equal relevance, response ordering is deterministic:
group->person->auditorium, then stable lexical tie-break by label/id. - Search automatically falls back to local cache if upstream RUZ fails.
- Search is Redis rate-limited to reduce abusive upstream API fan-out.
- Cached list returns recently cached groups, lecturers, and rooms with
updated_atso the offline drawer can show data freshness. - Schedule data returns:
scheduleavailable_modulesis_offlinesource_updated_atloaded_bounds-
GET /api/schedule/data/{type}/{id}acceptsrefresh=1to force a live refresh attempt even when the local cache is still fresh. - If a legacy Schedule URL or local state passes a non-numeric group, lecturer, or auditorium label such as
ПМ23-1as{id}, the API resolves it through live RUZ search before fetching schedule data, so refresh uses the numeric RUZ entity id. -
POST /api/schedule/cache/{type}/{id}/refresh_semesteris admin-only and forces an immediate current-semester RUZ fetch for one schedule entity. It resolves non-numeric group, lecturer, and auditorium labels to numeric RUZ ids, writes the semester payload tocached_schedules, and fails instead of silently serving old cache when the upstream refresh cannot be completed. -
POST /api/schedule/cache/refresh_all_semesteris admin-only and runs the semester maintenance workflow for cached and subscribed schedule entities: it searches each entity by display name, writes fresh semester data under the current RUZ id, deletes stale cache rows after successful remap, moves active Telegram subscriptions, updates website calendar custom profiles, and returns counters for refreshed, remapped, skipped, and failed entities.
What is_offline means:
- In
GET /api/schedule/data/{type}/{id},is_offline=truemeans live RUZ data was unavailable and the response was assembled from cached schedule data. - In
GET /api/schedule/search,is_offlineis per-result. Mixed responses are possible: some entities may come from live RUZ (false) while others are cache fallback (true). -
is_offline=falsemeans a live upstream response was used for that entity/request path.
Frontend behavior guidance:
- Keep fallback results selectable and renderable; cache fallback is a degraded-but-valid state, not a hard error.
- Surface a visible badge/state (for example
CACHE) when item-level or schedule-levelis_offline=true. - Treat
503from search as a full-source outage state (upstream unavailable and no cache matches), and show retry/help UI. - Use
source_updated_attogether withis_offlineto communicate data freshness to users.
How to use:
- Call
/search?term=...&type=all|group|person|auditoriumwith a term of at least 2 non-whitespace characters. - Use returned entity
type/idwith/data/{type}/{id}. - Optionally pass
base_date=YYYY-MM-DDto center the loaded window. - Pass
refresh=1from an explicit user action such asRefresh cache; do not use it for every automatic navigation.
Router:
/api/stats/*
Endpoints:
GET /api/stats/health-
GET /api/stats/users/{user_id}/profile(admin) -
GET /api/stats/action_users(admin, canonical) -
GET /api/stats/stats/action_users(admin, legacy alias, deprecating) -
GET /api/stats/users/{user_id}/export_actions(admin) -
POST /api/stats/users/{user_id}/send_message(admin) -
GET /api/stats/leaderboard(admin) -
GET /api/stats/activity(admin)
Feature details:
- Sort allowlists are strict and validated.
- Export supports
json|csv|weekly_pdf,date_from,date_to,timezone. -
weekly_pdfexport is Redis rate-limited because it renders a PDF in-process. - Admin send-message has Redis-backed per-admin rate limit and structured audit logs.
- Legacy alias can be hard-disabled with
ENABLE_LEGACY_ACTION_USERS_ALIAS=false.
How to use:
- Authenticate as admin.
- Use profile/action drill-down routes for analytics.
- Use export route for audits/reporting.
- Use send-message route for direct outreach to Telegram users.
Router:
/api/studio/*
Endpoints:
POST /api/studio/compileGET /api/studio/projectsPOST /api/studio/projectsGET /api/studio/projects/{project_id}PUT /api/studio/projects/{project_id}/files/{file_id}POST /api/studio/projects/{project_id}/uploadPOST /api/studio/projects/{project_id}/compileDELETE /api/studio/projects/{project_id}/files/{file_id}PUT /api/studio/projects/{project_id}/files/{file_id}/renameGET /api/studio/projects/{project_id}/export/zipGET /api/studio/projects/{project_id}/assets/{file_path}POST /api/studio/projects/{project_id}/send_telegram
Feature details:
- Project ownership is enforced on all project routes.
-
uploadsupports binary assets up to 5 MB. - Compile pipeline supports build cache reuse for project compile.
- Worker-backed compile and send-to-Telegram routes share the Studio compile rate limit.
How to use:
- Create project.
- Save/edit files and upload assets.
- Compile and preview.
- Export ZIP or send compiled PDF to Telegram.
Routes:
- Authorized profile/config routes under
/api/cal/subscription* - Public feed routes under
/api/cal/{secret}*
Authorized endpoints:
GET /api/cal/subscriptionPOST /api/cal/subscription/resetPOST /api/cal/subscription/togglePOST /api/cal/subscription/selectPOST /api/cal/subscription/profilesPATCH /api/cal/subscription/profiles/{profile_id}DELETE /api/cal/subscription/profiles/{profile_id}
Public feed endpoints:
GET|HEAD /api/cal/{secret}.icsGET|HEAD /api/cal/{secret}/basic.icsGET|HEAD /api/cal/{secret}/profiles/{profile_id}.icsGET|HEAD /api/cal/{secret}/profiles/{profile_id}/basic.icsGET|HEAD /api/cal/{secret}/telegram.icsGET|HEAD /api/cal/{secret}/telegram/basic.ics
Feature details:
- Profile-based feeds with health metadata.
-
ETagandLast-Modifiedfor cache-aware calendar clients. -
download=1forces attachment content disposition.
How to use:
- Use authorized routes from signed-in website session.
- Share only secret URLs with trusted calendar clients.
- Reset secret to revoke leaked links.
Endpoints:
WS /ws/stats/total_actionsWS /ws/bot_logWS /ws/users/{user_id}
Feature details:
- Stats stream sends full live analytics payload when changed.
- Bot log file streaming is disabled because services no longer write
.logfiles. - User-specific stream is restricted to admins or matching Telegram user.
How to use:
- Connect with authenticated websocket session/token.
- Subscribe to needed stream and handle reconnects on disconnect.
- For service logs, use
docker compose logs -f <service>instead of/ws/bot_log.
Source:
scheduler_app/main.pyscheduler_app/jobs.py
Configured jobs:
-
send_daily_schedules(cron, every minute): sends next-day schedules at subscriber-selected times. -
check_for_schedule_updates(interval, every 2h): detects diffs, sends change notifications, and refreshescached_schedules.updated_atafter every successful unchanged API poll for subscribed entities. -
refresh_schedule_entity_ids(cron Sunday 02:30): searches cached/subscribed schedule entities by name to resolve current semester RUZ ids, moves stale subscription/calendar references, and refreshes current-semester cache. -
update_schedule_cache(cron at 04:00 and 16:00): warm cache refresh. -
prune_inactive_subscriptions(cron at 03:00): cleanup inactive subscriptions. -
send_admin_summary(cron, every minute): checks summary schedule and sends due summaries.
Other scheduler features:
- Health endpoint on
:9584/health. - Telegram calls can use
TELEGRAM_PROXY_URLwithPROXY_URLas a backward-compatible fallback. - Scheduler Telegram delivery uses the same normalized proxy selection as the bot, so the local mixed
proxylistener is used ashttp://proxy:20170when applicable. - RUZ calls are forced direct and bypass proxy.
- Correlation IDs in scheduler stdout logs.
- Semester-wide scheduler jobs use the shared
get_semester_bounds()helper instead of duplicated date windows, keeping RUZ requests under the upstream date-range limit.
Source:
bot/logger.pyfastapi_stats_app/main.pyscheduler_app/main.pydocker-compose.ymldocker-compose.prod.yml
What it does:
- Bot, FastAPI, and scheduler logging is console-only through
logging.StreamHandler(). - The shared
bot_logsDocker volume and/app/logsmounts are removed. - Long-running containers use Docker
json-filelog rotation withmax-size=10mandmax-file=3. - Per-container Docker logs are capped at roughly 30 MB for
mpb-telegram-bot,mpb-fastapi-stats,mpb-worker,mpb-scheduler,postgres, andredis. - The
/ws/bot_logendpoint no longer tails a file and returns an informational message instead.
How to use:
- Read live logs with
docker compose logs -f mpb-telegram-botor another service name. - Use
docker compose -f docker-compose.prod.yml logs --tail=200 mpb-fastapi-statson production deployments. - After deploying this change, remove the old named log volume only after confirming no previous stack still needs it, for example
docker volume rm matplobbot_bot_logs. - Keep the
loggingblock on every long-running service that writes useful stdout/stderr output.
Source:
bot/main.pyshared_lib/telegram_http.pyshared_lib/telegram_polling.py
What it does:
- Uses
TELEGRAM_PROXY_URLfor Telegram-only outbound traffic, withPROXY_URLkept as a backward-compatible fallback. -
TELEGRAM_PROXY_TRANSPORTcontrols how Telegram reaches the mixed proxy listener: -
auto: current default, converts localsocks5://proxy:...tohttp://proxy:... -
http: always prefer HTTP proxy mode -
socksortcp: keep SOCKS/TCP mode and do not rewrite the scheme - When
TELEGRAM_PROXY_URLpoints to the local Dockerproxyservice on its mixed listener and transport isauto, Telegram traffic is sent throughhttp://proxy:...to avoid the aiogram SOCKS TLS handshake path. - The bot uses a custom aiogram session wrapper so HTTP proxies go through native
aiohttprequest proxying instead of aiogram'saiohttp_socksproxy connector. - The Mihomo proxy now routes by exact target domain instead of catch-all proxying: Telegram domains use
TELEGRAM-AUTO, OpenAI/ChatGPT domains useOPENAI-AUTO, and everything else stays direct. - The Telegram provider/group health checks probe Telegram directly (
https://api.telegram.org), and theTELEGRAM-AUTOurl-testgroup picks the lowest-latency Telegram-capable node instead of just the first alive node. - The OpenAI provider/group health checks probe
https://api.openai.com/v1/models, accept401/403style responses, and theOPENAI-AUTOurl-testgroup independently picks the lowest-latency OpenAI-capable node. - The bundled production proxy image pins a current Mihomo core version so modern subscription node formats and Telegram-facing HTTP proxy behavior stay compatible.
- The subscription cleaner preserves more VLESS Reality fields when converting provider JSON to Mihomo YAML, including
servername,alpn,skip-cert-verify,packet-encoding,encryption, and ML-KEM support flags. - The proxy bootstrap can also use
OUTLINE_ACCESS_KEYdirectly, including plainss://...access keys andssconf://...dynamic Outline links that resolve to an access payload. - The proxy cleaner now merges nodes from both
SUB_URLandOUTLINE_ACCESS_KEYinto one served provider document, so Mihomo can choose across the union of Happ subscription nodes and the Outline access key instead of forcing an either/or choice. - The Outline cleaner emits JSON-escaped YAML scalars for dynamic access keys, so provider values such as Shadowsocks
prefixstrings with CRLF control characters stay valid for Mihomo parsing. - The proxy keeps localhost and RFC1918 addresses direct so its own subscription refresh path does not recurse back through remote proxy nodes.
- The proxy cleaner now exposes internal diagnostics endpoints on port
8080:/health,/diagnostics,/summary, and/recheck?group=telegram|openai|all. - The proxy image waits for the local cleaner
/healthendpoint before launching Mihomo, which removes the startup race where Mihomo tried to fetch providers before the cleaner was listening. -
/diagnosticsreports the last merged-provider build state plus Mihomo controller snapshots for providers and the active Telegram/OpenAI groups. -
/summaryextracts the practical view you usually need: selected Telegram/OpenAI group member, candidate counts, and the top candidates sorted by the latest known delay. -
/rechecktriggers Mihomo provider health checks and group delay tests immediately, which the bot now uses before retrying a failed Telegram request. - Keeps
ruz.fa.ruout of process-level proxy env viaNO_PROXY, and creates RUZ aiohttp sessions withtrust_env=Falseso schedule fetches stay direct. - The bot session retries a small number of transport-level Telegram request failures before surfacing an error, which helps when a proxy node briefly resets or times out before the request reaches Telegram.
- The proxy groups probe more aggressively (
interval: 15,max-failed-times: 1,lazy: false) so Mihomo re-checks bad nodes quickly after a transport failure instead of waiting through several broken requests. - Treats Telegram/proxy transport failures during startup as retryable instead of fatal.
- Recreates the aiogram bot session for each retry so shutdown cleanup from a failed polling attempt does not poison the next one.
How to use:
- Set
TELEGRAM_PROXY_URLwhen Telegram traffic must go through the proxy container. - Set
TELEGRAM_PROXY_TRANSPORT=tcpwhen Telegram should use the mixed listener as SOCKS/TCP instead of HTTP proxy mode. - Optionally keep
GLOBAL_HTTP_PROXY_URLor legacyPROXY_URLfor other non-RUZ outbound traffic that still needs a process-level proxy. - Do not route
RUZthrough proxy; the app now forces direct aiohttp sessions forruz.fa.ru. - Optionally set
BOT_POLLING_RETRY_DELAY_SECONDSto tune the retry backoff. - Watch
docker compose logs -f mpb-telegram-botforBot polling failed with a retryable network errorwhen diagnosing Telegram reachability problems. - If the proxy container has many nodes, keep its health-check target aligned with the real destination (
api.telegram.org) so Mihomo does not prefer nodes that only pass generic web probes. - Rebuild the
proxycontainer whenproxy/Dockerfile.proxyorproxy/proxy_config.yamlchanges, because the production stack builds that service locally instead of pulling it from GHCR. - If your provider ships Xray-style JSON configs, keep the converter in
proxy/proxy_cleaner.pyaligned with the subscription format so Reality and chained dialer settings survive the translation into Mihomo YAML. - If your provider gives an Outline link, set
OUTLINE_ACCESS_KEYalongsideSUB_URLin.envand rebuild theproxyservice; the cleaner now merges both sources into one provider output instead of choosing one and ignoring the other. - Keep the Mihomo rules domain-specific:
api.telegram.organd related Telegram domains throughTELEGRAM-AUTO,chatgpt.com/openai.comdomains throughOPENAI-AUTO, andMATCH,DIRECTas the default so unrelated traffic does not consume fragile VPN nodes. - If the proxy path is flaky, tune
TELEGRAM_REQUEST_RETRY_ATTEMPTSandTELEGRAM_REQUEST_RETRY_DELAY_SECONDSto retry only transport-level Telegram request failures before a response starts; this reduces failures from brief proxy resets without broadly retrying completed Bot API sends. - If you want Mihomo to choose the fastest available provider node for Telegram or OpenAI, keep
TELEGRAM-AUTOandOPENAI-AUTOasurl-testgroups pointed at the real target domains instead offallbackgroups. - Keep
max-failed-times: 1on the Mihomourl-testgroups when you want a single failed Telegram/OpenAI request to trigger a quick re-check and push later retries toward another node. - If production
.envis generated by Jenkins, exportPROD_OUTLINE_ACCESS_KEYthere as well; the pipeline now appends it, plus optionalPROD_TELEGRAM_REQUEST_RETRY_ATTEMPTSandPROD_TELEGRAM_REQUEST_RETRY_DELAY_SECONDS, after writing the base.env. - Use
http://proxy:8080/diagnosticsfrom another service container orhttp://127.0.0.1:8080/diagnosticsinside the proxy container to inspect the merged node pool and Mihomo’s current Telegram/OpenAI group state. - Use
http://proxy:8080/summaryfor a compact operational view of which Telegram/OpenAI nodes are currently selected and which candidates are next in line by delay. - Use
http://proxy:8080/recheck?group=telegramto force an immediate Telegram-side health recheck when troubleshooting provider failover. - The repo includes
scripts/proxy_summary.py, which fetches/summaryand prints the merged entry counts plus the top Telegram/OpenAI candidates in a human-readable CLI format.
Source:
fastapi_stats_app/routers/stats_router.pymain_site_frontend/stats.htmlmain_site_frontend/js/stats.js
What it does:
- Adds an admin diagnostics block on the site
/statspage that summarizes the proxy cleaner state without leaving the dashboard. - Fetches
/api/stats/proxy_diagnostics, which normalizes the proxy cleaner/summaryresponse into a stable UI contract. - Shows the currently selected Telegram and OpenAI nodes, merged node inventory, the summary source URL, and a latency-ranked per-server table.
- Fails softly when the proxy cleaner is unreachable, so the main stats widgets still load while the diagnostics panel shows the upstream error.
How to use:
- Keep the proxy cleaner reachable from FastAPI at
http://proxy:8080/summaryinside Docker, or setPROXY_SUMMARY_URLwhen the summary endpoint lives elsewhere. - Open the site
/statspage with an admin account and pressDiagnostics. - Read
Telegram selected nodeandOpenAI selected nodefirst to confirm which Mihomo candidates are active right now. - Use the table rows to compare the latest known latency and liveness per candidate server for each route group.
- If the panel reports
Proxy summary unavailable, verify the proxy container, then check/summarydirectly or usescripts/proxy_summary.py.
Source:
shared_lib/telemetry.pyshared_lib/celery_app.pyfastapi_stats_app/telemetry.pybot/tracing.py
What it does:
- Enables OTLP trace export for FastAPI, the Telegram bot, and Celery workers.
- Creates spans for FastAPI requests, Telegram bot update handling, Celery task publish, and Celery task execution.
- Propagates W3C trace context plus the existing correlation ID through Celery headers so worker traces stay attached to the originating request or bot update.
- Instruments
aiohttpclient requests so outbound Telegram, GitHub, and other HTTP calls appear inside the same trace tree.
How to use:
- Set
OTEL_ENABLED=trueor provideOTEL_EXPORTER_OTLP_ENDPOINTorOTEL_EXPORTER_OTLP_TRACES_ENDPOINT. - Point the exporter at your collector, for example
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318. - Optionally set
OTEL_EXPORTER_OTLP_HEADERS,OTEL_DEPLOYMENT_ENVIRONMENT, andOTEL_SERVICE_NAMESPACEto match your collector and environment conventions. - Restart
mpb-fastapi-stats,mpb-telegram-bot, andmpb-workerafter changing tracing env vars. - Look for service names
matplobbot-fastapi,matplobbot-bot, andmatplobbot-workerin your tracing backend. - Use the existing
X-Request-IDand[cid=...]log fields to line up log lines with exported spans during incident analysis.
Source:
requirements.inrequirements.txtfastapi_stats_app/requirements.txtscheduler_app/requirements.txt.github/workflows/ci-cd.yml.github/workflows/dependency-audit.ymlJenkinsfile.groovyscripts/build_audit_requirements.pysetup.py
What it does:
- Pins
Pillowto a non-vulnerable release range (>=12.3.0,<13) and locksrequirements.txtto12.3.0. - Pins
python-dotenvto a non-vulnerable release range (>=1.2.2,<2) and locksrequirements.txtto1.2.2. - Pins
aiogramto3.29.1so the bot and scheduler can use the currentaiohttp 3.14.xrelease line without the old<3.14resolver cap. - Pins
aiohttpto the non-vulnerable3.14.3release across bot, scheduler, and shared package metadata. This is the minimum version that clearsPYSEC-2026-3545;PYSEC-2026-3546andPYSEC-2026-3547are fixed by3.14.2, but the lock must stay at least3.14.3. - Pins FastAPI to
0.136.3and Starlette to1.3.1infastapi_stats_app/requirements.txtso the stats service stays on a Starlette release line with the current multipart and request parsing fixes. - Uses an in-repo HS256 JWT implementation for FastAPI access tokens, avoiding the no-fix
python-joseJWE advisory while keeping existing bearer-token behavior. - Removes unused
markdownfrom the bot/worker requirements; Markdown rendering usesmarkdown-it-py. - Pins
python-multipartto0.0.31for multipart parser DoS fixes. - Pins
setuptoolsto83.0.0andweasyprintto69.0in the root requirements lock for the current audit gate. - Uses
scripts/build_audit_requirements.pyto build the same filteredaudit-requirements.txtin GitHub Actions, Jenkins, and local checks. The builder excludes editable installs and the localmatplobbot-sharedpackage, deduplicates matching pins, and fails on conflicting pins. - Keeps GitHub Actions and Jenkins
python -m pip_audit --strictgreen with a documented ignore forPYSEC-2024-277only. That finding is a disputed, no-fixed-versionjoblibadvisory pulled transitively bymatplobblibvia scikit-learn; this project does not load untrusted joblib pickle files. - Runs a separate scheduled Dependency Audit workflow every day at
03:17 UTC, so new advisories that appear after the last dependency change still fail CI.
How to use:
- If CI reports a new dependency advisory, update the minimum safe version in
requirements.in. - Refresh the lock in
requirements.txtand update service-specific pins such asfastapi_stats_app/requirements.txt. - Run
python scripts/build_audit_requirements.pyand thenpython -m pip_audit --strict -r audit-requirements.txt --ignore-vuln PYSEC-2024-277locally before merging dependency changes. - Use
--ignore-vulnonly for advisories with no fixed release or a verified non-applicable code path, and document the reason next to every CI/Jenkins command that carries the ignore. - Keep
setup.pyaligned for editable/local installs so dev and CI environments do not drift.
Source:
main_site_frontend/default.conf
What it does:
- Uses Docker DNS (
127.0.0.11) for runtime upstream resolution ofmpb-fastapi-stats. - Prevents the frontend Nginx container from crashing on startup when the API container is not yet resolvable during compose boot.
How to use:
- Keep
/api/cal/*routed through the internalmpb-fastapi-stats:9583upstream. - If the upstream service name changes in compose, update
main_site_frontend/default.confto match. - After changing frontend proxy routing, redeploy
main-site-frontendso Nginx reloads the updated config.
Source:
shared_lib/tasks.py
Tasks include:
- LaTeX compile/render.
- Mermaid render.
- Markdown to PDF render.
- Markdown to HTML render.
- Full project compile with build cache.
How to use:
- Bot/API enqueues task.
- Worker executes and returns serialized result.
- Caller sends output to user/UI.
What it does:
- Schedule fetch pipeline prefers live university API.
- Falls back to cached schedule when upstream fails.
- Tracks source outcomes in counters:
ruz_api_successcache_fallbackno_cache
How to use:
- Check
GET /api/schedule/fallback_countersas admin. - Correlate spikes in fallback/no-cache with upstream incidents.
Source:
fastapi_stats_app/routers/stats_router.pyshared_lib/schemas.pymain_site_frontend/stats.htmlmain_site_frontend/js/stats.js
What it does:
- Adds an admin-only
Modulestab on/stats. - Lists manual
discipline_name -> module_namemappings fromdiscipline_modules. - Lets admins create, update, search, filter, and delete mappings from the website.
- Uses the same mapping table as the Telegram
/set_module Discipline | Modulecommand, so schedule module filters consume one shared source of truth. - Keeps the selected tab in the URL with
/stats#modules. - Participates in the Stats page local i18n refresh loop, so tab labels, form controls, table actions, and loaded/saving/error statuses switch EN/RU without a reload.
How to use:
- Sign in as an admin and open
/stats#modules. - Enter the full discipline name exactly as it appears in the schedule.
- Enter or pick a module name such as
Военная кафедра. - Save the mapping, then refresh the schedule page if it already has loaded module filters.
- Use Edit for typo fixes and Delete only when a discipline should no longer be grouped into a manual module.
CI workflows:
.github/workflows/ci-cd.yml.github/workflows/autolint-autofix.yml.github/workflows/stats-visual-regression.yml.github/workflows/sync-wiki.yml
Pipeline features:
- Lint/test/type/security gates.
- Shared package version consistency checks.
- Auto version patching.
- Shared package publish to PyPI.
- Docker image build/push to GHCR.
- Stats visual baseline capture artifact.
- Wiki sync from
docs/wiki.mdto GitHub WikiHome.md.
Jenkins + deploy features:
-
Jenkinsfile.groovyruns a pre-deploy quality gate before touching production. - The quality gate creates
.jenkins-venv, installs project dependencies, checks critical FastAPI/test imports, runsruff check . --select E9,F63,F7,F82, and runspython -m unittest discover -s tests -v. - The gate fails if unittest output shows dependency-driven skips/import errors such as missing FastAPI modules.
-
Jenkinsfile.groovyperforms production deploy and smoke checks. - Deploy host fingerprint pinning via
APP_VM_SHA256(with optional one-off override). -
deploy.shpre-pulls only the GHCR application services, retries transient registry/network pull failures, and avoids unnecessary Docker Hub pulls for stable infra services on routine deploys. -
deploy.shalso rebuilds local build services such asproxyand restarts config-mounted services such asmain-site-frontendandcaddyso repo changes are actually applied in production.
How to use:
- Push to
mainto run CI and image publishing. - Start the Jenkins deploy job; it must pass the pre-deploy quality gate before deployment starts.
- Jenkins deploy job pre-pulls the tagged GHCR app images and runs smoke checks; routine deploys reuse already-cached
redis,postgres,nginx, andcaddyimages instead of re-pulling them every time. - If you changed a pinned infra image tag or are deploying onto a fresh host with no cached infra images, pre-pull them once before the rollout, for example:
docker compose -f docker-compose.prod.yml pull redis postgres main-site-frontend caddy - Keep
WIKI_PUSH_TOKENconfigured for automatic wiki mirror updates.
- Public calendar links are secrets. Rotate immediately if exposed.
- Legacy stats alias
/api/stats/stats/action_usersis deprecating; migrate clients to/api/stats/action_users. - Website API base can be switched per environment with
window.__MPB_API_BASE__. - Bot and website schedule features are intentionally coupled through shared subscription data and cached schedule sources.