- Initialise app-db with `(rf/reg-event-db ::init-db (fn [_ _] {:users [] :loading? false}))` — all state lives in one top-level map.
- Dispatch events with `(rf/dispatch [::load-users {:page 1}])` — never mutate app-db directly outside event handlers.
- Read state via subscriptions: `(rf/reg-sub ::users (fn [db] (:users db)))` — deref with `@(rf/subscribe [::users])` inside components.
- Use `reg-event-fx` for side effects: return `{:db (assoc db :loading? true) :dispatch [::fetch-users opts]}` from the handler.
- Keep event handlers pure — side effects belong only in `reg-fx` handlers or injected via `inject-cofx`.
- Scope event handlers with the `path` interceptor: `(rf/reg-event-db ::update-name [rf/trim-v (rf/path :user :name)] (fn [name [new-name]] new-name))`.
- Add `re-frame-10x` in dev for time-travel debugging — configure the shadow-cljs dev build to load it automatically.
- Use namespaced keywords for events and subs: `::events/load-users`, `::subs/users` — prevents naming collisions in large apps.