From 4b0b774d17506aebe8c9bfd04b8d2e7d1c700946 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 17 Oct 2026 13:56:01 +0000 Subject: [PATCH] docs: add AI-native UI quality spec and plan Document theme.config SSOT, local verify:ui, golden paths, and phase-1 non-goals. Co-authored-by: zuiidea --- .../2026-10-17-ai-native-ui-quality-design.md | 179 ++++++++++++++++++ .../2026-10-17-ai-native-ui-quality-plan.md | 99 ++++++++++ 2 files changed, 278 insertions(+) create mode 100644 docs/specs/2026-10-17-ai-native-ui-quality-design.md create mode 100644 docs/specs/2026-10-17-ai-native-ui-quality-plan.md diff --git a/docs/specs/2026-10-17-ai-native-ui-quality-design.md b/docs/specs/2026-10-17-ai-native-ui-quality-design.md new file mode 100644 index 0000000..c3b3213 --- /dev/null +++ b/docs/specs/2026-10-17-ai-native-ui-quality-design.md @@ -0,0 +1,179 @@ +# Design: AI-native UI quality (theme SSOT + thin verify:ui) + +> Status: approved for phase-1 implementation +> Date: 2026-10-17 +> Companion plan: [2026-10-17-ai-native-ui-quality-plan.md](./2026-10-17-ai-native-ui-quality-plan.md) + +## Decisions (confirmed) + +1. Phase 1 scope: `theme.config` + `verify:ui` + instructions/docs only; no `packages/create` changes; no shared UI package. +2. File name: **`theme.config.ts`** (not `brand.config.ts`); export **`themeConfig`**. +3. **`colorPrimary` is optional** on `themeConfig.token` (reserved; omit to use Ant Design default / existing env override where present). +4. **`verify:ui` is local/Agent only** in phase 1 (not wired into CI or `vp check`). +5. Root **alwaysApply** Cursor rule is OK. + +## 1. Background + +This monorepo ships AI-native admin templates (`apps/basic`, `apps/with-lingui`) plus `init-antd-admin`. Templates already use Ant Design 6, shared shells (`DataTable`, `FilterToolbar`, `FormModal`, CRUD hooks), scoped `.github/instructions`, and `vp check` / Playwright. + +Gaps: no single theme entry; UI/structure rules are soft; no objective ban script; golden paths are not registered; risk of over-building (shared UI packages, LLM judges) that fights simplicity. + +## 2. Goals and non-goals + +### 2.1 Goals (phase 1) + +1. **Theme customization**: change one `theme.config.ts` to affect ConfigProvider seeds (font, radius, light `colorBgLayout`, optional `colorPrimary`). +2. **UI consistency (operational)**: no literal colors in business TSX; prefer Ant Design; same archetype aligns to in-app golden paths. +3. **Maintainable quality**: harden existing instructions + AGENTS validation (YAGNI, Zod boundaries, single intent, bounded self-fix). +4. **Falsifiable bans**: per-app zero-dependency `verify:ui` script (Node builtins only), run locally / by agents. +5. **Simplicity**: no new workspace packages, no new runtime dependencies, no `packages/create` changes. + +### 2.2 Non-goals (phase 1) + +| Forbidden | Why | +|-----------|-----| +| `packages/ui` / `packages/theme-*` / `eslint-plugin-*` | No library extraction | +| Changes to `packages/create` | Template copy already carries app files; CLI flags later | +| Wire `verify:ui` into CI / `vp check` | Local + Agent only this phase | +| LLM review / screenshot baselines | Phase 2 | +| Ban all `div` / zero CSS | Conflicts with measure/`ref` and Aurora | +| Large CSS→TSX rewrites | Document allowlist only | +| Product behavior changes | Theme move must be behavior-equivalent | +| Rewriting `users` as a demo | Register paths only | + +## 3. Architecture + +```mermaid +flowchart TB + themeCfg["src/theme/theme.config.ts"] + tb["hooks/tokenBuilders.ts"] + uat["hooks/useAppTheme.ts"] + cp["ConfigProvider"] + themeCfg --> tb --> uat --> cp + gold["Golden paths in instructions"] + gate["scripts/verify-ui.mjs"] + gold --> agent[Agent/human] + agent --> pages[routes/components] + pages --> gate + tb -.->|allowlist| gate + themeCfg -.->|allowlist| gate +``` + +Golden pages stay **in-app paths**, never a library. Shared shells stay under each template `src/`. + +## 4. Theme contract + +### 4.1 Files + +- `apps/basic/src/theme/theme.config.ts` +- `apps/with-lingui/src/theme/theme.config.ts` (same seeds; keep existing `VITE_BRAND_PRIMARY` helper for behavior parity) + +### 4.2 Export shape + +```ts +import type { ThemeConfig } from "antd"; + +type ThemeTokenSeeds = { + fontFamily: string; + borderRadius: number; + borderRadiusSM: number; + borderRadiusLG: number; + /** Light layout background only; dark uses algorithm default */ + colorBgLayoutLight: string; + /** Optional brand primary; omit to use Ant Design default */ + colorPrimary?: string; +}; + +/** Project theme seeds. Only place for intentional brand/theme literals. */ +export const themeConfig = { + token: { + fontFamily: + "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif", + borderRadius: 8, + borderRadiusSM: 6, + borderRadiusLG: 12, + colorBgLayoutLight: "#ffffff", + // colorPrimary: "#1677ff", + } satisfies ThemeTokenSeeds, + controlComponents: { + Button: { + primaryShadow: "none", + defaultShadow: "none", + dangerShadow: "none", + }, + Input: { + activeShadow: "none", + }, + } satisfies NonNullable, +} as const; +``` + +### 4.3 `tokenBuilders.ts` + +- Remove local `SHARED_DESIGN_TOKENS` / `CONTROL_COMPONENTS`; import from `@/theme/theme.config`. +- Keep `MENU_LIGHT` / `MENU_DARK` / `buildTableTokens` in `tokenBuilders.ts`. +- Light seed uses `colorBgLayout: themeConfig.token.colorBgLayoutLight` plus font/radius. +- When `themeConfig.token.colorPrimary` is set, apply as `colorPrimary` / `colorLink` / `colorInfo`. +- `with-lingui`: preserve `VITE_BRAND_PRIMARY` override (env wins over optional static `colorPrimary`). +- Dark seed uses font/radius only (plus primary wiring when present). +- `useAppTheme.ts` export API unchanged. + +## 5. Golden paths (documentation only) + +| Archetype | Path | +|-----------|------| +| ListCRUD | `src/routes/_auth/users/` (`-Toolbar.tsx`, `-FormModal.tsx`) | +| Auth | `src/routes/login/` | +| Dashboard | `src/routes/_auth/dashboard/` | +| Shell | `src/components/Layout/` | +| Error | `src/components/NotFound/`, `src/components/RouteError.tsx` | + +Agent protocol: classify archetype → open golden path → copy structure/data flow → replace domain only → run Validation → fix same violations at most twice. + +## 6. `verify:ui` contract + +- Files: `apps/*/scripts/verify-ui.mjs` (duplicated; no shared package). +- Script: `"verify:ui": "node ./scripts/verify-ui.mjs"`. +- Scan: `src/`. +- Phase 1: **local / Agent only** (document in instructions; do not add CI job). + +**Errors (exit 1):** + +- **R1 `no-literal-color`**: `src/**/*.{ts,tsx}` except `src/theme/**` and `**/tokenBuilders.ts`; ban `#hex`, `rgb(`, `rgba(`, `hsl(`, `hsla(`. +- **R2 `no-parallel-ui`**: ban imports from `@mui/`, `@chakra-ui/`, `@mantine/`, `react-bootstrap`, `@headlessui/`, `vuetify`. +- **R3 `css-allowlist`**: every `src/**/*.css` must be one of: + +``` +src/index.css +src/components/Aurora/index.css +src/components/DataTable/index.css +src/components/Layout/Sidebar/index.css +src/components/Layout/UserMenu/index.css +src/routes/login/index.css +src/routes/_auth/dashboard/index.css +``` + +**Warn (exit 0):** W1 `prefer-flex-layout` for inline `display: 'flex'|'grid'`. + +Constraints: Node `fs`/`path` only; do not wire into `vp check` or CI in phase 1; document Agent order: check then `verify:ui`. + +## 7. Instructions and Cursor rule + +Update both apps’ `frontend` / `refactor` / `README` instructions and `AGENTS.md` Review Checklist. Add root `.cursor/rules/ai-native-ui-quality.mdc` (`alwaysApply: true`). Do not change `packages/create/**` or `apps/docs/**`. + +## 8. Success criteria + +- Spec + plan under `docs/specs/` +- Both apps have `theme.config.ts`; `tokenBuilders` reads seeds from it +- Both apps `pnpm verify:ui` exit 0 +- Both apps `pnpm check` (or `vp check --no-fmt`) pass +- Frontend instructions include golden paths + `verify:ui` +- No new workspace package; no new runtime dependencies; no `packages/create` diff + +## 9. Risks + +| Risk | Mitigation | +|------|------------| +| Theme extract breaks visuals | Move constants only; keep algorithms | +| verify false positives | Exclude `theme/` + `tokenBuilders`; warns non-fatal | +| Dual-app drift | Finish basic, then mirror lingui | diff --git a/docs/specs/2026-10-17-ai-native-ui-quality-plan.md b/docs/specs/2026-10-17-ai-native-ui-quality-plan.md new file mode 100644 index 0000000..be4fac1 --- /dev/null +++ b/docs/specs/2026-10-17-ai-native-ui-quality-plan.md @@ -0,0 +1,99 @@ +# Plan: AI-native UI quality (phase 1) + +> Companion design: [2026-10-17-ai-native-ui-quality-design.md](./2026-10-17-ai-native-ui-quality-design.md) + +Confirmed naming: **`theme.config.ts` / `themeConfig`**. Optional `colorPrimary`. `verify:ui` local-only. alwaysApply Cursor rule. + +Implement in Task order. + +## Task 0 — Land Spec/Plan + +**Files:** + +- Create: `docs/specs/2026-10-17-ai-native-ui-quality-design.md` +- Create: `docs/specs/2026-10-17-ai-native-ui-quality-plan.md` + +**Done when:** both files exist (with `theme.config` naming). + +## Task 1 — `apps/basic` theme SSOT + +**Files:** + +- Create: `apps/basic/src/theme/theme.config.ts` +- Modify: `apps/basic/src/hooks/tokenBuilders.ts` + +**Steps:** + +1. Create `theme.config.ts` with seeds + optional `colorPrimary` type slot. +2. Import `themeConfig` in `tokenBuilders`; delete local duplicates. +3. Run `pnpm check` in `apps/basic`. + +**Done when:** check green; theme seeds live in `theme.config.ts`. + +## Task 2 — `apps/with-lingui` theme mirror + +**Files:** + +- Create: `apps/with-lingui/src/theme/theme.config.ts` +- Modify: `apps/with-lingui/src/hooks/tokenBuilders.ts` + +**Steps:** Mirror basic seeds; preserve `VITE_BRAND_PRIMARY` / `readBrandPrimary` (env wins over optional static `colorPrimary`). + +**Done when:** lingui `pnpm check` green; primary env override still works. + +## Task 3 — verify-ui (`basic`) + +**Files:** + +- Create: `apps/basic/scripts/verify-ui.mjs` +- Modify: `apps/basic/package.json` (`verify:ui` script) + +**Done when:** `pnpm verify:ui` prints OK, exit 0. No CI wiring. + +## Task 4 — verify-ui (`with-lingui`) + +**Files:** Mirror Task 3. + +**Done when:** lingui `pnpm verify:ui` OK. + +## Task 5 — Instructions + Cursor rule + +**Files:** + +- Modify both apps’ `frontend.instructions.md`, `refactor.instructions.md`, `AGENTS.md`, instructions `README.md` +- Optionally tighten `api.instructions.md` Zod line if missing +- Create: `.cursor/rules/ai-native-ui-quality.mdc` (`alwaysApply: true`) + +**frontend.instructions.md required sections:** + +```markdown +## Golden paths +## Ant Design and tokens +## Div and CSS exceptions +## YAGNI +## Validation +``` + +Validation must include check + `pnpm verify:ui` (local/Agent). + +**Done when:** both frontends have golden path table; root Cursor rule exists and is short. + +## Task 6 — Acceptance + +1. Both apps: `pnpm check` && `pnpm verify:ui` +2. `pnpm test:unit` where feasible +3. Diff check: no `packages/create`, no new dependencies, no new `packages/*`, no CI `verify:ui` job + +**Done when:** design success criteria satisfied. + +## Commit strategy + +1. `docs: add AI-native UI quality spec and plan` +2. `feat(basic): extract theme.config SSOT` +3. `feat(with-lingui): mirror theme.config SSOT` +4. `feat: add verify:ui scripts for admin templates` +5. `docs: harden agent UI/quality instructions` + +## Out of scope reminders + +- No `packages/ui`, eslint plugin, create CLI flags, CI verify job, LLM review, or screenshot baselines.