4.6 KiB
Billing frontend
React + TypeScript, shadcn/ui (Radix), Tailwind CSS. Bun installs dependencies and produces a static browser bundle. No frontend runtime service or CDN is needed in production.
Commands
bun install --frozen-lockfile
bun run format
bun run check
bun run build
From the plugin root, scripts/build-ui.ps1 or bash scripts/build-ui.sh installs locked dependencies, checks formatting/types and builds the UI. The full plugin build calls the same frontend build first.
The compiler writes internal/web/dist/{ui.html,ui-config.js,app/main.js,styles/main.css}. These four generated files are intentionally tracked: go:embed needs them even for a Go-only checkout. Do not edit them manually. Source files, component files, Prettier configuration and bun.lock are tracked. node_modules, caches, logs, local environment files and temporary runtime outputs are ignored.
Preview
After building, run from the plugin root:
go run ./cmd/webdemo -input fake -listen 127.0.0.1:8320
Open http://127.0.0.1:8320/ui. The demo uses in-memory data, including notes/history operations. Changes made in the demo never affect the billing database. Restart/rebuild the Go preview after a frontend build because assets are embedded at compile time.
Structure
src/app.tsx: navigation, credential dialog, theme integration.src/lib/api.tsx: transport, read-only fallback and access state.src/pages: overview, requests, users, prices and logs; forms live in separate panels.src/components/ui: components installed by the official shadcn CLI.src/components/common.tsx: shared page-level presentation.src/styles.css: Tailwind and management-compatible color tokens.
Keep source formatted with Prettier (2 spaces, 100-column target). Run bun run format:check and bun run check before rebuilding. UI components are installed rather than recreated; use bunx shadcn@latest add <component> for additions and check the generated imports resolve to @/lib/utils.
Embedding and access
Assets use relative URLs, so the same build runs at /ui and /v0/resource/plugins/billing/ui. Go registers only the compiled asset paths. Same-origin iframes observe the parent document's data-theme attribute, including the light, white and dark themes from CPA management. Cross-origin embeds use local/system theme preferences.
The existing window.BILLING_UI_CONFIG contract and management-key discovery remain supported. Anonymous reads use the existing resource endpoint's view query. Writes always use the protected management API; UI controls are hidden without a verified management credential. Tokens and credentials are never placed in bundle source or URLs.
Requests retain server pagination and filters. Notes/history use their operation category as the display type and action as the endpoint label. Complete paths, timing and all usage fields remain available in the detail sheet. Auxiliary operations have no synthetic token charge.
The request table and detail sheet display cache rate as cache-read tokens divided by input tokens, using the API's percentage value with one decimal place. Auxiliary operations, zero-input requests, and records without a valid cache rate display an em dash; measured zero cache hits display 0.0%.
Layout
Keep the 46px header on one row, without a subtitle. Pages start with their data or a single search/action toolbar, without introductory headings or descriptions. The overview preserves the user totals table, seven-day stacked cost chart, and quota/concurrency bars in that order. Requests use compact single-line rows. User and model cards open on click or keyboard activation; user status and model pricing conditions appear beside their names. Keep the long-context price row present even when no rates are configured.
Dedicated reverse-proxy domain
When mapping / to /v0/resource/plugins/billing/ui, also map relative asset requests. For Caddy, add these rules inside the billing site block before the reverse proxy:
@root path /
rewrite @root /v0/resource/plugins/billing/ui
@billingAssets path /app/* /styles/* /ui-config.js
rewrite @billingAssets /v0/resource/plugins/billing{uri}
reverse_proxy cpa:8317
Preserve query strings for read-only requests such as /?view=usage-summary. Verify /app/main.js, /styles/main.css, and /ui-config.js return their correct content types through the public domain after deployment; verifying only the upstream resource URLs does not cover these rewrites.