Статычны сайт (React + Vite) з хуткім пошукам адразу па трох афіцыйных спісах — Рэспубліканскім спісе экстрэмісцкіх матэрыялаў (суды), пераліку экстрэмісцкіх фарміраванняў (МУС/КДБ) і пераліку фізічных асоб, прычастных да экстрэмісцкай дзейнасці (МУС), — і па чацвёртай, неафіцыйнай базе: беларусы ў вышуку МУС РФ паводле штодзённай выбаркі Медыязоны-Беларусь. Выдача змяшаная; запісы першага спісу маюць чырвоную палоску і плашку «Матэрыял · <арт>», другога — фіялетавую палоску і плашку «Фарміраванне · МУС/КДБ», трэцяга — бірузовую палоску і плашку «Асоба · ...», чацвёртага — янтарную палоску і плашку «Вышук РФ · <ведамства>».
data/materials.json база — крыніца праўды (тып, назва, суд, дата, №, дададзена/выдалена)
data/meta.json дата абнаўлення, крыніца, колькасць
data/formations.json другі спіс: экстрэмісцкія фарміраванні МУС/КДБ (назва, спасылкі, падстава, даты, даведка)
data/formations-meta.json дата праверкі і стан крыніцы другога спісу (асобна, каб не чапаць meta.json)
data/persons.json трэці спіс: фізічныя асобы з пераліку МУС (імя, транслітарацыя, грамадзянства, дата нараджэння, прысуд, даты, даведка, нумар .doc-часткі)
data/persons-meta.json дата праверкі, стан крыніцы і спіс .doc-частак трэцяга спісу
data/wanted.json чацвёрты спіс: беларусы ў базе вышуку МУС РФ паводле Медыязоны (імя, год нараджэння, нацыянальнасць, рэгіён і ведамства-ініцыятар, даты вышуку, іншыя напісанні, катэгорыя)
data/wanted-meta.json дата праверкі, стан крыніцы і дата файла Медыязоны (sourceDate) чацвёртага спіса
data/notified.json id запісаў, ужо дасланых у Telegram — абарона ад паўторных дайджэстаў
scripts/update.mjs спампоўвае афіцыйны спіс → разбор табліцы → даўнясенне новых запісаў у базу
scripts/parse.mjs разбор табліцы .doc → запісы (тып, назва, суд, дата, стабільны id)
scripts/update-formations.mjs другі спіс: старонка МУС (пререндэр ?_escaped_fragment_=) → .xlsx → даўнясенне ў data/formations.json
scripts/parse-formations.mjs разбор радкоў xlsx → запісы (id = назва + першае рашэнне, устойлівы да дапісаных рашэнняў)
scripts/update-persons.mjs трэці спіс: тая ж старонка МУС → усе .doc «Перечень граждан … Часть N» (з паўторамі спампоўкі) → data/persons.json
scripts/parse-persons.mjs разбор табліцы .doc па «якары» (падстава + дата ўключэння): id = імя + дата нараджэння + першая дата ўключэння; пазнаванне праўак
scripts/update-wanted.mjs чацвёрты спіс: JSON Медыязоны (brotli) → data/wanted.json; калі файл пераехаў — пошук адраса праз старонку і бандл віджэта
scripts/parse-wanted.mjs разбор JSON (id = імя + год нараджэння), зліццё mergeWanted: выключаныя ў крыніцы → removed без даты; пазнаванне праўак; пошук адраса файла
scripts/xlsx.mjs мінімальны чытач .xlsx без залежнасцяў (ZIP праз node:zlib + XML рэгулярнымі выразамі)
scripts/common.mjs агульнае для абнаўляльнікаў і зборкі: шляхі, fetch/спампоўка з таймаўтамі і праверкай паўнаты файла, readJson, запіс sourceError у мету, runMain
scripts/merge.mjs агульнае зліццё mergeList для чатырох абнаўляльнікаў + пазнаванне праўак: «зніклы» + «новы» з тым жа судом і амаль той жа назвай — адзін запіс
scripts/alert.mjs службовыя паведамленні адміну ў Telegram: збой джоба, змена стану крыніцы
scripts/alert-logic.mjs чыстае параўнанне стану крыніц (для alert.mjs)
scripts/notify.mjs дайджэст новых запісаў у Telegram-канал (калі зададзеныя сакрэты)
scripts/digest.mjs чыстае фарматаванне Telegram-дайджэсту (для notify.mjs)
scripts/build-index.mjs усе чатыры базы → public/data/{index.json, chunks/N.json, meta.json}: адзін індэкс з пазнакай спіса (генеруецца пры зборцы, у git не трапляе)
scripts/index-rows.mjs радкі індэкса, фрагменты, крос-спасылкі пералік МУС ↔ вышук РФ (linkLists) і RSS (для build-index.mjs)
scripts/geo.mjs GEO: robots.txt, llms.txt, llms-full.txt, sitemap.xml, opensearch.xml, 404.html, security.txt, статычныя FAQ-старонкі
scripts/geo-plugin.mjs Vite-плагін: JSON-LD, meta з жывымі лічбамі, кантэнт для краўлераў без JS, CSP у <meta>
scripts/csp.mjs CSP: палітыка і sha256-хэшы інлайн-скрыптоў і стыляў, палічаныя з гатовага HTML
src/lib/ чыстая логіка, агульная для Node і браўзера
normalize.js нармалізацыя (захоўвае даўжыню → дакладная падсветка), парсер запыту, дыяпазоны супадзенняў
identity.js замарожаная нармалізацыя для id запісаў (не мяняць: ад яе залежаць спасылкі і спісы назірання)
court.js назва суда, дата рашэння
person.js трэці спіс: суд і артыкулы КК з прысуду, група артыкулаў для статыстыкі
wanted.js чацвёрты спіс: ведамства-ініцыятар → серыя статыстыкі, даты вышуку («да …»), імя ВЯЛІКІМІ → звычайны рэгістр, removed без даты
search.js фільтр + сартаванне
results.js канвеер пошуку (runSearch): дакладна → транслітарацыя → прыблізныя словы; падлік па спісах
translit.js кірыліца ↔ лацінка (руская транслітарацыя і беларуская лацінка), і ↔ и
fuzzy.js прыблізны пошук (Левенштэйн па словах корпуса), калі дакладных супадзенняў няма
watch.js праверка спісу назірання па індэксе
whatsnew.js логіка старонкі «Новае»: дададзеныя/зніклыя за 30 дзён, групоўка па даце, фолбэк без гісторыі
stats.js агрэгацыя запісаў для таймлайна статыстыкі
format.js фарматаванне дат, акно «Новага» (30 дзён), парог састарэласці (36 гадзін)
api.js загрузка індэкса і ленівых фрагментаў (з кэшам)
entry.js запыт з уваходнай спасылкі (?q= / #q=) → history.state, адрас ачышчаецца
i18n.js тэксты інтэрфейсу (be/en) і спасылкі
notifications.js браўзернае апавяшчэнне спісу назірання (праз service worker, дзе іначай нельга)
wipe.js «Ачысціць усё»: localStorage, sessionStorage, кэшы, service worker
faq.js факты пра сайт і FAQ (бе/en) — крыніца для старонак, llms.txt і Schema.org
src/hooks/ useIndex (з «праверыць зноў»), useRecord (ленівы фрагмент), useQuery (запыт у history.state, не ў адрасе), useHashRoute (#/new, #/stats, #/r/<id>), useWatchlist, useOnline, useLocalStorage, useLang
src/components/ Header, Nav, SearchBar, Options, Facets, WatchPanel, ResultList, ResultItem, Highlight, WhatsNew, RecordPage, Consequences, StatsPage, Timeline, HelpDialog, LangToggle, ThemeToggle, ErrorBoundary, icons (агульныя SVG)
public/sw.js service worker: афлайн-рэжым (абалонка + база ў кэшы)
public/feed.xml RSS новых запісаў (генеруецца пры зборцы, у git не трапляе)
test/ Vitest
.github/workflows/ абнаўленне базы двойчы на дзень + зборка і дэплой на GitHub Pages
.github/dependabot.yml абнаўленні дзеянняў і npm
Пералік «организаций, формирований, ИП, причастных к экстремистской деятельности» МУС публікуе .xlsx-файлам у навіне на сваім сайце (старонка — SPA, пререндэраны HTML аддаецца з ?_escaped_fragment_=). npm run update:formations знаходзіць файл, разбірае яго без залежнасцяў (scripts/xlsx.mjs) і даўносіць новыя запісы ў data/formations.json; у CI гэта асобны крок, які ідзе раз на суткі (ранішні запуск) і не спыняе абнаўленне матэрыялаў пры збоі. Пры зборцы ўсе чатыры базы трапляюць у адзін індэкс з пазнакай спіса, таму пошук, спіс назірання, «Новае», RSS, Telegram-дайджэст і пастаянныя спасылкі працуюць па ўсіх спісах без асобнай логікі.
- У выдачы запісы пераліку пазначаныя фіялетавай палоскай і плашкай «Фарміраванне · МУС/КДБ» (для «экстрэмісцкіх арганізацый», ліквідаваных судом, — «Арганізацыя · суд»); укладкі-спісы пад пошукам («Усе · Матэрыялы · Фарміраванні · Асобы · Вышук РФ», з лічбамі знойдзенага ў кожным спісе) абмяжоўваюць выдачу адным спісам. Старонка запісу паказвае ўсе палі пераліку: кароткую назву, спасылкі, адрас, падставу, дату ўключэння, даведку і апісанне лагатыпа.
- id запісу — ад назвы і першага рашэння («18.10.2021 № 1ЭК»): дапісаныя пазней рашэнні і праўкі даведкі не ствараюць «новы» запіс, а моўчкі абнаўляюць тэкст.
- «Новае», RSS і дайджэст пры першым імпарце маўчаць (
added: null); новымі лічацца толькі запісы, якія з’явіліся ў наступных абнаўленнях. - Статыстыка (
#/stats) мае пераключальнік «Матэрыялы · Фарміраванні · Асобы · Вышук РФ»: для другога спісу той жа таймлайн, але серыі — хто прыняў рашэнне (МУС / КДБ / суд). У адзін графік спісы не змешваюцца (сотні матэрыялаў у месяц схавалі б адзінкі фарміраванняў); GEO-факты па гадах — толькі матэрыялы. - Засцярогі тыя ж: менш за 100 запісаў у файле, знікненне больш чым
max(20, 5 %)запісаў (г.зн. больш за 20 і разам з тым больш за 5 % базы) ці больш заMAX_ADDED(100) новых за раз спыняюць абнаўленне; крыніца недаступная або спрацавала засцярога —sourceErrorуformations-meta.json, папярэджанне ў шапцы і адмін-алерт. Адрас старонкі можна перавызначыць зменнайFORMATIONS_SOURCE; лакальны файл —node scripts/update-formations.mjs шлях/да/файла.xlsx. - Спісы фізічных асоб (
.docна той жа старонцы) — трэці спіс, гл. ніжэй.
«Перечень граждан Республики Беларусь, иностранных граждан или лиц без гражданства, причастных к экстремистской деятельности» МУС публікуе на той жа старонцы некалькімі .doc-файламі («Часть 1…N»): старыя часткі не мяняюцца, апошняя дапаўняецца амаль штотыдня. npm run update:persons знаходзіць усе часткі па подпісе спасылкі, спампоўвае іх (з паўторамі — сервер МУС часам абрывае вялікія файлы; абарваны файл не разбіраецца і бярэцца зноў), разбірае табліцу і даўносіць запісы ў data/persons.json. Усё ці нічога: калі хоць адна частка не спампавалася або спрацавала засцярога, база не кранаецца, а ў persons-meta.json пішацца sourceError (папярэджанне ў шапцы, адмін-алерт). На ўсе спампоўкі разам — ліміт 18 хвілін (PERSONS_BUDGET_MS), каб крок ніколі не паваліў увесь джоб. У CI гэта асобны крок пры кожным запуску (двойчы на дзень), які не спыняе абнаўленне матэрыялаў і дэплой.
- Разбор ідзе не па радках, а па «якары»: ячэйка падставы («Вступивший в законную силу приговор … статьи 342 УК») з датай побач (нараджэння перад ёй ці ўключэння за ёй). Так пераносяцца нераўнамерныя межы радкоў word-extractor, пустыя ячэйкі на разрывах старонак, лішняя ячэйка пасля імя ў свежай частцы, пустое грамадзянства і новыя запісы яшчэ без нумара. Выключаныя асобы (нумар з прочыркамі) прапускаюцца.
- id запісу — ад імя, даты нараджэння і першай даты ўключэння: перанумарацыя частак, дапісаная другая дата ўключэння, змена даведкі ці адраса моўчкі абнаўляюць тэкст. Выпраўленая памылка друку ў імені ці даце нараджэння пазнаецца як праўка (
pairPersonEdits), а не як новы чалавек. - У выдачы — бірузовая палоска і плашка «Асоба · ...» (паводле артыкулаў), імя, лацінская транслітарацыя, дата нараджэння («д.н.») з грамадзянствам (каб адрозніць цёзак), прысуд. Нумар МУС (калі ўжо прысвоены) і спасылка на .doc-частку пераліку — сярод палёў на старонцы запісу. Шукаецца імя кірыліцай і лацінкай, дата нараджэння, артыкулы КК і суд з прысуду, дата ўключэння; адрас (месцазнаходжанне) і грамадзянства ў індэкс не трапляюць — толькі ў фрагменце запісу (картка і старонка). Укладка «Асобы» пад пошукам абмяжоўвае выдачу гэтым спісам.
- Даведка з пераліку («судзімасць не пагашана», «адбывае пакаранне») разбіраецца і застаецца ў
data/persons.json(па ёй бачныя праўкі ў крыніцы), але на сайт не ідзе — ні ў фрагмент, ні ў картку, ні на старонку запісу: МУС не абнаўляе яе ва ўжо апублікаваных частках, таму ў старых запісах яна часта састарэлая. - Спасылка на першакрыніцу:
assignParts(update-persons.mjs) піша ў кожны запіс, які цяпер ёсць у крыніцы, нумар.doc-часткі (part), аpublicMetaаддае адрасы частак уmeta.persons.files(па парадку частак; лакальны запуск зfile://— не аддае). Старонка запісу робіць з іх знешнюю спасылку «Частка N (.doc)» з папярэджаннемExtLink. Для запісу, які знік з крыніцы, спасылкі няма — у файле яго ўжо не будзе. - Статыстыка (
#/stats/p): таймлайн па даце ўключэння ў пералік, серыі — група артыкулаў КК у прысудзе (342/293 групавыя дзеянні; 130, 367–370 выказванні; 361-х экстрэмізм; іншыя),src/lib/person.js. - Дайджэст, RSS і «Новае» — як і для іншых спісаў: імя, артыкулы, суд і дата ўключэння; дата нараджэння і адрас у канал не ідуць. Пры першым імпарце маўчаць (
added: null). - Засцярогі: менш за 1000 запісаў разам, менш за 50 у любой частцы, акрамя апошняй (новая «Часть N» першыя тыдні законна маленькая), раней бачаная частка паменшылася больш чым на 2 % (
partCountsу меце), знікненне больш чымmax(20, 5 %)запісаў ці больш заMAX_ADDED(300) новых за раз спыняюць абнаўленне. Парсер лінейны і абразае ячэйкі даўжэйшыя за 5 000 сімвалаў — чужы файл не можа падвесіць джоб; лішнія ячэйкі сапсаванага радка адкідаюцца і лічацца (parseу меце), а не становяцца чыімсьці імем. Адрас старонкі —PERSONS_SOURCE, агульны ліміт часу на спампоўкі —PERSONS_BUDGET_MS; лакальныя файлы —node scripts/update-persons.mjs частка1.doc частка2.doc ….
Сама база вышуку МУС РФ аддае толькі пошук па імені з капчай і не адказвае з-за мяжы (у тым ліку з раннераў GitHub), таму адзіная практычная крыніца — статычны JSON, які Медыязона-Беларусь збірае штодня для свайго віджэта на старонцы «База розыска РФ» (грамадзяне і ўраджэнцы Беларусі) і адкрыта прапануе спампаваць; сайт спасылаецца на яе ў падвале, на старонцы запісу і ў FAQ. npm run update:wanted спампоўвае файл (WANTED_SOURCE, brotli — Node распакоўвае сам, сырыя brotli/gzip таксама разбіраюцца), разбірае і даўносіць запісы ў data/wanted.json. Калі файл пераехаў (HTTP 403/404), адрас шукаецца нанова: старонка Медыязоны (WANTED_PAGE) → бандл віджэта → імя файла даных. Усё ці нічога: недаступная крыніца, змена фармату ці засцярога пакідаюць базу як была, а ў wanted-meta.json пішацца sourceError (папярэджанне ў шапцы, адмін-алерт). У CI гэта асобны крок пры кожным запуску (двойчы на дзень), які не спыняе астатняе абнаўленне і дэплой. Медыязона заяўляе штодзённае абнаўленне, але файл мяняецца нерэгулярна — таму ў тултыпе шапкі пад радком вышуку асобным радком паказваецца дата іх файла (sourceDate з Last-Modified); у бачны радок шапкі яна не трапляе.
- Запіс крыніцы: імя вялікімі літарамі (руская), год нараджэння, нацыянальнасць, рэгіён і ведамства Беларусі, па чыім запыце абвешчаны вышук (МВД, КГК, КГБ, ДИН, ГПК; у ~10 % не пазначана), дата абвяшчэння ў вышук (у часткі запісаў прыблізная — «<2026-05», у нас
before: каля 10 % жывых, разам з выключанымі — каля траціны), дата першага абвяшчэння для паўторна дададзеных, іншыя напісанні імя, рэдакцыйныя катэгорыі Медыязоны («Полк Калиновского», «в списке «террористов»») і статус: дададзены за 7 дзён ці выключаны з базы. Артыкула КК няма. Кожнае поле правяраецца на тып і абразаецца; запіс без імя кірыліцай ці з чужым годам прапускаецца, а калі такіх больш за 1 % — абнаўленне спыняецца. - id — ад імя і года нараджэння (нумароў у крыніцы няма): два розныя запісы вышуку аднаго чалавека (розныя ведамствы) зліваюцца ў адзін, застаецца апошні. Выпраўленае напісанне пры тым жа годзе ці выпраўлены год пры тым жа імені пазнаюцца як праўка (
isWantedEdit), а не новы чалавек. - Выключаныя ў крыніцы застаюцца ў файле з пазнакай, але без даты выключэння. Жывыя запісы ідуць праз
mergeListяк звычайна: знік з жывых (выключылі ці прыбралі з файла) —removedсёння, вярнуўся — зноў жывы. Выключаныя, якіх у базе яшчэ не было (першы імпарт ці чалавек трапіў у базу і выбыў між нашымі праверкамі), дадаюцца адразу зremoved: '?'(UNDATEDуsrc/lib/wanted.js) іadded: null: для лічыльнікаў і статыстыкі гэта выдалены запіс, а для «Новага», карткі і дайджэсту — не дата. Стандартныя засцярогі mergeList: знікла (у тым ліку выключана) больш за max(20, 5 %) — памылка заўсёды, дадалося больш заMAX_ADDED(500: пасля паўзы ў крыніцы прыходзяць сотні за раз) — безUPDATE_FORCE=1; менш за 5 000 запісаў у файле — узяты не той файл. - У выдачы — янтарная палоска і плашка «Вышук РФ · МУС/КДК/КДБ» (ведамства-ініцыятар), імя ў звычайным рэгістры (даўжыня радка не мяняецца, таму падсветка працуе), іншыя напісанні, год нараджэння («г.н.») з нацыянальнасцю, рэгіёнам і ведамствам; дата — абвяшчэння ў вышук, прыблізная — «да 05.2026»; выключаны — «выключаны з базы» без даты, калі яе няма. Нумароў у крыніцы няма. Шукаецца імя (і іншыя напісанні) кірыліцай і лацінкай, год нараджэння, ведамства («розыск», «МВД», «КГБ») і рэгіён; нацыянальнасць у індэкс не ідзе.
- Крос-спасылкі з пералікам фізічных асоб МУС (
linkListsуscripts/index-rows.mjs, пры зборцы індэкса): той жа чалавек — тое ж імя (ці іншае напісанне з базы вышуку) і той жа год нараджэння, толькі паміж жывымі запісамі. На картцы асобы — «↔ Таксама ў базе вышуку РФ», на картцы вышуку — «↔ Ёсць у пераліку фізічных асоб МУС» (полеalsoу фрагменце). Пры першым імпарце звязалася ~450 чалавек (каля 7 % пераліку МУС). - Статыстыка (
#/stats/w): таймлайн па даце абвяшчэння ў вышук, серыі — ведамства-ініцыятар (МУС, КДК, КДБ, іншае/невядома); запісы з прыблізнай датай на графік не трапляюць, іх колькасць — асобным радком. - Дайджэст, RSS і «Новае» — як і для іншых спісаў: імя ў звычайным рэгістры, ведамства, рэгіён і дата вышуку; год нараджэння ў канал і стужку не ідзе. Пры першым імпарце маўчаць (
added: null). Даты «дададзены за 7 дзён» крыніцы не выкарыстоўваюцца: «новае» — тое, што з’явілася ў нашай базе. - Тэксты: блок «Што гэта значыць для мяне» тлумачыць, што расійскі вышук абвяшчаецца па запыце беларускіх ведамстваў, што чалавека могуць затрымаць і выдаць у Расіі і краінах, якія з ёй супрацоўнічаюць, і што выключэнне з базы не спыняе крымінальны пераслед; FAQ, llms.txt і JSON-LD згадваюць чацвёрты спіс як неафіцыйны, з атрыбуцыяй Медыязоны. Зменныя асяроддзя —
WANTED_SOURCE(адрас JSON),WANTED_PAGE(старонка для пошуку адраса),MAX_ADDED; лакальны файл —node scripts/update-wanted.mjs файл.json.
- Укладкі-спісы пад полем пошуку («Усе · Матэрыялы · Фарміраванні · Асобы · Вышук РФ») паказваюць, колькі знойдзена ў кожным спісе (без запыту — колькі запісаў у базе), і абмяжоўваюць выдачу адным спісам. У ліпкім радку пад полем — чыпы, якія пераносяцца на новы радок, а не пракручваюцца: заўсёды кнопка «Назіранне» (раскрывае панэль спісу назірання ніжэй) і сартаванне, прыціснутае да правага краю; пры запыце дадаюцца «Сачыць» і «Спасылка», а «Любое са слоў» — толькі для запытаў з двух і больш слоў. На вузкім экране кнопкі займаюць шырыню па змесціве (не расцягваюцца), а «Спасылка» згортваецца ў іконку — подпіс вяртаецца на момант «Скапіявана».
- Спіс назірання — кнопка «Назіранне»: увядзіце нік/канал/спасылку і націсніце «Сачыць». Пры кожным адкрыцці сайт правярае ўсе запыты і паказвае колькасць супадзенняў і статус («Супадзенняў няма», «Ёсць супадзенні» або «Новыя супадзенні»). Запыты, налада апавяшчэнняў і стан адкрытасці панэлі захоўваюцца толькі ў
localStorage; ёсць «Праверыць зноў», «Ачысціць усё» і неабавязковыя браўзерныя апавяшчэнні. - Новае (
#/new) — запісы па даце з’яўлення ў спісе з фільтрацыяй па спісах («Усе · Матэрыялы · Фарміраванні · Асобы · Вышук РФ») і асобным пераключальнікам «Выдаленыя» для зніклых са спісаў; RSSfeed.xmlдля чытачоў стужак. - Статыстыка (
#/stats) — таймлайн колькасці запісаў па даце судовага рашэння: стос бараў па артыкуле (314 ГПК / 302 КГС / без артыкула) з лініяй тэндэнцыі, маштаб і пракрутка жэстамі, картка перыяду і табліца-дублёр (src/lib/stats.js,Timeline.jsx,StatsPage.jsx). Пераключальнік «Матэрыялы · Фарміраванні · Асобы · Вышук РФ» дае той жа таймлайн для кожнага спіса са сваімі датай і серыямі (гл. раздзелы спісаў вышэй); спасылкі#/stats/f,#/stats/p,#/stats/wадкрываюць патрэбны спіс адразу. - Пошук па спасылках, ніках і імёнах —
https://,www.,@у пачатку і/ці знак прыпынку ў канцы адкідаюцца, пошук падрадковы («nick» знойдзе і «t.me/nick»); кірыліца ↔ лацінка ў абодва бакі (для фізічных асоб — і афіцыйная транслітарацыя з пераліку); калі дакладна нічога няма — прыблізныя словы з пазнакай: адна памылка для слоў з 5–7 літар, дзве — ад 8 (карацейшыя — толькі дакладна). - Старонка запісу (
#/r/<id>) — адкрываецца па даце ў картцы (старонка пры гэтым пракручваецца ўверх); значок спасылкі справа ў кожнай картцы капіюе пастаянную спасылку на запіс з падказкай «Скапіявана». На старонцы — радок з кнопкай «Да пошуку» злева і «Скапіяваць спасылку», «Сачыць» справа (поўнае тлумачэнне ў падказцы), ніжэй загаловак, картка і палі: нумар у спісе (пазіцыя ў публікацыі; для фізічнай асобы — нумар МУС або пазнака, што яшчэ не прысвоены), для фарміраванняў, асоб і запісаў вышуку РФ — усе палі крыніцы, для вышуку РФ у канцы карткі палёў, за пункцірнай лініяй (як адрыўны корак білета), — заўвага пра крыніцу са спасылкай на гэты запіс у віджэце Медыязоны (?q=імя, знешняя, з тым жа папярэджаннем, што і спасылкі на рэсурсы са спісаў); асоба і запіс вышуку пра таго ж чалавека спасылаюцца адно на аднаго. - «Што гэта значыць для мяне?» — агаворка «не юрыдычная кансультацыя», потым каляровы блок на кожны спіс, які ёсць у выдачы ці якому належыць адкрыты запіс (матэрыялы — адміністрацыйная адказнасць і падпіскі, фарміраванні — крымінальная, асобы — абмежаванні, вышук РФ — не афіцыйны спіс), парада «калі знайшлі сябе» і спасылкі на праваабаронцаў; кожны факт — у адным месцы, без агульнага пераказу ўсіх спісаў.
- Афлайн (PWA) — пасля першага адкрыцця сайт і база працуюць без інтэрнэту; можна «ўсталяваць» на тэлефон. У шапцы — час апошняй праверкі крыніц («праверана …»; націск раскрывае тултып з датай па кожным спісе) і папярэджанні: крыніца не адказвае, узятая запасная, спіс матэрыялаў не правяраўся больш за 36 гадзін, афлайн.
Як працуе пошук. Пры адкрыцці грузіцца толькі індэкс (~1,1 МБ gzip): нармалізаваныя назвы і імёны, слоўнікі тыпаў, судоў і артыкулаў, даты. Пошук — падрадковы па ўсіх словах запыту (ці па любым), просты includes над ~22 тыс. радкоў — мілісекунды. Поўныя запісы ляжаць у фрагментах па 200 і падцягваюцца толькі для тых, што на экране.
npm install
npm run update # спампаваць свежы спіс і абнавіць data/
npm run update:formations # тое ж для пераліку экстрэмісцкіх фарміраванняў (МУС/КДБ)
npm run update:persons # тое ж для пераліку фізічных асоб (МУС, некалькі .doc)
npm run update:wanted # тое ж для базы вышуку РФ па беларусах (JSON Медыязоны)
npm run dev # збярэ індэкс і адкрые dev-сервер
npm test
npm run build # dist/Разабраць лакальны файл: node scripts/update.mjs шлях/да/файла.
Зменныя асяроддзя: SITE_URL — адрас сайта для спасылак у RSS/Telegram і GEO-файлах (у CI зададзены ў воркфлоу); BASE_PATH — шлях, з якога аддаецца сайт (па змаўчанні /); FORMATIONS_SOURCE, PERSONS_SOURCE — адрас старонкі МУС для другога і трэцяга спісаў; WANTED_SOURCE, WANTED_PAGE — адрас JSON Медыязоны і старонкі, праз якую ён шукаецца нанова; PERSONS_BUDGET_MS — агульны ліміт часу на спампоўку ўсіх частак пераліку фізічных асоб у мілісекундах (па змаўчанні 18 хвілін); MAX_ADDED — колькі новых запісаў за раз лічыцца падазроным (400 / 100 / 300 / 500 для матэрыялаў / фарміраванняў / асоб / вышуку); UPDATE_FORCE=1 — прыняць абнаўленне насуперак гэтай засцярозе.
Стварыце бота (@BotFather), дадайце яго адміністратарам у публічны канал і задайце ў Settings → Secrets рэпазіторыя TELEGRAM_BOT_TOKEN і TELEGRAM_CHAT_ID (@назва_канала або лічбавы id). Пасля кожнага абнаўлення з новымі запісамі scripts/notify.mjs дасылае дайджэст. Ніякіх персанальных запытаў — толькі публічны спіс новага.
Кожны запіс трапляе ў канал адзін раз: дасланыя id пішуцца ў data/notified.json і камітуюцца разам з базай, таму другі запуск за суткі нічога не дублюе. Калі адпраўка ўпала на сярэдзіне, пазначаецца толькі тое, што сышло, а рэшта дабіраецца наступным запускам (акно — 7 дзён, адзнакі захоўваюцца 60 дзён).
Адмін-чат (неабавязкова). Дадайце сакрэт TELEGRAM_ADMIN_CHAT_ID (ваш асабісты chat id: напішыце боту і паглядзіце getUpdates, або спытайце ў @userinfobot) — і той жа бот прышле туды паведамленне, калі джоб упаў, крыніца перастала адказваць ці ўключылася запасная. Пробнае паведамленне (telegram_test) таксама ідзе ў адмін-чат, калі ён зададзены, і ніколі не пазначае рэальныя запісы дасланымі.
Праўкі ў крыніцы. Выпраўленая памылка друку ці абрэзаны радок пазнаюцца як праўка, а не як новы запіс (scripts/merge.mjs): у дайджэст, RSS і «Новае» такі запіс не трапляе, старая пастаянная спасылка вядзе на актуальную версію, а спіс назірання не трывожыць, калі папярэднюю версію ўжо бачылі.
Сайт статычны: npm run build → змесціва dist/ можна выкласці на любы хостынг (Netlify, Cloudflare Pages, свой сервер, IPFS). Каб спасылкі былі правільныя, задайце BASE_PATH (шлях, з якога аддаецца сайт) і SITE_URL (поўны адрас).
Сайт — SPA, таму без JavaScript краўлер бачыць пусты <div id="root">, а генератыўныя рухавікі (ChatGPT, Claude, Perplexity, AI Overviews) цытуюць толькі тое, што ёсць у HTML. Каб сайт трапляў у адказы, пры зборцы генеруецца:
| Файл | Што гэта |
|---|---|
faq.html, faq-en.html |
статычныя старонкі «пытанне → самадастатковы адказ» з FAQPage-разметкай |
llms.txt |
карта сайта ў prompt-friendly выглядзе: факты, лічбы, спасылкі |
llms-full.txt |
увесь тэкст адным файлам: факты, правілы пошуку, усе пытанні і адказы (бе + en) |
robots.txt |
яўны дазвол GPTBot, ClaudeBot, PerplexityBot і іншым + Sitemap: |
sitemap.xml |
тры старонкі з lastmod па даце базы |
JSON-LD у index.html |
WebSite з SearchAction (?q=…), Dataset, WebApplication |
фолбэк у #root |
загаловак, лічбы і <noscript> са спасылкамі — React замяняе яго пры мантаванні |
opensearch.xml |
сайт можна дадаць як пошукавік у адрасны радок браўзера (#q=, хэш не ідзе на сервер) |
404.html |
старонка памылкі са спасылкамі — GitHub Pages аддае яе на невядомых шляхах |
.well-known/security.txt |
куды паведамляць пра ўразлівасці (RFC 9116), з копіяй у корані |
Тэксты жывуць у src/lib/faq.js і адтуль трапляюць ва ўсе фарматы адразу, з жывымі лічбамі (колькасць запісаў, дата абнаўлення, доля тыпаў). Усе файлы генеруюцца, у git не трапляюць.
- Запушце
mainу рэпазіторый. - Settings → Pages → Source: GitHub Actions.
- Сакрэты (Settings → Secrets):
TELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID, неабавязковаTELEGRAM_ADMIN_CHAT_ID. Правы токена зададзеныя ў самім воркфлоу (толькі джоб абнаўлення маеcontents: write), таму «Workflow permissions» можа заставацца «Read repository contents». - Запусціце workflow уручную або дачакайцеся чарговага запуску (двойчы на дзень). Воркфлоу збірае сайт з
BASE_PATH: /(уласны дамен,public/CNAME); калі сайт аддаецца з падтэчкіhttps://<user>.github.io/<рэпазіторый>/, пастаўце ў воркфлоуBASE_PATH: /<рэпазіторый>/. - Калі абнаўленне спынілася з-за засцярогі «падазрона шмат новых запісаў» (больш за
MAX_ADDED, па змаўчанні 400), праверце файл крыніцы і запусціце воркфлоу ўручную з галачкайforce(лакальна —UPDATE_FORCE=1 npm run update).
- Запыты не пакідаюць укладку: пошук працуе ў браўзеры, запыт не пішацца ў адрасны радок, гісторыю, кэш service worker'а і логі хостынгу. Спасылка на запыт — толькі па кнопцы, у выглядзе
#q=…(хэш не адпраўляецца на сервер); так жа працуе OpenSearch. - Спасылкі ў запісах вядуць на матэрыялы са спісу, таму адкрываюцца пасля папярэджання (адзін раз за сесію), з
rel="noreferrer"і<meta name="referrer" content="no-referrer">— рэсурс не бачыць, адкуль прыйшоў наведнік. - CSP праз
<meta http-equiv>(GitHub Pages не аддае загалоўкаў): толькі свае скрыпты і стылі, інлайн-скрыпт тэмы — па sha256-хэшу, які лічыцца пры зборцы (scripts/csp.mjs); знешніх запытаў у кодзе няма. - «Ачысціць усё» выдаляе спіс назірання, налады, запыт укладкі, афлайн-копію базы і service worker. Гісторыю браўзера сайт ачысціць не можа.
- Сапсаваная спасылка (напрыклад,
#/r/%) не кладзе сайт: маршрут разбіраецца бяспечна, а ErrorBoundary паказвае паведамленне з выхадам на галоўную. - CI: правы токена — толькі патрэбныя кожнаму джобу; крэдэнцыялы не застаюцца ў
.git/configпадчас разбору чужога.docіnpm ci; джоб абнаўлення ставіць толькі runtime-залежнасці без install-скрыптоў; дзеянні прыпінутыя да SHA, абнаўляе іх Dependabot. Каміт базы робіцца праз fetch + rebase з паўторамі; пры канфлікце ўdata/(папярэдняя спроба ці ручны push ужо абнавілі базу) джоб бярэ свежыmainі паўтарае разбор, каб не губляць адзнакі пра дасланыя дайджэсты і не валіць дэплой. Паўторны запуск (re-run) заўсёды бярэ актуальныmain, а не каміт першай спробы. - Засцярогі даных: абнаўленне спыняецца, калі «знікла» больш чым
max(50, 5 %)запісаў (матэрыялы) ціmax(20, 5 %)(фарміраванні, фізічныя асобы, вышук РФ) або дадалося больш заMAX_ADDEDзапісаў за раз; сеткавыя запыты да крыніцы з таймаўтамі; калі на старонцы некалькі.docспісу матэрыялаў, бярэцца той, дзе больш запісаў; часткі пераліку фізічных асоб бяруцца ўсе ці ніводная. Шапка сайта папярэджвае, калі спіс матэрыялаў не правяраўся больш за 36 гадзін (для пералікаў МУС і базы вышуку РФ такога таймера няма — толькі папярэджанне пра збой крыніцы), крыніца не адказвае або ўзятая запасная. - Персанальныя даныя трэцяга спісу паказваюцца як у афіцыйнай публікацыі, але ў пошукавы індэкс трапляюць толькі імя, транслітарацыя, дата нараджэння, артыкулы КК і суд з прысуду ды дата ўключэння; месцазнаходжанне і грамадзянства — толькі ў фрагменце запісу (картка і старонка запісу), а ў Telegram-дайджэст і RSS дата нараджэння і адрас не ідуць. Даведка пра судзімасць на сайт не трапляе зусім.
- Персанальныя даныя чацвёртага спісу (вышук РФ) — як у выбарцы Медыязоны: у індэкс трапляюць імя з іншымі напісаннямі, год нараджэння, ведамства-ініцыятар, рэгіён і дакладная дата вышуку; нацыянальнасць і рэдакцыйныя катэгорыі Медыязоны — толькі ў фрагменце запісу, а ў Telegram-дайджэст і RSS год нараджэння не ідзе.
- Пра ўразлівасці:
.well-known/security.txt→ GitHub Issues.
- Не ўлічваюцца рэгістр, «ё/е», лацінская/кірылічная «i», віды лапак. Фраза ў лапках — цалкам.
- Па рашэнні суда шукаюцца назва суда і дата рашэння (словамі «20 августа 2026» ці лічбамі «20.08.2026»); для фізічных асоб — суд і артыкулы з прысуду, дата ўключэння ў пералік і дата нараджэння («14.10.1983»); для вышуку РФ — імя і іншыя напісанні, год нараджэння, ведамства-ініцыятар («розыск», «МВД», «КГБ»), рэгіён і дата вышуку.
- Запыт не пішацца ў адрасны радок (і не трапляе ў гісторыю браўзера, кэш service worker'а і логі хостынгу): ён жыве ў
history.stateукладкі і перажывае перазагрузку. Спасылкай на запыт дзеляцца праз кнопку «Спасылка» (#q=…); пры адкрыцці прымаюцца і#q=, і?q=, пасля чаго адрас ачышчаецца./— фокус на поле пошуку.
What this is. An unofficial, open-source search over Belarus's official extremist lists: the Republican list of extremist materials — the register of channels, websites, accounts, videos, books and symbols that Belarusian courts have ruled extremist — the Interior Ministry / KGB list of extremist formations, and the Interior Ministry list of individuals “involved in extremist activity” (people convicted under “extremism” articles of the Criminal Code); plus a fourth, unofficial database — Belarusians on the Russian Interior Ministry wanted list, per Mediazona Belarus's daily extract (Belarusians end up there at the request of Belarusian agencies), cross-linked with the persons list by name and year of birth. Live at elist.itbeard.com.
Key facts.
| Entries | ~6 000 materials, updated automatically twice a day (shown with a red left border and “Material” label), plus ~380 entries from the Interior Ministry / KGB list of extremist formations (checked once a day, shown with a purple left border and “Formation” label) and ~6 900 individuals from the Interior Ministry persons list (checked twice a day, shown with a teal left border and “Person” label), plus ~6 700 Belarusians wanted in Russia per Mediazona (checked twice a day, shown with an amber left border and “RF wanted” label) |
| Search | runs entirely in the browser; Cyrillic ↔ Latin transliteration (plus the official Latin spelling of listed persons); when nothing matches exactly, typo tolerance of 1 letter for 5–7-letter words and 2 from 8 letters |
| Data collected | none — no queries, no cookies, no analytics, no server |
| Offline | yes, PWA; the database stays in the browser |
| Alerts | watchlist with browser notifications, RSS feed.xml, Telegram @elist_by |
| Stack | React 19 + Vite, static hosting, ~1.1 MB gzip index |
| Price | free, no sign-up |
Why it exists. Distribution, production, storage and transport of listed materials is an administrative offence in Belarus under Art. 19.11 of the Administrative Code — up to 20 base units or arrest for individuals. People need a fast way to check whether they, their channel or their bookshelf is on the list, without leaving a trace on a server.
Answers to common questions are on the static FAQ page (English).