Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
프로젝트와 자금을 추적해 신뢰를 쌓고 부탄 공공 자금이 어느 기관·펀더·구역에 쓰였는지 모든 수치를 출처와 연결해 보여준다
Track projects. Follow funds. Build trust. See where Bhutan's public money goes – by dzongkhag, funder and agency – with every figure linked to its source.
금융TypeScript · JavaScriptGitHub @Youngyang07온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Your dzongkhag. Your data. Your right. An open-source civic-transparency platform for Bhutan: where public money goes — development projects, budgets and allocations by dzongkhag (and gewog/village, where documents go that deep) — with the funding source and a link to the original document on every figure.
Modelled on the district-dashboard approach of ForThePeople.in (MIT), reimplemented for Bhutan.README 전문 보기 ↗Your dzongkhag. Your data. Your right. An open-source civic-transparency platform for Bhutan: where public money goes — development projects, budgets and allocations by dzongkhag (and gewog/village, where documents go that deep) — with the funding source and a link to the original document on every figure.
/en/thimphu) with a module sidebar, and a national one (/en/bhutan): Overview · Budget & allocations · Projects · Funding sources · Weather & rainfall · Tenders · Leadership & offices.Next.js 15 (App Router, TypeScript) · PostgreSQL (pg, plain SQL migrations) · Vercel Cron collectors · Vitest.
| Source | How | Refresh |
|---|---|---|
| World Bank Projects & Operations API | automated (pipeline/worldbank.mjs) | daily |
| Asian Development Bank IATI file | automated (pipeline/adb.mjs; override with ADB_IATI_URL) | daily |
| Parliament of Bhutan member records (National Assembly + National Council) | automated (pipeline/leaders.mjs; override with PARLIAMENT_API) | daily |
| Kuensel and The Bhutanese feeds — leadership-change watch | automated (pipeline/news.mjs; override with KUENSEL_FEED / BHUTANESE_FEED) | daily, with the members |
| e-GP — Electronic Government Procurement System (PMDD, Ministry of Finance) — every tender currently out to bid (203 notices on 2026-10-11) | automated (pipeline/egp.mjs; override with EGP_BASE) | daily |
| Open-Meteo weather | automated (pipeline/weather.mjs) | daily (Vercel Hobby allows at most one run/day per cron; on a Pro plan change vercel.json to e.g. 37 */6 * * *) |
| Ministry of Finance, National Budget Report FY 2026-27 — national summary, sector allocation, and the allocation of every dzongkhag, thromde and all 205 gewogs | reference file data/reference/budget-2026-27.json | yearly (new budget each May) |
| NSB 2017 Population & Housing Census (Table 2.1) | reference file data/reference/population-2017.json | per census |
| Ministry of Health, Annual Health Bulletin 2025 (Table 6.1) — all hospitals, PHCs, sub-posts, HISCs with beds | reference file data/reference/health-facilities.json | yearly |
| MoESD Annual Education Statistics 2024 (Annexure IV) — all 566 schools by name and level | reference file data/reference/schools-2024.json | yearly |
| Parliament member records, as shipped | reference file data/reference/leaders.json — the fallback shown until the daily refresh above has run | on change |
| MoICE Annual Industry Report FY 2025-26 (Annexure 3) and National Employment Report 2024-25 — industry licences and jobs filled per dzongkhag | reference file data/reference/economy.json | yearly |
| Dzongkhag administration websites and dated appointment notices — Dzongdags and office contacts | reference file data/reference/dzongdags.json, each entry graded by how well it is confirmed | on change |
| MoF / MoHCA / MoAL & other ministries' budgets, allocations, tenders, offices | curated CSV in data/manual/ — these are PDFs/web pages with no API. Every row must cite its public document | on commit |
Reference files ship with the code and work even without a database. tests/reference.test.ts checks each against the publication's own totals (census sums, the Health Bulletin's per-dzongkhag totals rows, MoESD Table A, 47 NA seats with the constitutional split), so a transcription slip fails CI.
Collectors run via vercel.json crons → /api/cron/<job> (rate-limited per job; a CRON_SECRET bearer skips the limit), and from the Load / refresh data now button on the Data sources page. Each job is isolated: on failure the previous good rows stay, the source is flagged stale on the Data sources page, and the run is written to the update log. A batch with any invalid record loads nothing.
A job that runs and fails flags its own source stale. A job that stops running at all is the harder case: the
status stays ok and the data simply ages, which nothing inside the app notices. So /api/cron/alerts checks
the age of each source's last success once a day against a 72 h limit (STALE_ALERT_HOURS), and an overdue
source is reported in three places:
ALERT_WEBHOOK_URL, if set — one POST, at most once a day per source, plus a line when it recovers. The
body carries the message under text, content and message, which covers Slack, Google Chat, Discord and
ntfy without a per-service adapter;/api/health, which answers 503 while any source is overdue (degraded: "stale-sources") or the
database is unreachable (degraded: "database").Point any uptime monitor at /api/health: it is the only one of the three that still works when the scheduler
running the other two has itself stopped.
The daily leaders job reads Parliament's own member records and replaces the list — but only if the response is a complete Parliament: 47 National Assembly seats with the constitutional split per dzongkhag, and one elected National Council member per dzongkhag. Anything less is rejected, the previous list stays, and the source is marked stale, so a half-written or broken response can never leave a gap on the site. The job finds the current term itself (the highest-numbered Parliament that is fully seated), so it keeps working after the next election without a code change. Until the job has run, the bundled data/reference/leaders.json is shown instead.
Newspapers are a watch, never a source. The same job reads the Kuensel and The Bhutanese feeds and flags articles that read like a change of office-holder in a named dzongkhag. A flag is a dated link inviting someone to re-check that entry against the official source — no name on DrukView is ever taken from a newspaper, because a headline such as "Dasho takes charge in Trongsa" cannot be parsed into a correct name, and a wrong name on a transparency site is worse than a late one. A feed that fails never fails the members refresh.
Bhutan's e-GP portal publishes no API, feed or export, and its tender page is a shell: the rows are fetched by the page's own script. The daily tenders job makes that same request — POST /TenderDetailsServlet with funName=AllTenders, carrying a session cookie from a prior GET of the search page — and reads the bare run of <tr> rows it returns. This request was observed against the live portal, not inferred; the first version of this collector guessed at it, fetched nothing for a day, and is written up in ADR-0002.
What it collects is the portal's live register: viewType=Live is 11 pages of 20, 203 notices when last measured, every one still open. The job reads all of it — 11 requests, about 13 seconds — so DrukView holds every tender out to bid rather than an arbitrary slice. The portal's other views are not read: the unfiltered view is 731 pages of history, Archive is 685 pages of closed notices and Cancelled is 37. A page size above 20 makes the servlet drop the connection, so the page size stays at 20.
Because that response's shape is the whole agreement, the parser is the tested part (tests/egp.test.ts runs it against a captured real response) and the job is all-or-nothing: a response without a readable row fails the run, the previous notices stay published and the source is marked stale. A redesign at e-GP therefore shows up as a stale source, never as missing or invented notices — and the Tenders page says so in as many words, because "no tenders here" and "we could not read e-GP" are different claims and only one of them is about Bhutan.
A tenders page shows at most 500 notices, one more than that is fetched so a cut-off list can say it is cut off rather than passing for the whole register, and the e-GP live register held 203 when last measured. Three honesty constraints: e-GP publishes no estimated value, so DrukView shows none; each notice cites its own page on e-GP (ViewNotice.jsp?id=…, which opens without a session) rather than a search page; and a notice is placed in a dzongkhag only when the procuring agency's own hierarchy names exactly one — never from a place name in the title, where it is usually where the work is rather than who is buying it. Of 203 notices, 129 were placed in a dzongkhag and 74 left national.
DrukView is open source (MIT) and open to anyone. Start with CONTRIBUTING.md — it sets out the seven data rules (never invent a number; cite every row; never mix Nu. and US$; never guess an identity or a place; reject the batch, not the row; say what you do not know; keep the date), how to add cited CSV rows or a reference dataset, and how to write a collector.
The most valuable contribution needs no code: if a figure here is wrong, open a Data correction issue with a link to the public document that proves it. Also see the Code of Conduct and, for anything security-related, SECURITY.md — report privately, never in a public issue. CI runs typecheck, tests and a production build on Node 20 and 22 for every push, plus a check that every curated row cites an https document and that no secret is committed.
cp .env.example .env.local # set DATABASE_URL (CRON_SECRET optional)
npm install
npm run db:migrate && npm run db:seed # optional: the app also does this itself on first visit
npm run job -- manual # load data/manual/*.csv
npm run job -- worldbank # needs network access to the source
npm run dev # http://localhost:3000
Tests: npm test (unit). Database integration tests run when TEST_DATABASE_URL points at a throwaway Postgres database (CI does this automatically; the suite drops and recreates the public schema there).
DATABASE_URL — the only required setting.Optional: ALERT_WEBHOOK_URL (where to send a notice when a source has not refreshed for three days — any Slack/Google Chat/Discord/ntfy incoming-webhook URL) and STALE_ALERT_HOURS to move that limit.
Optional: CRON_SECRET. The data jobs only read public data, so they run without a secret but at most once per interval (World Bank/ADB and Parliament 6 h, e-GP tenders 3 h, weather 2 h, curated CSVs 10 min; 5 min after a failure). A request carrying Authorization: Bearer $CRON_SECRET skips that interval. Every job stops after 50 s and records why, so a slow source can never fail silently.
The automated sources were checked against their real responses, and the parsers' tests use trimmed copies of those (tests/fixtures/*real*):
project_abstract = {"cdata!": …}, US-style dates (12/31/2027 12:00:00 AM), and totalcommamt "0" (= not reported, shown as such, never "US$0").https://www.adb.org/iati/iati-activities-bt.xml is valid IATI 2.03; 62 activities are merged into 38 projects (e.g. grants 0088 + 0089 → project 39221-022, US$14.30M, matching adb.org). IATI status 3 "Finalisation" = completed (adb.org shows these as Closed). Sector codes are resolved to names from the official IATI codelist (shared/iati-sectors.json).src/geo/bhutan-dzongkhags.json, public/geo/bhutan-gewogs.json) from OCHA ROAP / HDX via geoBoundaries (gbHumanitarian 2019, CC BY 3.0 IGO): 20 dzongkhags + 205 gewogs from one consistent dataset; every gewog's dzongkhag was assigned geometrically and checked against the official count per dzongkhag (tested).What is still unproven is the runtime on your host (network egress, timeouts, database permissions): run the collectors once after deploying and read the Data sources page.
/en/…) but ships English only; a Dzongkha translation will be added once a native speaker can review it.