---
id: w1/m11.5/t002
title: Custom Domains table in Settings (list, status badges, empty state)
worker: worker1
status: done
estimate: 40m
depends_on: [w1/m11.5/t001]
---

## Objective

Add the Custom Domains read section to the service Settings tab: a table listing
each domain with its Name (external link), Verified Status badge, and Certificate
Status badge — matching Render's Settings → Custom Domains layout captured live
on 2026-07-09.

## Context

- **Render capture (2026-07-09):** table has a "Name" column (domain as a clickable
  external link, count shown as "N total row"), "Verified Status" column (badge:
  "Verified" with green check, or pending), and "Certificate Status" column (badge:
  "Unknown" / "Active" with icon). Per-row kebab "Menu" button (actions in t004).
- bex-api maps: `verificationStatus` → "verified" | "pending"; `serverStatus` →
  "active" | "pending". The `id` field equals `name` (hostname used as opaque id).
- Settings tab lives at `dashboard/src/routes/services.$serviceId.settings.tsx`;
  today it only shows `InstanceTypeRow`.
- Pattern: add a new `CustomDomainsSection` component under
  `src/features/services/components/`, wire `useCustomDomainsQuery` from t001.
- Follow the dashboard visual pattern (`dashboard/CLAUDE.md` § Visual layout pattern):
  `space-y-6` between sections, shadcn `Card` wrapping the table.
- All user-visible strings through `useTranslations()` with `services.*` keys
  and matching `en`/`zh` locale entries.

## Steps

1. Create `src/features/services/components/custom-domains-section.tsx`:
   - Call `useCustomDomainsQuery({ variables: { id: serviceId } })`.
   - Render a shadcn `Table` with columns: Name, Verified Status, Certificate Status,
     and an empty Actions column header (populated in t004).
   - Name cell: external `<a href="https://{name}" target="_blank">` link.
   - Status badges: use shadcn `Badge` variant `outline` for "pending" (yellow/muted)
     and `default` (or `success`) for "verified"/"active".
   - Empty state: a centered paragraph "No custom domains configured." with an
     "Add Custom Domain" placeholder button (wired in t003).
   - Loading state: `<Skeleton>` rows.
2. Add the section to `services.$serviceId.settings.tsx` below `InstanceTypeRow`.
3. Add locale keys (`services.customDomainsTitle`, `services.noDomains`, …) in
   `src/features/services/locales/{en,zh}.ts`.

## Files

- `dashboard/src/features/services/components/custom-domains-section.tsx` (new)
- `dashboard/src/routes/services.$serviceId.settings.tsx` (add section)
- `dashboard/src/features/services/locales/{en,zh}.ts` (locale keys)

## Acceptance criteria

- [ ] Settings tab shows "Custom Domains" section with a table when domains exist.
- [ ] Each row: domain name links externally; Verified Status and Certificate Status
      badges show the correct values.
- [ ] Empty state shows "No custom domains configured."
- [ ] Loading state shows skeleton rows, not a blank space.

## Out of scope

- Add/Delete actions (t003, t004). Platform subdomain display (t004).
