영어 원문
이 설계 기록은 역사적 맥락과 원문의 의미를 보존하기 위해 영어로 제공합니다.
ADR-001: Minimal embedded admin key console¶
Date: 2026-06-11 Status: Accepted Deciders: maintainers, with a 2-round multi-model consensus gate (codex gpt-5.5, gemini 3.1-pro) on the implementation plan Related: design spec §9 (roadmap), Appendix A ("UI separation" decision), §5.5 (admin auth)
Context¶
The design spec deliberately keeps UI out of the v0.1 core. Appendix A records the regret-prevention decision "keep UI out of core (self-service only in v0.2)" — a full UI in core was rejected as "a frontend-maintenance tax on a small-maintainer project." The v0.2 roadmap carries "key-issuance self-service page (minimal UI — log in → issue my key)".
Meanwhile v0.1 operators have only two key-management surfaces: the
token-gated /admin/keys JSON API and the local inferplane keys CLI.
Operators evaluating the gateway (the "attach it in 5 minutes" pitch) asked
where the admin page is — there is none, and that gap is felt in the first
five minutes.
Decision¶
Pull forward only the minimal key console from the v0.2 line, with a hard ceiling on frontend surface:
- One Go package
internal/server/adminuiembedding three static files (index.html,app.js,style.css) viago:embed— no build step, no framework, no npm, no toolchain. The assets ship inside the single static binary. - Served on the admin plane at
GET /admin/ui/. The static assets are data-free (no key material, no team data, nothing secret) and therefore served unauthenticated — the same posture as/metricson the same plane (§5.5). All data operations go through the existing token-gated/admin/keysJSON API; the operator pastes the admin Bearer token into the page, which holds it in a JS variable only (never localStorage, never cookies, never the URL). - The page covers exactly the existing API surface: list keys, create a key
(plaintext
ik_...rendered once with a "will not be shown again" warning), revoke a key. Nothing else. - Responses carry a strict CSP (
default-src 'self') andX-Content-Type-Options: nosniff.
Alternatives considered¶
- Full SPA (React/Vue + npm toolchain). Rejected — exactly the maintenance tax Appendix A predicted: lockfiles, supply-chain surface, a second build system in a CNCF-aspiring single-binary Go project.
- Server-rendered templates with session/cookie auth. Rejected — invents a second authentication path on the admin plane (sessions, CSRF) where one already exists (Bearer token, SHA-256 constant-time). More security surface for no capability gain.
- Postpone entirely to v0.2 (status quo). Rejected for the key console only — the v0.1 evaluation experience demonstrably stalls at "where do I issue a key?". The OIDC-login self-service page (per-user keys) remains v0.2; this console is the operator view of the API that already ships.
Consequences¶
- Frontend tax is capped at three dependency-free static files; any future growth of the UI requires a new ADR.
- The unauthenticated surface of the admin plane grows by static assets only;
the authenticated JSON API is unchanged. The admin plane remains
cluster-internal by deployment convention (§5.5) — operators exposing
:9090publicly were already exposing/metricsand must keep using network policy, not obscurity. - The v0.2 self-service page (OIDC login → my keys) builds on, and does not replace, this console.
- Tests enforce the posture: assets contain no secrets and no
localStorage/document.cookieusage;/admin/keysstays 401 without a token after the UI is wired.