# MailHub UI Visual Redesign Design

## Goal

全面升级 MailHub 管理台与登录/注册页的视觉系统，使其从「默认 Ant Design 后台模板」提升为辨识度高的 Modern SaaS 控制台，同时**不改动后端 API、权限模型、业务状态机与核心信息架构**。

## Confirmed Product Decisions

| Decision | Choice |
|----------|--------|
| Scope | Full visual system redesign (theme + layout shell + component patterns + key pages) |
| Auth pages | Included; same visual language as admin console |
| Visual style | Modern SaaS — light canvas, indigo primary, airy product feel (Resend / Railway-like) |
| Shell | Dark left sidebar (full text labels) + light top bar + content canvas |
| Density | Comfortable — larger type, generous whitespace, breathable cards |
| Implementation approach | Design system + shell upgrade on existing React + Ant Design v5 |
| Dark mode | Out of scope for this redesign |

## Non-Goals

- New features, new routes, or new API endpoints
- Replacing Ant Design / React / Vite stack
- Full custom component library rebuild
- Dark mode theme
- Changing domain DNS workflow semantics, token lifecycle, or admin permissions
- Rewriting analytics models or i18n message semantics (minor chrome strings only)

## Architecture

Continue the current React admin app (`src/frontend/`, `src/layouts/`, `src/pages/`, `src/components/`) built by Vite into `public/`. Visual upgrades land as:

1. **Design tokens** — CSS custom properties + Ant Design `ConfigProvider` theme tokens
2. **Shell redesign** — `AdminLayout` and auth shell (`AuthApp`)
3. **Shared presentation components** — PageHeader, MetricCard, SectionCard, StatusPill, EmptyState, CodeBlock
4. **Page restyles** — recompose existing page markup around the new patterns without changing data loading or handlers

Business logic remains in existing model modules (`*-model.js`), `api.ts`, and page containers.

Admin and auth are **separate Vite entry points** (`src/frontend/main.tsx` → `App.tsx`, `src/frontend/auth/main.tsx` → `AuthApp`). Each mounts its own `ConfigProvider`. Extract a **shared theme/token module** (e.g. `src/frontend/theme.ts` + CSS variables in `styles.css`) and apply it in both entry trees so brand stays consistent without implying a single React tree.

```text
theme.ts + styles.css (shared tokens)
  ├── Auth entry: ConfigProvider → I18nProvider → AuthApp
  └── Admin entry: ConfigProvider → I18nProvider → App
        └── AdminLayout (sider + header + content)
              └── pages (Dashboard, Domains, …)
                    └── shared presentation components
```

## Visual System (Tokens)

### Color

| Role | Value | Usage |
|------|-------|-------|
| Primary | `#4F46E5` | Primary buttons, links, active nav accent |
| Primary hover | `#4338CA` | Hover / pressed primary |
| Primary soft | `#EEF2FF` | Soft fills, selected chips |
| Ink / Sider | `#0F172A` | Sidebar background, primary text |
| Text secondary | `#64748B` | Labels, helper text |
| Text muted | `#94A3B8` | Meta / placeholders |
| Canvas | `#F4F6FB` | App background |
| Surface | `#FFFFFF` | Cards, header, auth form card |
| Border | `#E2E8F0` | Dividers, card borders |
| Success | `#16A34A` (+ soft green bg) | Healthy / accepted |
| Warning | `#D97706` (+ soft amber bg) | Pending / DNS issues |
| Danger | `#DC2626` (+ soft red bg) | Failed / destructive |

### Shape, Type, Space

- **Radius:** controls `10px`, cards `14px`, pills `999px`
- **Shadow:** light elevation — thin border + soft ambient (`0 1px 2px` + `0 8px 24px` slate-tinted)
- **Spacing rhythm:** 8-based (`8 / 16 / 24 / 32`); content padding `24–32px`
- **Type scale:** page title `22–24px`, metric value `28–32px`, body `14px`
- **Font stack:** Inter preferred, with system-ui / -apple-system / Segoe UI fallbacks
- **Inter loading:** prefer **system stack only** or **self-hosted** font files if Inter is added later; avoid third-party CDN font loads for self-hosted deploy reliability. Default implementation may use system-ui stack without shipping Inter files.

### Ant Design Theme Mapping

Map tokens into `ConfigProvider` at least for:

- `colorPrimary`, `colorSuccess`, `colorWarning`, `colorError`
- `colorBgLayout`, `colorBgContainer`, `colorBorderSecondary`, `colorText`, `colorTextSecondary`
- `borderRadius`, `borderRadiusLG`
- Component overrides for `Card`, `Table` (comfortable cell padding), `Button`, `Menu` (sider), `Tag` or custom StatusPill preference

Default Ant blue `#1677ff` must not remain as brand primary.

## Shell Design

### AdminLayout

- Sticky dark sider width **248px**, background ink `#0F172A`
- Brand block: gradient MH mark + title `MailHub` + subtitle `Email Delivery`
- Navigation **groups** (labels only; routes unchanged):
  - **Overview** — Dashboard, Domains, DNS API
  - **Delivery** — SMTP, API Tokens, Sending Logs, Webhooks
  - **System** — Admin (admin role only), Settings
- Active item: primary-soft indigo wash + light text (custom sider styles; avoid stock dark-menu look)
- Header: white surface, border bottom, page title / breadcrumb, language select, refresh, primary CTA **Add domain**, user dropdown
- Content: canvas background, comfortable padding
- Responsive: below `lg`, collapse sider to drawer-style behavior (existing Ant Layout breakpoint pattern)
- Optional light account summary at sider bottom is allowed; primary account actions stay in header dropdown

### Auth (Login / Register / Forgot / Reset / Resend)

- Same tokens as admin
- Desktop split:
  - **Left:** ink brand panel — logo, headline, short value prop, 2–3 capability signals
  - **Right:** soft canvas/indigo wash + elevated white form card
- Mobile: single column; brand panel compressed on top
- Keep existing auth modes and API calls; restyle forms, alerts, segmented control, and spacing only

## Shared Presentation Components

| Component | Responsibility |
|-----------|----------------|
| `PageHeader` | Title, optional subtitle/description, right-side actions (one primary action per region) |
| `MetricCard` | Label, large value, optional trend pill / soft icon tile |
| `SectionCard` | Standard content card (14px radius, light shadow, consistent header/body padding) |
| `StatusPill` | Semantic soft status chip (success / warning / error / info / neutral) |
| `EmptyState` | Icon, message, optional primary CTA for empty lists/charts |
| `CodeBlock` | Mono, wrap-safe long values (DNS/token samples) with copy affordance |

Prefer placing these under `src/components/common/` (or equivalent) and reusing across pages. Existing `StatusTag` may be adapted into or replaced by `StatusPill` for visual consistency.

## Key Page Treatments

### Dashboard

- Keep security alert (default admin password) at top when applicable
- Condense the metric strip to **exactly four primary MetricCards**:
  1. **今日发送** (today sent)
  2. **成功率** (success rate)
  3. **已验证域名** (verified domains)
  4. **DNS 问题** (DNS issues count)
- Place remaining current summary fields as secondary, not equal-weight cards:
  - **Bounce rate / complaint rate** — show as captions or mini stats under success-rate card, or in status distribution context
  - **Last sent at** — meta line under recent-sends SectionCard header or toolbar
  - **SMTP status** — compact readiness chip in PageHeader extra area or a small readiness row above charts
- Chart row: trend + status distribution in SectionCards; recolor plots to token palette
- **Retain existing secondary panels** (domain ranking, hourly heatmap, domain health list / recent failures if present) — restyle with SectionCard chrome; do not drop them from the layout inventory
- Recent sends table inside SectionCard
- No analytics model API changes

### Domains list

- PageHeader + toolbar (search, status filter, add domain)
- Table inside SectionCard; domain name as emphasized link control
- Status via StatusPill; comfortable row padding

### Domain detail

- Upgrade `DomainHealthCard` to a **hero block**: domain title, status pill, key stats, DNS progress, primary action stack (apply DNS / check / test / edit)
- Tabs and two-column DNS records layout remain
- DNS record cards use CodeBlock + StatusPill + consistent action buttons
- No change to DNS apply/check/test flows

### Other pages (SMTP, Tokens, Logs, DNS API, Settings, Admin, Webhooks placeholder)

- Apply PageHeader + SectionCard + table/form spacing polish
- Do not redesign information architecture or form field sets beyond visual hierarchy
- Token create modal / secret-once warning keeps existing behavior with improved visual emphasis

## Engineering Boundaries

### In scope files (expected)

- `src/frontend/App.tsx` — theme provider tokens
- `src/frontend/styles.css` — CSS variables + shell/page styles
- `src/frontend/auth/AuthApp.tsx` (+ auth-related styles)
- `src/layouts/AdminLayout.tsx`
- `src/components/common/*` (new or updated shared UI)
- `src/components/domain/*` (visual structure only)
- `src/pages/**` (composition / classNames / shared components; handlers stay)

### Out of scope

- `src/server.js`, `src/db.js`, mailer/submission/DNS provider logic
- Model pure functions unless a pure presentation helper is needed
- Docker / deploy scripts

### i18n

- Reuse existing keys for page meaning
- May add short chrome keys (nav group labels, empty-state titles) in both locales already supported by the app

### Testing & verification

- Existing `npm test` suite must remain green (models, i18n, server APIs unchanged)
- Add tests only if new pure helpers are introduced
- Manual / build verification: `npm run build` (and UI smoke of login + dashboard + domain detail)

## Delivery Order

1. Design tokens (CSS vars + ConfigProvider)
2. AdminLayout shell + nav groups
3. Auth shell restyle
4. Shared presentation components
5. Dashboard
6. Domains list + domain detail / health / DNS cards
7. Remaining pages sweep
8. Build + test gate

## Success Criteria

- Brand primary is indigo-based, not default Ant blue
- Admin and auth feel like one product
- Layout remains dark sidebar + comfortable density as approved
- All existing navigation destinations and primary workflows remain reachable
- No intentional API or auth behavior regressions
- `npm test` and `npm run build` pass

## Open Questions

None blocking. Optional later (explicitly out of this spec): dark mode, illustration pack, custom icon set beyond `@ant-design/icons`.
