Web app architecture
Read web-craft first. Load only the references the task needs; kit and framework adapters only for the chosen kit
and framework.
Map
| Topic | Reference |
|---|---|
| Server vs client components, BFF, env and secrets boundary | references/server-client.md |
| API layer, error model, state ownership, forms, optimistic UI, URL state | references/data-forms.md |
| Loading, error and not-found boundaries, retry, offline, skeleton timing | references/states.md |
| i18n: registry, resolution, URL, catalogues, formatting, backend header | references/i18n.md |
| RTL, logical properties, directional icons, portals | references/rtl.md |
| Auth, authorization, XSS, CSRF, cookies, cache isolation, personal data | references/auth-security.md |
| Theme: user preference vs applied theme, system changes, no flash | references/theming.md |
| SEO for public pages | references/seo.md |
| GEO: visibility in AI search and assistants | references/geo.md |
| Next.js App Router adapter | references/fw-next.md |
| React + Vite adapter | references/fw-vite.md |
| shadcn/ui adapter | references/kit-shadcn.md |
| Ant Design adapter | references/kit-antd.md |
| Material UI adapter | references/kit-mui.md |
| Working with a node-craft (or any OpenAPI) backend | references/node-craft-contract.md |
| Official sources and review dates | references/sources.md |
Rules that hold everywhere
- Boundaries by need. A component is a client component because it needs interactivity, browser APIs or client state, not by default. Keep interactive islands small. Never import server-only code, ORM clients or secrets into client code; a public env variable is not a secret.
- One API layer. One fetch client, one typed error model keyed by stable codes and status, one auth behaviour. Features do not build their own fetch and retry. Server data lives in the query/cache layer, global client state in a small store or context, form state in the form tool, local UI state in the component. A mock source is switched on by configuration for development and tests, never by editing features; untrusted responses are parsed at runtime.
- Forms. react-hook-form + Zod unless the project has another tool.
mode: 'onTouched',reValidateMode: 'onChange', focus and scroll to the first error, server field errors throughsetError, values kept after errors, double submit blocked. The server stays the authority on validation. - States have boundaries. Route-level loading and error boundaries plus local Suspense where data streams; one failing widget does not blank the page.
- i18n is architecture. A real engine, a locale registry (BCP 47 tag, direction, catalogue, display name), English fallback unless chosen otherwise, request-scoped locale on the server, the same initial locale on server and client, catalogues loaded per locale and namespace, kit and date locales mapped from the app locale.
- Security is server-side. Authorization in the backend. Sanitize any HTML you render. Cookie sessions need CSRF protection. Personal responses never go into a shared cache; locale- and user-dependent responses vary their cache keys.
- Public pages are findable. Locale-correct metadata rendered on the server, canonical per language, hreflang alternates only for real counterparts, sitemap, structured data that matches the visible content. GEO starts with that: indexable, citable content and an explicit AI crawler policy. No ranking or citation guarantees.
- Kits are adapted, not wrapped. Theme and tokens come from the product's design decisions. Wrap a kit component only for repeated product behaviour or to pin an API. Do not stack a second animation system on a kit's own transitions.
Done
Apply web-craft → done, plus: no client bundle contains a secret or server-only module; two concurrent requests in
different locales or for different users cannot mix data; the first render is in the right language and theme; every
claimed kit/framework combination was actually checked.