Live-дашборд «Вступ 2026»
Метадані
Section titled “Метадані”| Поле | Значення |
|---|---|
| Статус | 🚧 задеплоєно на Cloudflare Pages за Cloudflare Access (приватно, лише власник); публічно ще не відкрито |
| Поверхні | окремий дашборд на CF Pages (edge-static), не web-app abitly.org |
| Доступність | наразі приватно (email-SSO власника); публічне відкриття — рішення власника |
| Власник | TODO: |
| Останнє підтвердження | 2026-07-20 · CF Pages live (за CF Access) + read-only pull прод-БД + Playwright-рев’ю графіка |
Призначення
Section titled “Призначення”Живий публічний дашборд перебігу вступної кампанії-2026: подані заяви, конкурс, найпопулярніші напрями/ЗВО, розподіл балів НМТ і «Гонка спеціальностей» — як прогноз попиту із симулятора Abitly переходить у реальні подані заяви. Дизайн — темний, мінімалістичний (monobank-teardown), кожен блок самодостатній для скріншота в канал/медіа. Усе на реальних даних.
Три плани даних (усі реальні):
- ЄДЕБО (
vstup.edbo.gov.ua/statistics/date) — національний попит: заяви/особи за днями (снапшот: 327 795 заяв / 185 337 осіб). - Abitly Prod DB (
studsearch-prod, схемаabitly) — 92 401 бюджетне місце, 25 223 абітурієнти-2026, конкурс 3,5, продуктові вибори напрямів/ЗВО. - УЦОЯО — розподіл балів НМТ-2025 (пул-2026 складав ті самі тести).
Архітектура: snapshot-once, read-from-cache
Section titled “Архітектура: snapshot-once, read-from-cache”Дашборд публічний і може отримати вірусний сплеск (репост у медіа) — тому жоден
візит не торкається БД. Уся важка робота виконується рідко плановим джобом і
матеріалізується в один незмінний snapshot.json (~6 КБ); сайт — статика, читає
лише цей файл з CDN. 100 000 відкриттів/годину = 100 000 віддач з edge і 0 запитів
у Postgres (БД бачить лише 2 запуски генератора на добу).
flowchart LR
edbo["ЄДЕБО статистика<br/>(scrape)"] --> build
prod[("Prod DB 2026<br/>read-only, PII-free")] --> build
ucoqo["УЦОЯО НМТ-2025<br/>(baked)"] --> build
build["build_snapshot.py"] --> snap["snapshot.json"]
snap --> cdn["CDN edge (Cloudflare)"]
cdn -->|"0 запитів у БД"| browser["браузер · inline-SVG, 0 залежностей"]
Клієнт (app.js, vanilla, 0 залежностей) малює всі графіки інлайновим SVG;
fetch('data/snapshot.json') — один запит на візит, повністю з CDN.
Блоки дашборда
Section titled “Блоки дашборда”- Hero — заяв подано у кампанії (велика цифра) + KPI: абітурієнти, заяви/особу, бюджетні місця, конкурс.
- «Заяви за днями» — кумулятивна крива поданих заяв (ЄДЕБО), hover за будь-який день.
- «Найпопулярніші спеціальності / ЗВО» — дві смуги: помаранчева = унікальні абітурієнти, що розглядають напрям у симуляторі Abitly (з 19 липня), синя = унікальні особи, що вже подали заяви в ЄДЕБО.
- «Гонка спеціальностей у часі» — стрімграф прогнозу + перемикач «Прогноз → реальні заяви» (див. нижче).
- «Розподіл балів НМТ · де мій бал» — інтерактивна гістограма УЦОЯО-2025: обери предмет, встав свій бал → перцентиль.
- Roadmap — ключові дати за Порядком прийому-2026.
«Гонка спеціальностей у часі» — ключовий графік
Section titled “«Гонка спеціальностей у часі» — ключовий графік”Хендрольнутий SVG-стрімграф (центрована wiggle-база, inside-out порядок шарів, Catmull-Rom згладжування) у тому ж 0-залежному ідіомі, що й решта графіків. Має два режими через перемикач.
Режим OFF — прогноз (намір). X = дні (28.06 → сьогодні), кожна смуга — напрям,
ширина = кумулятивна кількість унікальних абітурієнтів-2026, що тримають напрям
пріоритетом №1–2 у своєму списку в симуляторі. Топ-12 напрямів + згорнутий хвіст
«Інші»; hover показує склад пулу за будь-який день. Щоденна історія попиту копиться
append-only знімками у схемі admission_timeline (abitly_dev) і вплітається у
snapshot.json (початково крива реконструювалася з simulation_application.createdAt —
min(createdAt) рядків із пріоритетом 1/2; аудит-логу змін КП немає, тож минулі
видалення/перепріоритезації історично не відновлюються).
Режим ON — «Прогноз → реальні заяви». Смуги продовжуються з прогнозу в
реальність: ліворуч від пунктирної межі — намір (та сама щоденна крива), праворуч
кожна смуга «перетікає» в те, куди абітурієнти реально подали заяви тим самим
пріоритетом №1–2 — за опрацьованими рейтинговими списками ЄДЕБО-2026
(wide_competition.applications, дедуп за особою). Той самий метрик з обох боків,
тож морф «яблуко-до-яблука». Знімок: прогноз 5 229 у топ-2 → реальність 9 726
(8 370 унікальних осіб). Наочно видно розрив намір≠факт: Психологія 179 → 539,
Медицина 187 → 385, тоді як деякі (Економіка, Міжнародні відносини) просіли.
Дані та API
Section titled “Дані та API”Немає api-v2 — дашборд статичний, читає лише snapshot.json. Генератор
(collect_prod_db.sh + build_snapshot.py) тягне агрегати read-only:
| Джерело | Entity / запит | Призначення |
|---|---|---|
| ЄДЕБО | vstup.edbo.gov.ua/statistics/date (scrape) | національні заяви/особи за днями |
| Prod DB | simulation_application + offers + specialities + users | прогноз-стрімграф (пріоритет 1/2 по днях) і топ напрямів/ЗВО |
| Prod DB | wide_competition.applications (пріоритет 1/2, дедуп pib) | реальність для морфу прогноз→факт + сині смуги ЄДЕБО-осіб |
| Prod DB | offers (max_budget_licence, year=2026) | бюджетні місця, конкурс |
| Prod DB | premium_orders | продуктові показники (продажі симуляції) |
| УЦОЯО | статичний агрегат НМТ-2025 (data/nmt_2025.json) | гістограма «де мій бал» |
Похідне у snapshot.json: cohort.spec_stream = {days[], series[{code,name,data[],reality}] + «Інші», reality_total, reality_people}.
Деталі write-path, кешування й SQL — в ARCHITECTURE.md артефакту.
Зв’язки з іншими фічами
Section titled “Зв’язки з іншими фічами”- simulation — джерело прогнозу (пріоритет №1–2 у конструкторі вступліста); стрімграф — його агрегат у часі.
- wide-competition — той самий реальний план даних (
wide_competition.applications); дашборд бере з нього «реальність». - priorities — пріоритет заяви, за яким рахується топ-2 з обох боків морфу.
- abitly-analytics — сусідня аналітична поверхня (
abitly.org/analytics); дашборд — окремий publish-канал тієї ж моделі «снапшот замість live-обчислень».
Гітігнорний артефакт у хаб-воркспейсі (не в публічному репо):
| Шлях | Примітка |
|---|---|
.context/vstup-2026-live/index.html | структура сторінки (блоки-картки) |
.context/vstup-2026-live/assets/app.js | рендер + анімації + інтерактив (inline-SVG, 0 залежностей); renderStreamgraph() з морфом прогноз→реальність |
.context/vstup-2026-live/assets/style.css | дизайн-система (dark, one-accent + стрім-палітра) |
.context/vstup-2026-live/build_snapshot.py | генератор снапшота (зливає джерела → snapshot.json) |
.context/vstup-2026-live/collect_prod_db.sh | write-path: read-only агрегати з прод-БД (SSM-тунель, statement_timeout, PII-free) |
.context/vstup-2026-live/ARCHITECTURE.md, README.md | архітектура даних/кешування + запуск |
Обмеження та блокери
Section titled “Обмеження та блокери”- Приватний за Cloudflare Access: задеплоєно на CF Pages (
abitly-vstup-live.pages.dev), але вхід лише для власника (email-SSO); публічне відкриття — рішення власника. - Реальність — знімок без щоденної історії (немає часової осі в
wide_competition/offer_requests), тож права частина морфу — кінцева точка, а не крива. - Часткове покриття реальності:
wide_competition.applications— лише опрацьовані рейтингові списки (≈10,8 тис. осіб, зростає, коли ЗВО обробляють заяви); прогноз — вибірка симулятора (~25 тис. абітурієнтів). - Пріоритет прогнозу «пінується» до
createdAtвцілілих рядків (немає аудит-логу КП) — минулі перепріоритезації/видалення не видно. - Оновлення даних — рідко (планово 2×/добу / вручну), не realtime; бейдж свіжості показує «станом на …» чесно.
- Команда-виключення застосована; у
snapshot.json— нуль ПД (лише агрегати).
Історія змін
Section titled “Історія змін”| Дата | Подія | Джерело |
|---|---|---|
| 2026-07-19 | Дашборд-каркас: hero, крива заяв, топ спеціальностей/ЗВО, НМТ-розподіл, roadmap; snapshot-пайплайн (ЄДЕБО + Prod DB + УЦОЯО → snapshot.json → CDN); Playwright-рев’ю | артефакт .context/vstup-2026-live/ |
| 2026-07-20 | Стрімграф «Гонка спеціальностей» — прогноз попиту (пріоритет №1–2, кумулятив по днях, топ-12 + «Інші»), хендрольнутий SVG (wiggle + inside-out + Catmull-Rom) | collect_prod_db.sh (spec_stream), build_snapshot.py, renderStreamgraph() |
| 2026-07-20 | Перемикач «Прогноз → реальні заяви»: морф кожної смуги з прогнозу в реальні подані заяви ЄДЕБО тим самим пріоритетом (пунктирна межа + зона «реальність · зараз»); реальність — знімок, перехід — лінійний морф | wide_competition.applications (spec reality), renderStreamgraph({reality:true}) |