尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Public sales demo: queryless, cited security-advisory search over NVD CVE data with a simulated RBAC role toggle
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Ask a question about an organisation's open data in plain English and get a short data story with charts. Every number comes from a SQL query run on the real data, and every chart shows its query.
One engine, one config folder per client. Live: search.portaljs.com (DataHub, the default) · search.portaljs.com/demo/toronto
How it works in depth (pipeline, costs, hosting, decisions): ARCHITECTURE.md.
Datopian has two ways to build a client demo. They are different products, in different repos.
| PortalJS Ask (this repo) | Portal demo | |
|---|---|---|
| What the client sees | One page with a question box. A question gets a short data story with charts | Their own portal, modernised: catalogue, search, dataset pages, plus an optional data story and "Ask AI" |
| What it sells | The AI question-answering layer on its own | A portal revamp or migration (with AI as a bonus) |
| Best for | Organisations with open data but no portal they care about, or an AI add-on for an existing client | Anyone who already runs a portal: CKAN, ArcGIS Hub, EntryScape, Opendatasoft, Socrata |
| Effort | Hours: pick 5–20 datasets, write data notes and example questions | Days: connect the backend, brand it, write one story |
| Repo | datopian/portaljs-ask, one folder per client in portals/ | datopian/data-portal-examples (internal), see its CLIENT-DEMO-GUIDE.md |
| URL | search.portaljs.com/demo/<slug> or the client's own domain | <slug>.arc.portaljs.com or <slug>.portaljs.com |
They combine well: a portal demo's story page can link to the client's PortalJS Ask page for follow-up questions.
It is:
portals/<slug>/. Never a fork.It is not:
/security, /governance) were removed on 2026-10-12.portal-refresh).| What | Where |
|---|---|
| Code | This repo. main is production |
| Hosting | Vercel, Datopian team, project portaljs-ask. Every pull request gets a preview URL |
| Client configs | portals/<slug>/: portal.json, sources.json, notes.md, profile.md, instant.json |
| Which portal is the homepage, client domains | portals/index.json |
| Data files | Vercel Blob store portaljs-ask-data, one folder per portal and snapshot. Not in git |
| Team skills for Claude Code | .claude/skills/: portal-new, portal-verify, portal-refresh, ask-cost-report |
Existing portals: datahub (17 DataHub core datasets, the homepage) and toronto (20 City of
Toronto datasets).
You need Node 20+ and an Anthropic API key (ask for the team key; never commit it).
gh repo clone datopian/portaljs-ask
cd portaljs-ask
npm install
cp .env.example .env.local # set ANTHROPIC_API_KEY at minimum
npm run dev # builds the portal configs, then starts Next.js
instant.json and cost nothing. Typed questions call the API and cost money.portals/, re-run npm run portals (dev and build do it for you).Easiest: in Claude Code, from this repo, run the portal-new skill and give it the
organisation, its catalogue URL and (optionally) the datasets. It follows the steps below and
stops at a preview link.
By hand (full detail in ARCHITECTURE.md §6 and .claude/skills/portal-new/SKILL.md):
git checkout -b portal/<slug>portals/<slug>/portal.json by copying portals/toronto/portal.json
and changing every field (name, owner, headline, theme colours, logo, source, catalogue,
data.base = /data/<slug>/, data.snapshot = today). Add sources.json with 5–20 tables.
Pick tabular datasets with dates and categories people ask about; skip map-only, PDF-only
or very large datasets.node scripts/portal-data.mjs <slug> downloads, cleans and converts the data and
writes profile.md. Resolve every Check item it lists.portals/<slug>/notes.md: for every table, what one row is, every column
with unit and range, how to count correctly, and traps. This is where answer quality comes
from. Check every number you write with DuckDB.datasets and 15–20 examples to portal.json. The first 3 are the
headline ones.BLOB_READ_WRITE_TOKEN=... node scripts/upload-data.mjs <slug>, then put the
printed URL in data.remote in portal.json. Deploys fail without it.npm run portals && npx tsc --noEmit -p ., commit, push, open a draft PR and
wait for the Vercel preview.ASK_ADMIN_TOKEN=... node scripts/precompute.mjs <slug> --api <preview URL>, then run the
portal-verify skill. Read every saved story against its rows (counts, ratios,
"highest", periods), not only the headline numbers.search.portaljs.com/demo/<slug>.Zero-risk mode: set "live": false in portal.json. The question box disappears, only
the pre-computed examples show, and the AI cost is zero. Use it for demos sent by email.
Client's own domain (e.g. ask.example.org): add "<host>": "<slug>" to domains in
portals/index.json, add the domain to the Vercel project, and have the client point a CNAME
at cname.vercel-dns.com. See ARCHITECTURE.md §6.
| Limit | Default | Env var |
|---|---|---|
| Monthly AI spend for live questions | $40 (Anthropic account hard cap: $50) | ASK_MONTHLY_BUDGET_USD |
| Live questions per day, all portals | 30 | ASK_DAILY_TOTAL |
| Live questions per visitor per day | 5 | ASK_DAILY_PER_VISITOR |
When a limit is hit, live questions pause and the examples keep working. Check spend with the
ask-cost-report skill, or:
curl -H "x-ask-admin: $ASK_ADMIN_TOKEN" https://search.portaljs.com/api/data/status
?q=...) and check the link preview."live": true or false for this audience.data.snapshot (this starts a fresh cache), re-check the
notes, re-run pre-compute.| Problem | Fix |
|---|---|
| "Live questions are paused" | A daily or monthly limit was hit. Examples still work. See §6 |
| Deployment fails | A portal is missing data.remote in portal.json (step 6), or npx tsc --noEmit -p . fails |
| Wrong or odd numbers in answers | Fix notes.md (units, how to count, traps), then re-run precompute.mjs (--restory rewrites stories from existing rows) |
| Question outside the data | Expected: the page offers a free catalogue search linking to matching datasets |