Give your agent a wallet you control.
에이전트가 일회용 카드나 기계 결제 프로토콜로 온라인 결제하고, 모든 요청을 직접 승인
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
UK Public Finances Explorer — a factual, data-led explorer for UK government debt and public finances. Every figure shows its source, date, and confidence level. Built with Eleventy; WCAG 2.2 AA.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A clean, factual, data-led website that helps people understand UK government debt and public finances. Built with official data sources in mind, plain-English explanations, historical context, and useful comparisons.
It is not a political commentary site and not a gimmicky debt clock. Every major figure shows its source and date, and figures are clearly marked when estimated, provisional, or calculated.
Live at ukpublicfinances.org. The headline, monthly, and indicator figures were refreshed on 25 October 2026 against the ONS September 2026 public sector finances release, and the international comparison against the IMF World Economic Outlook of October 2026. The Budget 2026 page and the EU-limits section on the international page use the OBR's Economic and fiscal outlook of 28 October 2026. Those figures were read from the PDF on 28 October 2026. On 29 October 2026 the dashboard's debt interest moved to the same forecast (the 2026-27 figure, £124bn). So did the GDP growth and tax burden indicators, and the simulator's interest rate and nominal growth assumptions. Every public-facing figure was last re-audited in full against its primary source (ONS, OBR, HMRC, HM Treasury, House of Commons Library, IMF, and DWP) on 21 July 2026, following the June 2026 release and PESA 2026, with the international comparison pulled directly from the IMF DataMapper. Each record shows its own source_url, date, and confidence_level. Known caveats: the long-run historical series before about 2010 is a best-estimate reconstruction (confidence_level: estimated); and the GDP figure is the denominator consistent with the published debt-to-GDP ratio rather than a single published release. See docs/UPDATING-DATA.md for how to refresh figures.
assets/js/lib/calc.js).Requires Node.js 18+ (developed on Node 24 LTS, pinned in .node-version).
npm install # install Eleventy
npm run dev # local dev server with live reload, usually http://localhost:8080
npm run build # production build to ./_site
npm test # data-integrity + tool-maths tests (node:test)
npm run a11y:all # build + serve + WCAG 2.2 AA audit of every page (see below)
npm run a11y:all # one shot: build, serve _site, pa11y-ci over every route, tear down
npm run a11y # quick single-page check, needs `npm run dev` running first
a11y:all is self-contained: it builds, starts a static server on port 8081, runs
pa11y-ci at the WCAG 2.2 AA standard, then stops the
server. Routes come from sitemap.xml at run time rather than a hand-kept list, so a new
monthly update needs no change here. .pa11yci.json holds the shared settings plus the
pages the sitemap deliberately omits: 404.html, which is not a real route, and
/monthly/, which canonicalises to the latest dated entry. A test pairs the two, because
a page dropped from the sitemap otherwise leaves the audit silently. The audit tools are
fetched on demand via npx (kept out of the dependency tree to stay lean); the first
run downloads a headless Chromium, so expect it to take a minute. To audit a specific
page while developing, run npm run dev and npm run a11y (defaults to the homepage,
edit the URL in the script for others).
For performance and best-practices scores too, run Lighthouse against the dev server:
npx lighthouse http://localhost:8080 --only-categories=accessibility --view
.
├── .eleventy.js # Eleventy config + filters (number, oneDp, readableDate, isoDate, timeTag, latestOf, poundsShort, findBy, jsonScript, yearOf)
├── netlify.toml # build settings + security headers (CSP, etc.)
├── .pa11yci.json # routes for the WCAG audit
├── .node-version # Node 24 (fnm locally, Netlify in CI)
├── src/
│ ├── _data/ # SOURCE OF TRUTH: all figures live here as JSON
│ │ ├── dashboard.json # homepage headline metrics
│ │ ├── debtTimeseries.json # long-run series for the timeline
│ │ ├── spendingComparisons.json # annual budgets for context
│ │ ├── internationalComparisons.json
│ │ ├── budget2026.json # the latest OBR forecast, for the Budget page and the EU limits box
│ │ ├── indicators.json # wider economic indicators (health page)
│ │ ├── monthlyUpdates.json # monthly explainer entries
│ │ ├── events.json # neutral timeline markers
│ │ ├── primeMinisters.json # context for the lifetime tool
│ │ ├── assumptions.json # tool assumptions (translator, simulator)
│ │ ├── sources.json # data source catalogue
│ │ ├── glossary.json # glossary terms
│ │ ├── meta.json # confidence definitions, footer note
│ │ └── site.json # title, nav, url, analytics token, publisher
│ ├── _includes/
│ │ ├── layouts/base.njk # page shell: head meta, OG, JSON-LD, header, footer
│ │ └── components/macros.njk # reusable components (see below)
│ ├── assets/
│ │ ├── css/main.css # mobile-first, single stylesheet
│ │ ├── js/ # nav, big-numbers, timeline, lifetime, budget-simulator
│ │ │ └── lib/calc.js # pure tool maths (ESM), unit-tested
│ │ ├── favicon.svg, og-image.png, icon-*.png, apple-touch-icon.png
│ ├── favicon.ico, site.webmanifest # root icons + manifest (passthrough)
│ ├── index.njk … sources.njk # the content pages
│ ├── 404.njk, privacy.njk # error page, privacy notice
│ └── robots.njk, sitemap.njk, llms.njk # crawl files (robots.txt, sitemap.xml, llms.txt)
├── test/ # data.test.js (data contract), calc.test.js (maths), lastmod.test.js (sitemap), no-emdash.test.js (style)
└── docs/ # data sourcing, updating, next steps
Reusable Nunjucks macros in src/_includes/components/macros.njk:
| Macro | Purpose |
|---|---|
metricCard | A headline figure: value, explanation, "what this means", source note |
sourceNote | A dl of Source, Figure dated, Retrieved, Confidence and an optional Note, styled as one line |
caveatBox | A clearly flagged caution |
dataFreshnessBadge | Confidence level marker (official / provisional / estimated / calculated); says "Confidence:" to a screen reader unless called bare inside a labelled list |
glossaryTerm | A defined term |
The timeline chart renders a <table> fallback server-side, then enhances with SVG. The translator calculates in JavaScript and shows a <noscript> notice pointing at the sources page instead of results.
Every figure record carries provenance:
{
"metric_name": "Public sector net debt",
"value": 2917,
"unit": "£ billion",
"date": "2026-04-30",
"source_name": "ONS, Public sector finances",
"source_url": "https://www.ons.gov.uk/...",
"retrieved_date": "2026-06-10",
"notes": "Excludes public sector banks.",
"confidence_level": "provisional"
}
confidence_level is one of: official, provisional, estimated, calculated (defined in meta.json and enforced by the tests).
Built to WCAG 2.2 AA principles: semantic headings, keyboard-operable controls, the GOV.UK-style yellow focus state (yellow with a black companion, on every focusable element including the skip link), a large type scale (17px mobile, 19px from tablet up), 4.5:1 text contrast, 44px touch targets, no chart-only information (every chart has a table), labelled form fields with clear errors, mobile-first responsive layout, and prefers-reduced-motion support.
Verify, don't assume: run npm run a11y:all (pa11y-ci, WCAG 2.2 AA across every page) before publishing.
The audit is a regression guard, not a proof: it cannot tell a strong doing a title's job from a title, or a card that should be a list from one that is. These are checked by hand when a template changes.
article with an h3 (the dashboard and health cards).dl of dt/dd pairs, label first, on every page and in every script that injects cards. Source lines are this pattern too: sourceNote renders a dl and the stylesheet runs it as one line, so no page writes a source line as a paragraph.ul > li > article, so a screen reader announces the count (the dashboard, health and sources grids). A repeated set of plain items is a list too, without the article (the comparison bars on debt in context). These lists carry role="list", because list-style: none strips list semantics in WebKit.figure, outside it ("The chart below shows..."), with a link to the data table; the image itself is named "Line chart" and its figcaption carries the heading.div with role="note" and a real heading, not an aside.timeTag filter, so they carry datetime; readableDate is for text-only output.section with aria-labelledby appears only where a block needs a heading the design hides, or is a distinct labelled region such as a tool. Prose pages run bare h2s.tabindex="0" with role="region" and a name, because a focusable element needs both.aria-labelledby on an article with its own heading, no aria-label on a button with visible text.Built into the layout and a few generated files:
og-image.png).WebSite + Organization + WebPage site-wide, DefinedTermSet on the glossary, FAQPage on the debt-vs-deficit explainer.robots.txt (welcomes AI crawlers and links the sitemap), sitemap.xml, and llms.txt (a curated content guide for LLMs).The jsonScript filter escapes embedded JSON so data can't break out of a <script> tag.
Cloudflare Web Analytics: cookieless, no consent banner, no personal data. The beacon renders only when site.analytics.cloudflareToken is set in src/_data/site.json (the token is public, so it lives in the repo). See the /privacy/ page.
netlify.toml sets security headers on every response: a Content-Security-Policy (allows self, inline data/JSON-LD, and the Cloudflare beacon), plus X-Content-Type-Options, Referrer-Policy, X-Frame-Options, and Permissions-Policy. Assets are unfingerprinted, so caching is left to Netlify's deploy-aware revalidation (no long max-age) to avoid serving stale CSS/JS after a deploy.
docs/DATA-SOURCES.md: every source and what it covers.docs/UPDATING-DATA.md: how to refresh the figures.docs/NEXT-STEPS.md: what is built and what comes next.Neutral, factual, plain English, following the GOV.UK content style guide. Facts are separated from interpretation. No party-political blame. National debt is not presented as updating second-by-second. The household-finance analogy is used only with its limits spelled out.
The site is a static Eleventy build, hosted on Netlify. Config is in netlify.toml (build npm run build, publish _site, Node 24).
Connect the repo (recommended):
netlify.toml, so no manual build settings needed.main builds and deploys automatically; pull requests get deploy previews.Custom domain: Site settings → Domain management → Add a custom domain, then point your registrar's DNS at Netlify (or use Netlify DNS). HTTPS is automatic.
Quick one-off deploy (no Git): npm run build, then drag the _site folder onto the Netlify deploy page.
Node version is pinned in .node-version (24), so local (via fnm) and Netlify use the same runtime.
MIT. See LICENSE.