Skip to main content
vibld

Template

Tokenmoor

The API keys management page in a developer workflow platform. Admins see every organisation key with masked value, scopes, creation date, last use, expiry and status, and can create or revoke keys.

Organisation API keys table · App screen: table · Small tools and apps · full-stack app (auth + DB)

A mock-up of the screen, drawn from its layout, palette and typefaces. A build follows the full prompt below.

Start from this screenRead the build prompt

Typefaces

The catalog's own faces. A screen composed into a template is drawn in that template's typefaces.

  • InterHeadings: Inter 600, 24px H1
  • InterBody: Inter 400/500, 15px table cells (dense table), 16px elsewhere; column headers 14px 500

Patterns

  • persistent left sidebar with grouped nav
  • page header with primary action
  • bordered data table in card
  • mono key chip
  • status and expiry chips
  • row-level destructive icon button
  • theme switcher in sidebar footer

States it is designed for

  • Loading skeleton rows
  • Empty ('No API keys yet' with Create button)
  • Never used ('Never' in Last used)
  • Expired row (muted, Expired chip)
  • Revoked row (strikethrough name, Revoked chip, no delete)
  • Revoke failure toast with retry
  • Non-admin view (no create/revoke, explanatory note)

Who it is for

  • Developers wiring CLI, SDK or API access
  • Platform admins auditing credentials
  • Security reviewers checking stale keys

Layout

  1. Left sidebar 240px: logo + product name, primary nav (Trigger, Runs, Reviews, Monitoring), labelled groups (Agent, Workflow, Developer) with active item as dark pill; footer: docs link, theme segmented control, collapse
  2. Top bar: org avatar + name switcher, breadcrumb 'API keys'
  3. Page header: H1, one-line description, dark 'Create API key' button right
  4. Table card: Name (key icon + name), Key (mono chip), Scopes (chip), Created, Last used, Expires (chip), Status (chip), delete icon
  5. Below 900px: table becomes stacked cards; sidebar becomes a drawer

Palette

precise, calm, utilitarian. Credentials presented like inventory, nothing flashy.

  • app background#f7f7f7
  • table card#ffffff
  • primary text#18181b
  • muted text#5e5e66
  • table/input border#8a8a93
  • chip fill#f0f0f1
  • dark button / active nav#18181b
  • danger icon#b42318
  • danger icon hover fill#fef3f2
  • success status#15803d
  • focus ring#2563eb

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on card17.72:14.5:1
Aamuted text on app bg6.00:14.5:1
Aachip text on chip fill15.56:14.5:1
Aabutton label on dark17.72:14.5:1
danger icon on hover fill6.05:13:1
Aastatus text on card5.02:14.5:1
table border3.42:13:1
focus ring5.17:13:1

As vibld’s tokens

The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on.

  • background
  • card
  • muted
  • primary
  • secondary
  • accent
  • destructive

Type scale

Display
Inter 600, 24px H1
Body
Inter 400/500, 15px table cells (dense table), 16px elsewhere; column headers 14px 500

Keys and scopes in JetBrains Mono 13px inside chips; similar to the observed grotesk + mono pairing.

Spacing and imagery

Dense table: 52px rows, 16px cell padding; page padding 16px/24px; card radius 10px, chips radius 6px; sidebar item 36px tall radius 8px.

Line icons only (key, trash, external link); no imagery.

Components

  • Grouped sidebar nav
  • Org switcher
  • Page header with action
  • Data table
  • Mono key chip
  • Scope chip
  • Expiry chip
  • Status chip
  • Row delete (revoke) icon button
  • Revoke confirm dialog
  • Create key dialog
  • Empty state

Interactions

  • Sortable Created and Last used columns
  • Hover row tint; delete icon turns red-tinted on hover
  • Revoke opens confirm dialog requiring the key name to be typed
  • Create key opens dialog then the one-time reveal sheet
  • Theme control switches system/light/dark

Data

  • ApiKey{id, org_id, name, prefix, scopes[], created_at, last_used_at, expires_at, status (active|expired|revoked), created_by}
  • OrgMember{org_id, user_id, role (owner|admin|member)}
  • AuditEvent{org_id, actor_id, action, target_id, at}

Guardrails

Experience

  • Never show full keys in the table; prefix + ellipsis only
  • Show 'Never' for unused keys so stale ones stand out
  • Make revoke deliberate: typed confirmation
  • Keep status as text chips, not dots
  • Explain to non-admins why actions are missing

Accessibility

  • Table uses real th with scope and aria-sort on sortable columns
  • Icon-only delete button has an accessible name including the key name
  • Chips contain text; colour is secondary
  • Confirm dialog focuses the input and returns focus on close
  • Dense 15px text only in table cells

Security

  • Only a salted hash and prefix are stored; plaintext never retrievable
  • RLS: members select via a view without the hash; owners/admins insert and revoke
  • Revoke is an update to status; no hard deletes, for audit
  • Audit create/revoke with actor and time
  • Rate-limit create and revoke endpoints

Build prompt

The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.

The baseline
### How to use these prompts
Paste an entry's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project.

### Engineering baseline
- TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone.
- Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only.
- Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables.

### Data and auth baseline (full-stack entries)
- Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views.
- Store roles in a separate table checked by a security-definer function, never in a user-editable profile field.
- Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs.
- Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms.
- Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data.

### Accessibility and UX baseline
- Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change.
- Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels.
- Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images.
- Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives.
- Build mobile-first and test at 375px, 768px and 1280px.

### Content guardrails
- Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text.
- Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.

### SaaS screen baseline
- Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs.
- Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible.
- Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy.
- Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke.
- Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal
Build **Tokenmoor**'s organisation API keys page for a developer workflow platform. Admins list, create and revoke keys; every row shows masked value, scopes, created, last used, expiry and status so stale or risky keys are obvious.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix primitives) and lucide-react icons. TanStack Query for server state, react-hook-form + zod for forms, date-fns for dates. Supabase for Auth, Postgres and Row Level Security. TanStack Table for sorting; an Edge Function for key creation.

### Pages & layout
1. **Sidebar** (240px, `--bg`): logo + product name; nav Trigger, Runs, Reviews, Monitoring; group 'Agent' (Agents, Shared resources); 'Workflow' (Workflows, Templates); 'Developer' (Webhooks, API keys active, Connect); Settings. Footer: Documentation (external icon), theme segmented control (system/light/dark), collapse button, user avatar.
2. **Top bar**: org avatar + name dropdown, breadcrumb 'API keys'.
3. **/settings/api-keys**: H1 'API keys', muted 'Create and manage organisation keys for CLI, SDK and API access', dark '+ Create API key'.
4. **Table card**: columns Name, Key (`tk_live_ab12...` mono chip), Scopes (`*` or named scopes), Created (`Sep 21, 2026, 1:22 PM`), Last used (`Never`/relative), Expires chip, Status chip, revoke icon.
5. Below 900px: rows become cards with label/value pairs; sidebar in a drawer.

### Design system
- Colors: `--bg: #f7f7f7` (app background), `--card: #ffffff` (table card), `--fg: #18181b` (primary text), `--muted: #5e5e66` (muted text), `--border: #8a8a93` (table/input border), `--chip: #f0f0f1` (chip fill), `--primary: #18181b` (dark button / active nav), `--danger: #b42318` (danger icon), `--danger-bg: #fef3f2` (danger icon hover fill), `--success: #15803d` (success status), `--ring: #2563eb` (focus ring).
- Fonts: Inter 400/500/600; H1 24px 600; body 16px/1.5; table cells 15px; JetBrains Mono 13px in chips.
- Spacing: 4px base; row height 52px; page padding 24px.
- Radius: card 10px, buttons 8px, chips 6px.
- Shadows: none; card border 1px `--border` at 35% opacity.
- Motion: 120ms hover tints; dialog fade/scale 150ms.

### Components & interactions
`AppSidebar` (grouped nav, active dark pill), `OrgSwitcher`, `PageHeader`, `KeysTable` (TanStack Table, aria-sort), `KeyChip`, `ScopeChip`, `ExpiryChip`, `StatusChip`, `RevokeButton` (icon, aria-label 'Revoke key Backend service'), `RevokeDialog` (type key name to confirm), `CreateKeyDialog` (name, scopes, expiry: never/30/90/365 days), `EmptyState`, `ThemeControl`.

### Data & state
`api_keys(id, org_id, name, prefix, key_hash, scopes text[], created_by, created_at, last_used_at, expires_at, status)`, `org_members(org_id, user_id, role)`, `audit_events`. Expose `api_keys_public` view without `key_hash`. Status derived: expired when `expires_at < now()`. Mock: one active never-used key, one expired, one revoked.

### Accessibility
Real table semantics with `aria-sort`; icon buttons labelled with the key name; chips are text. Dialog focus management via Radix. Keyboard: Enter on a row opens key details; Delete key triggers revoke dialog for admins. Focus ring 2px `--ring`.
Verified contrast: body text on card: #18181b on #ffffff = 17.72:1; muted text on app bg: #5e5e66 on #f7f7f7 = 6.00:1; chip text on chip fill: #18181b on #f0f0f1 = 15.56:1; button label on dark: #ffffff on #18181b = 17.72:1; danger icon on hover fill: #b42318 on #fef3f2 = 6.05:1; status text on card: #15803d on #ffffff = 5.02:1; table border: #8a8a93 on #ffffff = 3.42:1; focus ring: #2563eb on #ffffff = 5.17:1.

### Security
RLS: `api_keys` select for members through the view; insert/update (status only) for owner/admin; no delete policy. `audit_events` insert only via security-definer function, select for admins. Keys generated server-side with a CSPRNG; hash with a per-key salt. Rate-limit create/revoke to 30/hour per org.

### Performance & SEO
Server-side pagination beyond 50 keys. Lazy-load dialogs. App routes `noindex`.

### Guardrails
- Invent key prefixes, names and org names.
- No real vendor names in scopes.
- Never render plaintext keys in this table.

Acceptance criteria:
- [ ] Sorting by Created and Last used works
- [ ] Revoke requires typed name and flips status
- [ ] Members without admin role cannot create or revoke (RLS)
- [ ] Empty state appears with zero keys
- [ ] Contrast pairs pass

Open the builderAll templatesThis palette on its own