Skip to content

docs: public data + machine-readable endpoints reference (#54) - #149

Merged
todorkolev merged 6 commits into
midt-bg:mainfrom
StanislavBG:docs/public-data-api
Jul 3, 2026
Merged

docs: public data + machine-readable endpoints reference (#54)#149
todorkolev merged 6 commits into
midt-bg:mainfrom
StanislavBG:docs/public-data-api

Conversation

@StanislavBG

Copy link
Copy Markdown
Contributor

Какво и защо

Външен разработчик (#54, Явор) пита къде е документацията за източника на данни, за да направи location-based мобилно приложение. Този PR добавя docs/api.md — справка за наличните публични данни и машинно четими endpoint-и, така че да се строи върху СИГМА без HTML скрейпинг.

Покрива (всичко проверено спрямо реалните routes):

Линкнат от docs/README.md.

Валидация: endpoint-ите, content-type-овете и параметрите са сверени 1:1 с apps/web/app/routes.ts, contract.json.tsx, contracts.csv.tsx и lib/filters.ts. prettier чист.

Closes #54

An external dev (midt-bg#54) asked where to find docs for the data source to build a
location-based app. Document what exists: CSV exports (honouring the list
filters), per-contract JSON, sitemaps, the shared query/filter grammar, the
CC-BY source/licence, rate limits, and the explicit non-goals (no open SQL/REST
query endpoint — matches the security posture). Linked from docs/README.

Closes midt-bg#54

@nedda76 nedda76 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хубав и точен документ — нужен е за външни разработчици (#54). Спот-проверих endpoint-ите и филтър-параметрите спрямо реалните routes: съвпадат, формулировките за кеш/rate-limit/лиценз също.

Едно за подредбата (не по съдържанието): редът „CSV-тата уважават същите филтри като списъка" е точно поведението, което #146/#138 поправя — на main днес /contracts.csv още игнорира ?bids, така че твърдението става напълно вярно чак след merge на #146. Бих мерджнала #149 след #146 (или с кратка уговорка дотогава), за да не изпревари документът кода за кратко. Иначе — готова за merge. 🙏

@lyubomir-bozhinov lyubomir-bozhinov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Преди merge — този PR рекламира точно повърхностите, които #173 маркира като изтичане на ЕИК на физически лица (CWE-359 · GDPR Art. 4/5 · ЗЗЛД), и то без бележка за физически лица:

  • ред 41: GET /contracts/{id}.json → „пълният запис на договора" (JSON-ът носи eik + сурови имена от източника; сервира се с Cache-Control: public, s-maxage=… и без X-Robots-Tag).
  • редове 31–33: /contracts.csv, /companies.csv, /authorities.csv (CSV-тата съдържат ЕИК на физически лица).
  • редове 17–18: ЕИК като ключ на субекта, без разграничение ЕТ / физическо лице.
  • секцията за sitemap-и насърчава програмно изброяване на „всички URL-и (вкл. всеки договор)".

HTML профилите вече слагат noindex за физически лица (company.tsx), а машинно-четимите повърхности — не. Тоест документацията промотира за bulk/индексируема консумация повърхност с нерешен privacy дефект.

Не блокирам самия текст — фактологически е верен. Но предлагам да изчака политиката по #173 (или поне да добави кратка бележка в api.md за идентификаторите на физически лица), за да не насърчава bulk консумацията преди #173 да е затворен. Бележката за „CSV-тата уважават същите филтри като HTML списъка" пък важи чак след #146.

@StanislavBG

Copy link
Copy Markdown
Contributor Author

Благодаря за прегледа — двете бележки са добавени в docs/api.md (11fb911):

…eguards

The note claimed sitemaps carry natural-person ЕИК and that the model does
not yet distinguish ЕТ from legal entities. The code does distinguish them:
recognised ЕТ profiles are noindex and /sitemap-companies.xml drops ЕТ-named
profiles (name-prefix heuristic, so not exhaustive). Scope the caveat to the
outputs that really carry undifferentiated ЕИК (CSV exports, contract JSON)
and stop promising "all URLs" in the sitemap section.
@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Прегледах docs/api.md (@ 5ea95a3) срещу кода — честен и сам се каузира (bids/#146, ЕТ/#173). Две за уточнение:

  1. (по-важно) Ред 10: „нормализира и обогатява, но не променя сумите". За value_suspect договорите ETL-ът repair-ва amount_eur към прогнозната стойност на процедурата (normalize-raw.sql:357 — „repaired to the procedure estimate"), тъй че показаното число се различава от суровото в storage.eop.bg. Точно bulk потребителите, към които е насочена страницата, ще сравнят и ще видят разлика. Добавете уговорка (напр. „сумите се показват както са, освен малък набор value_suspect редове, при които се показва прогнозната стойност на процедурата вместо явно сгрешена сума").
  2. (дребно) Ред 84: „Endpoint-ите са rate-limited" — bypass-ът през .data суфикса (bug(web): rate limiter-ите се заобикалят през single-fetch суфикса .data #184) е поправен само в още неслетия fix(web): rate limiter-ите вече хващат и single-fetch .data формата (#184) #185; дотогава не важи за машинно четимите .data близнаци.

Иначе точен и полезен. Approve по същество след горните уточнения.

@StanislavBG

Copy link
Copy Markdown
Contributor Author

Двете уточнения са добавени в af568c7: бележката за източника вече казва, че при малкия набор value_suspect редове amount_eur показва прогнозната стойност на процедурата вместо явно сгрешената сума (scripts/normalize-raw.sql:357), а rate-limit твърдението има временен caveat за .data вариантите (issue #184, маха се след merge на #185).

@ydimitrof

Copy link
Copy Markdown
Contributor

✅ Проверих всичко срещу кода. Готово с прегледа. Ето финалния коментар (само той, за публикуване):


Прегледах този PR стриктно — с фокус върху сигурност, лични данни и целостта на данните. PR-ът е само документация (docs/api.md +101, docs/README.md +1 ред); няма изпълним код, няма SQL, няма промени по зависимости, няма тайни. Затова OWASP/injection повърхността тук е нулева — рискът е единствено дали текстът описва вярно реалното поведение и дали не промотира съществуващ privacy дефект. Проверих го ред по ред спрямо кода.

Сверено 1:1 с кода (всичко се потвърждава):

  • Всичките 15 endpoint-а от документа съществуват в apps/web/app/routes.ts (CSV × 3, contracts/:id.json, robots.txt, sitemap индекс + 4 под-карти). ✓
  • Договорният JSON: contract.json.tsx:17,21,22 връща { "error": "not_found" } + 404, Content-Type: application/json; charset=utf-8, Cache-Control: publicCache(3600) — и наистина без X-Robots-Tag (както отбеляза @lyubomir-bozhinov). ✓
  • value_suspect → прогнозна стойност: normalize-raw.sqlCASE WHEN x.value_flag = 'value_suspect' THEN x.proc_est_eur. Бележката за сумите е точна. ✓
  • ЕТ noindex: company.tsx:32,55 слага robots: noindex за разпознати ЕТ. sitemap-companies.tsxsitemaps.ts:110 пропуска профилите през isNaturalPersonProfileName(r.name) (евристика по име — не изчерпателна, точно както пише документът). ✓
  • Временната бележка за bids/fix(web): list CSV exports must honour all filters — contracts bids + drift-proofing (#138) #146: потвърдена — contracts.csv.tsx не чете bids (params обектът няма такъв ключ), докато HTML списъкът contracts.tsx:62 го чете. Caveat-ът е коректен. ✓
  • Query граматата и multi-value синтаксисът съвпадат с lib/filters.ts (getMulti, повтарящи се/запетайни стойности). ✓

Целост на данните и лични данни: документът не въвежда дефект — той описва съществуващи повърхности. Основната останала грижа (промотиране на bulk/машинно четими изходи, които носят ЕИК на физически лица преди затваряне на #173 — CWE-359 · GDPR чл. 4/5 · ЗЗЛД) е изрично оградена с бележка на редове 47–53, насочваща потребителите да третират полетата като лични данни. Това е приемливо смекчаване за документ, докато политиката по #173 се финализира.

Дребни бележки (не блокиращи, вече повдигнати от рецензентите):

Няма следи от зловреден код, backdoor, обфускация или ексфилтрация. Чисто, точно и полезно за външните разработчици (#54). Благодаря за прилежната работа по caveat-ите — рядко се вижда документация, която честно описва собствените си все-още-неслети зависимости. 🙏

Verdict: APPROVE — само-документация, фактологически вярна и сверена с кода; препоръчвам merge след (или заедно с) #146 и #185, а #173 да се проследи отделно.

…rate-limit)

Removes two 'Временно' notes: the midt-bg#146 one (/contracts.csv now honours bids -
midt-bg#146 is merged) and the note stating the .data variants are un-rate-limited
until midt-bg#185 (do not publicly document an un-throttled surface; the gap stays
tracked in midt-bg#184/midt-bg#185).
@todorkolev
todorkolev merged commit c004a8e into midt-bg:main Jul 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API docs

5 participants