Skip to content

UX design: dashboard and admin console

Status: approved contract (synthesized from dual UX reviews — Qwen + terra/Sol, with tiny-reviewer pairing). This is the reference for implementation; deviations need review.

Dashboard (tenant, Supabase session auth) — two peer sections:

  • Repositories (primary): “Add repository” button + the repo list/cards.
  • Connections (secondary): “Add connection” button + the connection list.

Admin console (/admin, X-Admin-Key auth) — a console, not a table:

  • Overview counters row: tenants, repos, connections, reconcile failures, unprovisioned/needs-admin repos, held leases.
  • Persistent search/filter bar: repo slug, forge host, tenant id.
  • Tabs: Repositories | Connections | Stats.
  • Tenant detail drawer: a tenant’s connections + repos + provisioning/reconcile state.

Each managed repo row shows:

  • owner/repo and base branch.
  • Connection badge: bot @ host (from forge_connections), clickable → tooltip with connection details (bot, host, token type, created_at).
  • Wake mode: poll (cron, every 5 min) or webhook. Display chip; editable per repo.
  • Provisioning chips (independent): Webhook and Branch protection, each Ready | Needs admin | Not configured | Error, with a timestamp/detail on hover. Poll mode shows webhook as Not required.
  • Reconcile status: ok / error / unknown + last run time; Reconcile now button.
  • Remove with confirmation.
  • Dedup: normalized identity (tenant_id, instance_url, bot_username) is unique — enforced by a DB constraint and handled in POST /api/v1/connections (report “Using existing connection” instead of creating a duplicate).
  • Per connection: repos using it, Rotate token (credential form → PATCH /api/v1/connections/:id, never returns tokens), Remove (named confirm explaining that its managed repos are cascade-deleted).
  • Add-repo flow: choose an existing connection first; creating a new connection is a distinct, explicit action (no credential re-entry when adding more repos).
  • On add and on Provision, show a result panel: per-item outcome for webhook and branch protection (status + detail).
  • Needs admin → inline guidance: (a) upgrade the connection token to repo-admin scope, (b) Retry provisioning (disabled while running), (c) Set up manually — expandable Forgejo steps (webhook URL https://api.gondolier.dev/api/v1/webhooks/forgejo, events, per-repo secret; branch protection with the repo’s status_context as a required check).
  • Poll mode: webhook item is Not required; protection still applies.
  • Verification reads actual forge state, so manual setup is detected as Ready.

One complete safe repo view returned by both GET /api/v1/user/repos and GET /api/v1/user/queue/status:

{ id, name, base_branch, status_context, merge_style, automerge, instance_url,
forge_conn_id, connection: { bot_username, instance_url, token_type },
wakeup_mode, provisioning: { webhook: {status, detail?}, protection: {status, detail?},
last_provisioned_at }, reconcile: { ran_at, ok, error? }, lease_state }

Fixes the wake-mode reset (the status previously omitted settings.wakeup_mode and PATCH merged stale settings back) and gives the UI a stable id for CRUD.

  • PATCH /api/v1/user/repos/:id — set wakeup_mode; optimistic in the UI; provisioning receives the requested mode, not stale settings.
  • PATCH /api/v1/connections/:id — rotate credentials (token in request only).
  • POST /api/v1/user/repos/:id/reconcile — one-shot reconcile trigger.
  • POST /api/v1/connections — dedup via the unique constraint + conflict fetch.
  • Supabase creates use Prefer: return=representation; created-row reads guard body?.length.
  • No credentials ever appear in responses or logs.
  • GET /api/v1/admin/repos — enrich with connection display + provisioning + reconcile (safe fields only); support q, limit (≤100), offset.
  • GET /api/v1/admin/connections — all connections (incl. zero-repo), token-free.
  • GET /api/v1/admin/stats — actionable counts (tenants, repos, connections, reconcile failures, unprovisioned/needs-admin, held leases).
  • Search/filter client-side over the fetched sets; tenant drawer opens from a repo row.

7. Implementation order (unambiguous tasks, each its own PR)

Section titled “7. Implementation order (unambiguous tasks, each its own PR)”
  1. API/state (index.mjs + dedup migration + tests): complete repo view, PATCH wakeup_mode by id, PATCH connections rotation, POST reconcile, dedup constraint + conflict handling, return=representation fixes, safe admin enrichments.
  2. Dashboard (site/dashboard.html): two sections, repo cards, connections management (add/rotate/remove), provisioning result panel, optimistic PATCH, Reconcile-now, remove-confirm.
  3. Admin console (site/admin.html): counters, search, tabs, tenant drawer.
  4. Docs: this doc (already) + docs/API.md + docs/getting-started/hosted-setup.md.

Each task: validate (node --check, JS tests where feasible, git diff --check), commit (cloudkoopa identity, no Copilot trailer), open a PR. Pair with tiny-reviewer per task.