# InternetPressure.io — web frontend Next 16 (App Router, React 19, TypeScript strict, Tailwind 4) instrument for **The real-time pressure gauge for the Internet**. It renders the public API (`docs/API.md`) server-side, then follows the `/api/v1/live` SSE stream in small client islands. Dark-first, tabular numerals, no motion without a real update (spec §66), visible "Instrument degraded" state when `internal_status ≠ ok` (spec §57). ## Structure ``` apps/web ├── next.config.ts env loading (../../.env), /api → API_URL rewrite, security + cache headers, standalone output ├── Dockerfile multi-stage node:22-alpine → .next/standalone (port 8351) ├── mock/server.mjs DEV-ONLY API fixtures for every endpoint of docs/API.md, incl. SSE (never shipped) ├── scripts/copy-maplibre-worker.mjs copies MapLibre 6 module worker to public/maplibre (predev/prebuild) ├── qa/screens.mjs Playwright screenshots + overflow/console checks at 1440×900 and 390×844 ├── public/logo.svg gauge glyph (also inline in components/chrome/Logo.tsx and src/app/icon.svg) └── src ├── app │ ├── layout.tsx html.dark, Geist fonts, TimeProvider (UTC/local) │ ├── (site)/ public chrome: layout (LiveProvider + header/footer), all public routes │ ├── admin/ separate layout (token gate, no SSE) + 10 sections │ ├── opengraph-image.tsx OG image from the live index · robots.ts · sitemap.ts · error.tsx · not-found.tsx │ └── globals.css design tokens, pressure scale CSS variables, .tbl dense tables ├── components │ ├── chrome/ Header, NavLinks, Footer, Logo, LiveIndicator, DegradedBanner, TimeToggle, Search (⌘K) │ ├── gauge/ Gauge (the number), ExplainPanel (explain rows → components → signals) │ ├── home/ ComponentRows, Fronts, IncidentsList, Ticker, Clock, RegionsTable, ProbeStrip │ ├── map/ MapIsland (lazy, ssr:false) → WorldMap (MapLibre), ModeSelector, modes │ ├── charts/ echarts core registration, useEChart, HistoryChart, SeriesChart │ ├── detail/ ScopeHeader, ComponentGrid, Tables (targets/probes/latency matrix), ScopeCharts │ ├── incidents/ routes/ service/ history/ bgp/ targets/ admin/ │ └── ui/ primitives (Section, LevelBadge, Delta, Bar, Sparkline, Stat…), AnimatedNumber └── lib ├── types.ts TypeScript mirror of docs/API.md (public + admin) ├── api.ts server-side fetch (API_URL_INTERNAL, no-store, 404 → notFound) ├── live.tsx one EventSource per page, backoff reconnect, sliced store (useSyncExternalStore) ├── pressure.ts levels, colours, pressureColor(level|value), component labels ├── format.ts numerals, deltas (true minus), durations, formatTime(ts, utc|local) ├── time.tsx UTC/local toggle persisted in localStorage;