shoc-frontend-new/docs/FRONTEND_MAINTAINABILITY.md
2026-07-23 18:48:15 -03:00

66 lines
2.7 KiB
Markdown

# Frontend maintainability conventions
## Conditional rendering
Use logical `&&` or the `when` prop on `Text` when JSX has only a rendered state and an empty
state. Use a ternary only when both branches render meaningful alternatives.
```tsx
{
error && <Alert severity="error">{error.message}</Alert>;
}
<Text variant="description" when={Boolean(description)}>
{description}
</Text>;
```
ESLint rejects `condition ? <Element /> : null`. This keeps one-sided conditions visually
distinct from real either-or UI decisions.
## Typography and feedback
Use `Text` from `@/components/ui/text` for headings, paragraphs, descriptions, labels, captions,
code, and asynchronous feedback. It owns:
- semantic HTML for each visual variant;
- the display, body, and monospace font families;
- default, muted, error, success, and warning tones;
- accessible `alert` and `status` live regions for error and feedback text;
- one-sided conditional text through `when`.
ESLint rejects raw paragraph and heading elements. Existing MUI `Typography` usages remain valid,
but new shared UI should prefer `Text` so semantics and design tokens do not drift.
## Forms and mutations
Use the libraries already established in the application:
- React Hook Form owns field registration, touched/dirty state, and client form lifecycle.
- Zod owns form validation and inferred form value types.
- TanStack Query owns server reads and mutations, including pending/error state, cache
invalidation, and retries where safe.
Do not add TanStack Form alongside React Hook Form. It would create two form conventions without
removing any current dependency. Reconsider only as a deliberate repository-wide migration with
benchmarks, a codemod plan, and an approved deprecation path.
File uploads are not ordinary form fields. Keep file selection and client validation in a focused
component, and use a TanStack Query mutation for upload progress, errors, completion refresh, and
retry state. Do not place upload orchestration in a route-sized page component.
## Page state
Pages should compose focused state components instead of accumulating unrelated booleans:
- query loading, error, and empty states stay adjacent to the query result;
- mutation pending/error state belongs to the component that initiated the mutation;
- route pages coordinate sections and navigation;
- reusable sections own their interaction details;
- errors render inline with accessible feedback, with toasts reserved for cross-page outcomes.
## Enforcement and rollout
The lint rules are repository-wide and the initial violations were migrated in the same change.
`npm run lint`, `npm run build`, and the `Text` behavior tests are required gates. Future
maintainability rules must also land with a green migration rather than a warning-only backlog.