Skip to content

Commit 4c1009d

Browse files
Haibreadclaude
andauthored
docs: post-audit cleanup across CHANGELOG, CLAUDE, PLAN, README, design, ADR 0001, UI/UX plan (#60)
Sweep over the project's markdown to bring it back in line with the post-Phase-7 + post-audit codebase. Documentation was lagging in multiple places — the project audit's docs front had flagged most of this; this PR ships the fixes. CHANGELOG.md Repointed the `Unreleased` section to cover BOTH the existing Phase 7 access-control + change-approval bundle (PRs #28-#32 + #37) AND the project-audit follow-ups (PRs #52-#59) that just landed. The audit follow-ups subsection summarises each merged PR with its scope and verification, plus a deferred-items list (DisallowUnknownFields, rate-limiter janitor, per-handler child spans, eager markdown chunk). Added a note that a real version stamp is overdue. CLAUDE.md - Tech stack: drop the "sqlc or pgx" hedge — the codebase is pgx + hand-written SQL only. - Auth bullet: stop claiming hashed API keys are supported; they're parked under v0.4.x. Mirrored on Decision B in the table. - Deployment bullet: stop claiming docker-compose has dev + prod profiles. Only dev + ci exist; the prod profile is parked. - Conventions: drop the obsolete `claude/ai-registry-setup-KMC3l` bootstrap branch reference; describe the actual feat/fix/docs/chore convention. - Configuration section: "**both** of the following" → "**all three**" (env / YAML / default). Original wording predated the YAML layer and was only updated on the precedence list, not the lede. PLAN.md - Phase 5 hardening section: the four-line `**TODO — Phase 5:**` list was misleading — the items weren't unfinished Phase 5 work, they were carried forward into v0.4.x. Replaced with a "Parked from Phase 5 (now tracked under v0.4.x)" header that points at the README + CLAUDE.md Decision B for the live status. - v0.2.2 section: the entire DoD checklist was rendered as `- [ ]` even though the section header said "✅ SHIPPED". Replaced the unchecked checklist with a past-tense "What landed" summary, a "Carried forward" subsection for the OTel-spans gap that v0.2.2 only partially closed (PR #58 finished it), and a DoD-met note. README.md - Tech stack: PostgreSQL 16 → 18, matching the dev compose (postgres:18-alpine since PR #41) and the Helm CNPG cluster (PR #56). - Infra bullet: replace the "docker-compose (dev / ci / prod)" claim with an accurate description of the two real overlays (dev, ci) and a parked-under-v0.4.x note for prod. design.md - Typography table: drop the "Geist (next/font)" row — that loader was removed with the rest of the Next.js stack in Phase 6 (ADR 0004). The web app uses Tailwind's default `font-sans` / `font-mono` system stacks; explained in a follow-up paragraph. - Admin sidebar ASCII diagram: add the Workspaces nav item that Phase 7 introduced; rename "Activity" → "Audit" to match the actual nav label; flag the API Keys item as a placeholder. docs/adr/0001-workspaces-under-publishers.md - Drop the "Migration numbers ... are **placeholders**" preamble — the actual numbered migrations (000008, 000009, 000010) are on disk and the placeholder language is no longer accurate. - Mark Step 1 + Step 2 as shipped with the actual entry points (Go-side `db.BackfillWorkspaces` instead of the original `make backfill-workspaces`). - Add an explicit "Status note (2026-05-10)" callout that Step 3 (the finalising migration that drops `publisher_id` and flips `workspace_id` to NOT NULL) was scoped at design time but never landed; production keeps both columns coexisting and code paths still read `publisher_id` directly. Verified by grep against `internal/store/mcp.go`. docs/ui-ux-implementation-plan.md - Added a "Status: largely shipped — retrospective document" banner at the top. The document plans 10 batches, the vast majority of which shipped across v0.2.x and v0.3.x. Without the banner the file reads as forward-looking work and gives a misleading picture to anyone landing on it via search. Points the reader at PLAN.md and README.md for current open work. Out of scope (audit findings deliberately not addressed here): docs/ui-ux-proposals.md is a decision record (proposals + accepted / deferred verdicts), so staleness is by design — not a bug. The runbook, db-backup, future-multi-environment, ADRs 0002/0003/0004, and test/load README are all current. No code changes; no test impact. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 083aeb2 commit 4c1009d

7 files changed

Lines changed: 196 additions & 88 deletions

File tree

CHANGELOG.md

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@ All notable changes to this project are documented here.
44

55
## Unreleased
66

7-
Phase 7 access-control + change-approval bundle plus an admin UI polish
8-
sweep. The server-side work landed across PRs #28#32 and is reflected
9-
here for the first time; the UI polish landed in PR #37.
7+
Two distinct workstreams sit here pending the next version stamp:
8+
9+
1. **Phase 7 access-control + change-approval bundle plus an admin UI
10+
polish sweep.** Server-side work landed across PRs #28#32; UI
11+
polish landed in PR #37.
12+
2. **Project-audit follow-ups (PRs #52#59).** A four-front sweep
13+
produced a punch-list; the high-impact findings shipped as a
14+
batch of small, surgical PRs.
15+
16+
A real version stamp is overdue — the workstreams below are
17+
substantial enough that "Unreleased" understates them.
1018

1119
### 🏢 Workspaces under publishers
1220

@@ -91,6 +99,75 @@ new workflow surfaces had landed:
9199
surface the slug inline under the name where the dedicated column
92100
is hidden; page headers wrap.
93101

102+
### 🧭 Project-audit follow-ups (PRs #52#59)
103+
104+
A four-front audit (server, web, infra/config, docs) surfaced a P0/P1
105+
punch-list. The high-impact items shipped as small, surgical PRs;
106+
the deferred items are documented inline in the relevant PR
107+
descriptions.
108+
109+
- **PLAN refresh** (#52) — mark v0.2.2 / v0.3.0 / v0.3.1 / v0.3.2 as
110+
shipped; PLAN was lagging behind the actual release state.
111+
- **Doc + dead-code cleanup** (#54) — flip ADRs 0001/0002/0003 from
112+
`Proposed``Accepted`, drop the stale `next-themes` row from
113+
PLAN's Phase 6 migration table, prune dead Renovate rules
114+
(`next`, `eslint-config-next`, `next-auth`, `autoprefixer`,
115+
`tailwindcss-animate`), bump `@types/node` pin from `^22.0.0`
116+
`^24.0.0` (CI runs Node 24), delete the unused
117+
`compatibility-info.tsx` component.
118+
- **Config-layer fixes** (#55) — `PUBLIC_BASE_URL` and
119+
`BOOTSTRAP_FILE` were bypassing the config layer (read directly
120+
via `os.Getenv` from handlers and main), violating CLAUDE.md's
121+
env+YAML+default mandate. Both are now reachable via env, YAML
122+
(`http.public_base_url`, `bootstrap_file`), and a built-in
123+
default. The `--bootstrap-file` CLI flag still wins. The
124+
`OAuthProtectedResource` handler also dropped its silent
125+
`localhost:8081` fallback — empty `PublicBaseURL` now returns
126+
HTTP 500, mirroring `GlobalAgentCard`. 8 new tests pin the
127+
three-place rule.
128+
- **Helm CNPG postgres bump** (#56) — `cnpg.postgresVersion: "16"`
129+
`"18"`. Closes the version drift with the docker-compose stack,
130+
which moved to `postgres:18-alpine` in PR #41. `pg-probe` snippets
131+
in `docs/runbook.md` updated to match.
132+
- **ADR 0004 backfill** (#57) — Phase 6 (Next.js → Vite migration)
133+
was a cross-cutting decision but never got an ADR. `docs/adr/0004-vite-spa-migration.md`
134+
captures the rationale, alternatives considered, and historical
135+
implementation steps so the decision survives the next "why
136+
aren't we on Next.js?" question.
137+
- **OTel uplift** (#58) — three observability test gaps closed:
138+
- `router_otel_test.go` only pinned spans for 4 hand-picked routes;
139+
new `router_otel_walk_test.go` enumerates every chi-registered
140+
route and asserts every request lands inside an `otelhttp` span,
141+
so a future router change that drops instrumentation on any
142+
real handler fails CI.
143+
- `internal/observability/` was at 0.0% coverage; new
144+
`observability_test.go` pins log-level mapping, trace_id /
145+
span_id injection, and metric-instrument registration.
146+
- `internal/problem/` was at 0.0% coverage; new tests pin the
147+
RFC 7807 wire shape, `omitempty` semantics, and slug-as-URL
148+
contract.
149+
- Bonus: `handlers/config.go` (the SPA's `/config.json` bootstrap)
150+
gained its first tests covering the auth_storage coercion and
151+
the empty-issuer dev-boot case.
152+
- **P2 quality fixes** (#59) — three small surgical fixes:
153+
- **Counter drift on delete.** `CreateServer` / `CreateAgent`
154+
incremented `MCPServersTotal` / `AgentsTotal`; the matching
155+
delete handlers never decremented. The OTel `UpDownCounter`
156+
monotonically inflated. Fixed.
157+
- **Audit metadata silent-drop.** A `json.Marshal` failure in
158+
`store.LogAuditEvent` dropped metadata without a log entry;
159+
now we `slog.Warn` and continue with `metadata=NULL`.
160+
- **`flag.Parse` error swallow.** `_ = fs.Parse(os.Args[1:])` is
161+
now a structured `slog.Warn` so log aggregators see flag
162+
typos.
163+
164+
Deferred (documented in the audit synthesis but not shipped):
165+
`DisallowUnknownFields` rollout (no `additionalProperties: false`
166+
in the OpenAPI spec — needs per-endpoint risk analysis first),
167+
rate-limiter time-based janitor (bigger change), per-handler
168+
internal child spans, eager markdown chunk on detail pages
169+
(`React.lazy` deferral).
170+
94171
## v0.3.2
95172

96173
Helm-chart-only patch release. Four fixes that unblock a fresh

CLAUDE.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ A centralized registry for AI ecosystem artifacts:
3838

3939
## Tech stack
4040

41-
- **Server**: Go, `chi` router, PostgreSQL, `sqlc` or `pgx` for DB access,
42-
`golang-migrate` for schema migrations.
41+
- **Server**: Go, `chi` router, PostgreSQL, `pgx` for DB access (no ORM,
42+
hand-written SQL), `golang-migrate` for schema migrations.
4343
- **Auth**: OAuth2 / OIDC (external IdP, Keycloak in dev via docker-compose).
44-
JWT access tokens validated via JWKS. MCP-compatible. Also supports hashed
45-
API keys for machine-to-machine admin operations. Frontend uses `oidc-client-ts`
46-
as a PKCE public client (no client secret; no NextAuth/Auth.js).
44+
JWT access tokens validated via JWKS. MCP-compatible. Hashed API keys for
45+
machine-to-machine admin operations are planned but not yet implemented —
46+
see PLAN.md and Decision B below. Frontend uses `oidc-client-ts` as a PKCE
47+
public client (no client secret; no NextAuth/Auth.js).
4748
- **Frontend**: Vite + React Router v7 + TanStack Query v5 + TypeScript +
4849
shadcn/ui + Tailwind. A pure SPA served as static files from nginx. Public
4950
section for browsing; `/admin` section guarded by a `<RequireAuth>` wrapper.
@@ -52,8 +53,12 @@ A centralized registry for AI ecosystem artifacts:
5253
in `src/pages/`.
5354
- **OpenAPI**: hand-written OpenAPI 3.1 spec is the source of truth; server
5455
types and TS client are generated from it.
55-
- **Dev infra**: docker-compose for Postgres + Keycloak + server + web.
56-
- **Deployment**: docker-compose (dev + prod profiles) + Helm chart for k8s.
56+
- **Dev infra**: docker-compose for Postgres + Keycloak + server + web
57+
(`docker-compose.yml` baseline + `docker-compose.dev.yml` overlay for
58+
local development; `docker-compose.ci.yml` is CI-only).
59+
- **Deployment**: docker-compose for self-hosted single-host installs +
60+
a Helm chart for k8s with optional CNPG-managed Postgres. A dedicated
61+
`docker-compose.prod.yml` profile is parked under v0.4.x.
5762
- **Observability**: OpenTelemetry (OTel) for all signals — traces, metrics,
5863
and logs. Use the Go `go.opentelemetry.io/otel` SDK in the server; export
5964
via OTLP (gRPC or HTTP). Every HTTP handler must be traced; DB calls must
@@ -86,9 +91,9 @@ CLAUDE.md # this file
8691

8792
## Conventions
8893

89-
- **Branching**: feature work on `claude/ai-registry-setup-KMC3l` for initial
90-
setup; subsequent features on descriptive branches. Never push to `main`
91-
without explicit request.
94+
- **Branching**: feature work on descriptive feature branches
95+
(`feat/<topic>`, `fix/<topic>`, `docs/<topic>`, `chore/<topic>`). Never
96+
push to `main` without an explicit request.
9297
- **Commits**: conventional commits (`feat:`, `fix:`, `docs:`, `chore:`).
9398
- **DB**: schema changes are forward-only migrations. Down migrations are
9499
maintained for local development convenience only — never rely on them in
@@ -106,8 +111,8 @@ CLAUDE.md # this file
106111

107112
## Configuration (non-negotiable)
108113

109-
Every configuration value MUST be settable in **both** of the following ways,
110-
with the listed precedence (highest wins):
114+
Every configuration value MUST be settable in **all three** of the following
115+
ways, with the listed precedence (highest wins):
111116

112117
1. **Environment variable**`UPPER_SNAKE_CASE` (e.g. `DATABASE_URL`).
113118
2. **Config file key**`lower_snake_case` in a YAML file whose path is given
@@ -159,7 +164,7 @@ Rules for implementors:
159164
| # | Decision | Choice | Rationale |
160165
|---|----------|--------|-----------|
161166
| A | JWT admin claim | `realm_access.roles[]` contains `"admin"` | Keycloak default shape |
162-
| B | API-key auth | Deferred to Phase 5 | Phase 2 ships JWT-only; Phase 5 adds hashed API keys |
167+
| B | API-key auth | Deferred to v0.4.x | Phase 2-5 ship JWT-only; hashed per-publisher API keys parked under v0.4.x roadmap (see PLAN.md and README) |
163168
| C | `/v0/` wire format | Strict MCP registry spec shape | `{ servers: [{id, name, description, version, packages, repository, _meta}], metadata: {count, nextCursor} }` for list; single object for detail |
164169
| D | Integration test infra | testcontainers-go (postgres module) with snapshot isolation | No external dependency needed to run `go test` |
165170
| E | `packages` JSONB validation | Structural: each entry must have `registryType`, `identifier`, `version`, `transport.type` | Matches MCP server.json spec; strict schema deferred |

PLAN.md

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,20 @@ admin console. No `/api/v1/users` endpoint or `/admin/users` page will be built.
205205
route on publishers, MCP servers, and agents has dedicated coverage
206206
in `internal/http/handlers/*_test.go` (testcontainers Postgres).
207207

208-
**TODO — Phase 5:**
209-
- [ ] `POST /api/v1/api-keys`, `DELETE /api/v1/api-keys/{id}` — hashed API keys (per-publisher, machine-to-machine)
210-
- [ ] API-key auth middleware (JWT-first, fallback to API-key lookup)
211-
- [ ] Admin UI: API keys management page (`/admin/api-keys` — placeholder only today)
212-
- [ ] Docker Compose prod profile (`deploy/docker-compose.prod.yml`)
208+
**Parked from Phase 5 (now tracked under v0.4.x):**
209+
210+
These items were originally listed as Phase 5 TODOs but were not
211+
attempted before Phase 5 closed. They are now part of the v0.4.x
212+
roadmap (see [README — Roadmap](README.md) and CLAUDE.md Decision B):
213+
214+
- `POST /api/v1/api-keys`, `DELETE /api/v1/api-keys/{id}` — hashed API
215+
keys (per-publisher, machine-to-machine).
216+
- API-key auth middleware (JWT-first, fallback to API-key lookup).
217+
- Admin UI: real API-keys management page (the `/admin/api-keys`
218+
route ships as a placeholder today; the test file has a single
219+
`it.skip` waiting on the endpoints).
220+
- Dedicated `deploy/docker-compose.prod.yml` profile for self-hosted
221+
production single-host installs.
213222

214223
### Phase 6 — Migrate web app from Next.js → Vite + React SPA ✅ COMPLETED
215224

@@ -316,50 +325,43 @@ test-only — no shipping features in this release unless they fell out
316325
of fixing a bug surfaced by the new tests. See CHANGELOG `v0.2.2` for
317326
the full coverage / CI / performance summary.
318327

319-
**Web — admin depth**
320-
- [ ] Interactive coverage on `admin/mcp/detail.tsx` and `admin/agents/detail.tsx`:
321-
per-version publish, deprecation, edit-in-place, status transitions, and
322-
the lifecycle stepper. Today these files only have render-and-link smoke
323-
tests.
324-
- [ ] Real flow for `admin/api-keys.tsx` (currently a single `it.skip` waiting
325-
on Phase 5). Lifts as soon as the API-key endpoints land.
326-
- [ ] Extract the shadcn/Radix Select jsdom shims (`hasPointerCapture`,
327-
`releasePointerCapture`, `scrollIntoView`) into `web/src/test/setup.ts`
328-
so individual test files stop re-declaring them.
329-
- [ ] OIDC token refresh / expired-session paths in `AuthContext`
330-
`accessTokenExpiring` event, silent-renew failure, logout-on-401.
331-
332-
**Server — protocol & spec conformance**
333-
- [ ] OTel span emission tests: every HTTP handler must produce a span with
334-
the documented attributes (per CLAUDE.md "every new handler gets a
335-
span"). Use the OTel test SDK / in-memory exporter.
336-
- [ ] Migration tests: forward apply of every numbered migration against a
337-
fresh testcontainers Postgres, plus idempotency (running `Migrate`
338-
twice must be a no-op).
339-
- [ ] `/v0/` MCP wire-format conformance suite — assert the exact response
340-
shape from the MCP registry spec (`{servers, metadata: {count, nextCursor}}`,
341-
single-object detail, `_meta`, `packages[].registryType`, etc.).
342-
- [ ] A2A Agent Card schema conformance — validate the per-agent
343-
`/.well-known/agent-card.json` and the global card against the pinned
344-
a2a-project June 2025 schema (decision G).
345-
- [ ] `openapi.yaml` ↔ handler contract test: every documented path/operation
346-
must have a matching route, and every registered route must be
347-
documented. Catches drift between spec and implementation.
348-
- [ ] Router-level test for `PublicRateLimitRPM` wiring — a test request
349-
loop that proves the env/YAML value reaches the per-IP bucket and
350-
changes the cutoff.
351-
352-
**Server — write paths**
353-
- [ ] Audit every `POST` / `PATCH` / `DELETE` handler for untested error
354-
branches (RFC 7807 problem responses, 409 conflicts, 422 validation,
355-
403 admin-guard short-circuits). Today happy paths and 404s are well
356-
covered, error branches less so.
357-
358-
**Definition of done for v0.2.2**
328+
**What landed**
329+
330+
- *Web admin depth.* Interactive coverage on `admin/mcp/detail.tsx` and
331+
`admin/agents/detail.tsx` (per-version publish, deprecation,
332+
edit-in-place, status transitions, lifecycle stepper). Shared
333+
shadcn/Radix Select jsdom shims (`hasPointerCapture`,
334+
`releasePointerCapture`, `scrollIntoView`) extracted into
335+
`web/src/test/setup.ts`. OIDC token-refresh / expired-session paths
336+
in `AuthContext` (`accessTokenExpiring`, silent-renew failure,
337+
logout-on-401).
338+
- *Server protocol & spec conformance.* Migration forward-and-idempotent
339+
apply tests against a fresh testcontainers Postgres. `/v0/` MCP
340+
wire-format conformance suite. A2A Agent Card schema conformance
341+
against the pinned a2a-project June 2025 schema (decision G).
342+
`openapi.yaml` ↔ router contract test (bijection enforced via
343+
`chi.Walk`). Router-level test for `PublicRateLimitRPM` wiring.
344+
- *Server write paths.* Error-branch coverage on every `POST` / `PATCH`
345+
/ `DELETE` handler (RFC 7807 shapes, 409 conflicts, 422 validation,
346+
403 admin-guard short-circuits).
347+
348+
**Carried forward**
349+
350+
- *OTel span emission tests.* v0.2.2 landed a focused 4-route span
351+
smoke test (`router_otel_test.go`); the broader "every handler"
352+
coverage came later in PR #58 (audit follow-up) via
353+
`router_otel_walk_test.go` which enumerates every chi-registered
354+
route and asserts each request lands inside an `otelhttp` span.
355+
- *`admin/api-keys.tsx` real flow.* Still a single `it.skip`
356+
unblocks once the API-keys endpoints land in v0.4.x.
357+
358+
**Definition of done (met at release)**
359+
359360
- Coverage report shows no admin page below 80 % statement coverage.
360-
- Every handler has at least one OTel span assertion.
361361
- `/v0/` and A2A conformance suites are in CI and gating.
362362
- `openapi.yaml` ↔ router contract test is in CI and gating.
363+
- "Every handler has at least one OTel span assertion" — partially met
364+
in v0.2.2 (focused smoke test), fully met in PR #58.
363365

364366
### v0.3.0 — Browse polish ✅ SHIPPED
365367

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ AI Registry gives teams a single place to publish, discover, and evaluate the bu
5656

5757
## Tech stack
5858

59-
**Server** — Go 1.25 · [chi](https://github.com/go-chi/chi) v5 · [pgx/v5](https://github.com/jackc/pgx) · PostgreSQL 16 · [golang-migrate](https://github.com/golang-migrate/migrate) · [jwt/v5](https://github.com/golang-jwt/jwt) · [oklog/ulid](https://github.com/oklog/ulid) · [testcontainers-go](https://github.com/testcontainers/testcontainers-go) · OpenTelemetry SDK + OTLP exporter
59+
**Server** — Go 1.25 · [chi](https://github.com/go-chi/chi) v5 · [pgx/v5](https://github.com/jackc/pgx) · PostgreSQL 18 · [golang-migrate](https://github.com/golang-migrate/migrate) · [jwt/v5](https://github.com/golang-jwt/jwt) · [oklog/ulid](https://github.com/oklog/ulid) · [testcontainers-go](https://github.com/testcontainers/testcontainers-go) · OpenTelemetry SDK + OTLP exporter
6060

6161
**Frontend**[Vite](https://vitejs.dev/) · React 19 · [React Router v7](https://reactrouter.com/) · [TanStack Query v5](https://tanstack.com/query/v5) · TypeScript · [shadcn/ui](https://ui.shadcn.com/) + Radix · Tailwind v4 · [oidc-client-ts](https://github.com/authts/oidc-client-ts) · Vitest + React Testing Library · Playwright (e2e)
6262

63-
**Infra** — docker-compose (dev / ci / prod) · Helm chart with optional CNPG-managed PostgreSQL cluster, HTTPRoute, and Ingress · Keycloak for local OIDC · OTel Collector
63+
**Infra** — docker-compose (`docker-compose.yml` baseline + `dev` overlay; `ci` overlay for CI only) · Helm chart with optional CNPG-managed PostgreSQL 18 cluster, HTTPRoute, and Ingress · Keycloak for local OIDC · OTel Collector. (A dedicated `docker-compose.prod.yml` profile is parked under v0.4.x.)
6464

6565
**API spec** — Hand-written OpenAPI 3.1 at `server/api/openapi.yaml` (**81 operations**), embedded into the binary and served live at `/openapi.yaml`. Server types and the TypeScript client are generated from the spec. A bijection test ensures the router and spec never drift.
6666

design.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -505,11 +505,18 @@ system handles the swap automatically.
505505

506506
| Role | Font | Weight | Size |
507507
|------|------|--------|------|
508-
| Display heading | Geist (next/font) | 700 | `text-3xl``text-5xl` |
509-
| Section heading | Geist | 600 | `text-xl``text-2xl` |
510-
| Body | Geist | 400 | `text-sm``text-base` |
511-
| Label / caption | Geist | 500 | `text-xs``text-sm` |
512-
| Code / version | Geist Mono | 400 | `text-xs``text-sm` |
508+
| Display heading | Tailwind `font-sans` (system stack) | 700 | `text-3xl``text-5xl` |
509+
| Section heading | `font-sans` | 600 | `text-xl``text-2xl` |
510+
| Body | `font-sans` | 400 | `text-sm``text-base` |
511+
| Label / caption | `font-sans` | 500 | `text-xs``text-sm` |
512+
| Code / version | `font-mono` (system monospace stack) | 400 | `text-xs``text-sm` |
513+
514+
The web app does not bundle a webfont — Tailwind's default system stacks
515+
(`font-sans``ui-sans-serif, system-ui, …`; `font-mono`
516+
`ui-monospace, SFMono-Regular, …`) keep first-paint fast and the bundle
517+
small. The original Next.js scaffold used `Geist` via `next/font`; that
518+
loader was dropped along with the rest of the Next.js stack in Phase 6
519+
(see [ADR 0004](docs/adr/0004-vite-spa-migration.md)).
513520

514521
#### Spacing & Radius
515522

@@ -592,12 +599,13 @@ redirect to the IdP authorize endpoint and a callback flow handled by
592599
│ Review │ │
593600
│ queue │ ⓘ │
594601
│ Publishers│ │
602+
│ Workspaces│ (Phase 7 — nested under each publisher) │
595603
│ MCP │ │
596604
│ Servers │ │
597605
│ Agents │ │
598606
│ Reports │ │
599-
Activity │ │
600-
│ API Keys │
607+
Audit │ │
608+
│ API Keys │ (placeholder — see PLAN.md v0.4.x)
601609
│ │ │
602610
└──────────┴──────────────────────────────────────────┘
603611
```

0 commit comments

Comments
 (0)