frontend-ui-engineering
Build production-quality React UIs in AS v2 (React 19 + Antd v5 + Tailwind). Use when creating components, implementing pages, managing client state, or modifying any user-facing interface.
- License 许可
- Apache-2.0
- 最近更新
- 2026-11-12
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- frontend-ui-engineering
- description
- Build production-quality React UIs in AS v2 (React 19 + Antd v5 + Tailwind). Use when creating components, implementing pages, managing client state, or modifying any user-facing interface.
02 资源文件 4
- 参考文档reference/a11y.md1.1 KB
- 参考文档reference/domain-patterns.md2.3 KB
- 参考文档reference/forms.md2.0 KB
- 参考文档reference/tables.md1.3 KB
03 SKILL.md 正文
Frontend UI Engineering — Aprender Sistema
Overview
Stack: React 19 + Ant Design v5 + Tailwind CSS + Vite 7 (migrado do React 18 no #1675;
antd usa o shim @ant-design/v5-patch-for-react-19, importado no main.tsx). Goal: UI that
matches AS v2's existing design language, not AI-generated-looking output.
Layout under v2/frontend/src/: pages/ (41, lazy-loaded in AppRoutes.tsx), components/ (22 reusable + access/,
google/, lgpd/), hooks/ (13 custom), api/ (one client per domain).
The one rule: Antd first
Use Antd components for everything that has one; Tailwind for spacing/layout only.
// Good: Antd component, Tailwind for layout
<Card className="mb-4">
<Space direction="vertical" className="w-full">
<Typography.Title level={4}>Solicitação</Typography.Title>
</Space>
</Card>
// Avoid: custom div when Antd has a component
<div className="border rounded p-4 bg-white shadow"> // use <Card>
Reference (read the file for the task at hand)
-
UX principles (owner's rule, read first):
v2/docs/specs/frontend/ux-principios.spec.md— clarity, flow, a11y as baseline, feedback; no paternalism/dark patterns/useless polish; hard limits (WCAG AA, CWV); PR checklist. Screen pattern:pages.spec.md→ "Padrão responsivo". -
Forms, data fetching (
fetchAPI), polling, state management →reference/forms.md -
Tables (
useTableFilters), empty/loading/error states →reference/tables.md -
Accessibility (WCAG), keyboard, ARIA, responsive →
reference/a11y.md -
Timezone, wizard, approval flow, conflict codes →
reference/domain-patterns.md
Anti-Patterns to Avoid
| Anti-Pattern | Why Bad | Correct Approach |
|---|---|---|
fetch() direct / raw axios |
No CSRF/credentials; axios removed (ADR-013) | fetchAPI from api/config.ts |
Custom CSS / inline style={{padding:15}} |
Off Antd/Tailwind scale | Antd Space + Tailwind p-4/gap-* |
| Manually rendered toasts | Antd has it | message.error('Erro ao salvar') |
| Naive date display | UTC ≠ Fortaleza (CP-03) | .tz('America/Fortaleza') |
| Redux/Zustand/React Query | Project uses Context + fetchAPI + polling |
see reference/forms.md |
React.memo everywhere |
Premature optimization | Only on profiled bottlenecks |
Vite manualChunks |
Breaks dep ordering, crashed prod | Never (feedback_no_manual_chunks.md) |
lowercase fetchpriority |
React 19: Invalid DOM property (só o checklist console-errors pega) |
camelCase fetchPriority |
useRef() sem argumento |
React 19 exige valor inicial | useRef<T>(null) |
import ... from 'react-router-dom' |
v8 removeu o pacote -dom (#1675) |
from 'react-router' |
| Proportional digits in numbers that change or get compared (counters, totals, table columns) | Digits have different widths: values jitter as they update and columns don't line up. Antd v5 doesn't set tabular-nums (v4 did) |
Tailwind tabular-nums on the counter or cell (column className: 'tabular-nums') |
| Pointer target smaller than 40×40px | Missed taps on tablets in the field; antd's default Button is 32px, size="small" 24px |
New or touched controls: size="large" (40px) where it fits; in a dense table, enlarge the hit area with a pseudo-element that stops short of the neighbours (after:absolute after:-inset-1 takes a 32px button to 40px; antd's Button is already position: relative) |
Swapping content for a spinner (if (loading) return <Spin />) |
The page collapses to a spinner and jumps back when data arrives (layout shift) | Keep the component mounted (<Table loading>, <Card loading>, <Spin spinning>) or reserve the final size (Skeleton of the same shape) |
Measure, don't eyeball
A claim about the rendered page ("the target is big enough", "the digits line up", "nothing
jumps when the data arrives") is a number read from the browser, not an impression from a
screenshot. Read it with the Playwright already in v2/frontend (playwright.config.ts,
specs in e2e/; authenticated pages run in the chromium project):
import { test, expect } from '@playwright/test';
test('alvo e dígitos medidos', async ({ page }) => {
await page.goto('/solicitacoes/minhas');
// The control you added or touched: visible box >= 40x40px
const alvo = page.getByRole('button', { name: 'Nova Solicitação' });
const { width, height } = await alvo.evaluate((el) => el.getBoundingClientRect());
expect(Math.min(width, height)).toBeGreaterThanOrEqual(40);
// A numeric column you added: tabular digits are what the browser actually computed
const numero = page.getByRole('cell').filter({ hasText: /^\d[\d.,]*$/ }).first();
expect(await numero.evaluate((el) => getComputedStyle(el).fontVariantNumeric))
.toContain('tabular-nums');
});
- A hit area enlarged by a pseudo-element doesn't show up in
getBoundingClientRect, which measures the element's own box. Probe a point outside the visible box but inside the intended 40px withdocument.elementFromPoint(x, y);el.contains(hit)must be true. - Layout shift is the sum of the
layout-shiftentries withouthadRecentInput, the same sumgetPerformanceMetrics()does ine2e/checklist/performance.spec.ts. Read the entries with a bufferedPerformanceObserver:performance.getEntriesByType('layout-shift'), which that helper calls, returns no entries in Chromium, so it always reads 0. The callback never fires when nothing shifted, hence the timeout:
const cls = await page.evaluate(() => new Promise<number>((resolve) => {
type Shift = PerformanceEntry & { value: number; hadRecentInput: boolean };
new PerformanceObserver((list) => resolve((list.getEntries() as Shift[])
.reduce((sum, e) => (e.hadRecentInput ? sum : sum + e.value), 0)))
.observe({ type: 'layout-shift', buffered: true });
setTimeout(() => resolve(0), 1000);
}));
expect(cls).toBeLessThan(0.1);
Verification Checklist
Before merging a UI change:
- [ ] Antd components used before custom ones
- [ ] Uses
fetchAPI(not raw fetch or axios) - [ ] Dates rendered in America/Fortaleza timezone (CP-03)
- [ ] Empty / loading / error states — no blank screens, no layout shift: final size reserved
- [ ] Pointer targets ≥ 40×40px on new or touched controls — measured, not eyeballed
- [ ] Numeric columns and counters use
tabular-nums - [ ] Keyboard navigable (Tab through page); icon-only buttons have
aria-label - [ ] Responsive at 375 / 768 / 1024 / 1920px
- [ ] No console errors/warnings
- [ ] Lighthouse Performance ≥ 70 (Lighthouse CI gate,
v2/frontend/lighthouserc.cjs); bundle size not significantly increased - [ ] E2E checklist passes (
cd v2/frontend && npm run test:checklist)
References
- CP-03 (timezone Fortaleza), CP-06 (conventional commits)
- ADR-013: axios pinning → fetch migration (
docs/architecture/project-decisions/) v2/frontend/src/api/config.ts—fetchAPI,buildUrl,fetchBlobv2/frontend/src/hooks/useTableFilters.ts- Tabular numbers, 40px hit area and no-layout-shift rules adapted from wellwelwel/skills@1c4eb58 (MIT), itself adapted from jakubkrehel/make-interfaces-feel-better@3845620 (MIT) by Jakub Krehel.
04 同仓库更多 Skills
writing-standards
Apply AS v2 technical-writing standards (clarity, brevity, active voice, Python/Django conventions). Use when writing a README, a docstring (PEP 257), a commit message, a PR description, an error message, or any technical doc.
verification-gate
Verify before claiming success. Use when about to say something works/is done, after implementing a feature, after a bugfix, or before pushing — run the proof command and confirm output first.
test-driven-development
Write the failing test before the implementation in AS v2 (pytest + Django/DRF). Use when implementing a feature or fixing a bug, before any production code is written.
subagent-development
Orquestra subagents no AS v2 — decompõe a tarefa em domínios independentes, paraleliza e revisa em 2 estágios. Use ao delegar exploração, implementação ou validação cross-arquivo para acelerar o trabalho e poupar o contexto principal.
security-scan
Automated security scanning for AS v2. Use before commits or when reviewing changes for vulnerabilities. Runs dependency audit (pip-audit, npm audit), secret detection (grep patterns), and code pattern scanning (SQL injection, XSS, eval, pickle, hardcoded secrets). Integrates with project hooks system.
resume-handoff
Resume work from a saved handoff document, validating its state against the current codebase before continuing. Use when resuming work from a saved handoff after a context clear or in a new session (path, session name, or GitHub issue).