# State rules for enterprise apps

Source: https://tt-tech.io/blog/enterprise-frontend-state-ownership
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. Before you add state, name its kind: server data, UI state, form state, URL state or session state. Store it as that kind.
2. Put anything a link, a bookmark, a support ticket or the back button must restore in the URL: filters, tabs, the selected record. In Angular, bind route and query parameters to inputs with `withComponentInputBinding`, and expect a missing parameter to arrive as `undefined`.
3. Server data belongs to the backend. Never copy it into a component. Read it from the store of its domain.
4. Give each domain its own store (accounts, cards, requests), owned by the team that owns the domain. Never add a single global store for everything.
5. Keep global only what is cross-cutting by nature: the session, the permissions, maybe feature flags. Do not cache roles in a store nobody refreshes.
6. Keep UI state (which panel is open) in the component that owns it.
7. Derive, do not duplicate. If a value can be calculated from state, use `computed` in Angular or calculate it during render in React. Never store it as a second copy.
8. Never use `effect` to propagate state changes. Use `computed` instead.
9. Keep a store's writable state private. Expose read-only signals with `asReadonly()` and derived values, so the store is the only owner.
10. In long regulated forms, keep drafts, mirror the server's validation and track dirty state. The server still validates; the client check is for the person typing.
11. Use Signal Forms in new code built with signals. Keep reactive forms in an existing app that uses them. Do not migrate forms for fashion.
12. Use signals for state (a value now) and RxJS for events over time (keystrokes, websockets, retries). Bridge them with `toSignal`.

## Before you say done

- For every new piece of state in the diff, list its kind and its owner in the pull request.
- Search the diff for `effect(` calls that set other state, and for stored values that could be a `computed` or a calculation during render.
- For every new filter, tab or selection, confirm it lives in the URL, or say why not.
