The backend shares data with the frontend through Pinia stores. It does not hand data to a component which then copies it into state; it tells the frontend which store gets what. This page describes the contract between both sides. The backend half is autoAjax() from crudadmin/autoajax, the frontend half is Response from @crudadmin/helpers.

The response

Every endpoint answers with autoAjax(). Its JSON contains only the keys which were set:
Turn the store key on in every project. Without it, autoAjax() merges the store data into data and nothing reaches the stores:
config/autoajax.php
Hybrid projects serving older apps sometimes switch this per request ('store' => isHybridApp()). New projects set it to true.

How store is bound

useResponse(response) walks the keys of store and every registered Pinia store. A key matches a store by its id (the first argument of defineStore()): A key of a store which is not registered is ignored. Properties which the store does not declare are added to it, so keep the names of both sides the same.
app/store/eventStore.js
Name sections and stores in the singular: event, setting, friend. The bootstrap section event() fills the store event, the store is defined as defineStore('event', ...) and used as useEventStore().

Patterns on the backend

Shared data on boot

Data the whole app needs (settings, code lists, the logged user, translations) is a section of the bootstrap request. The frontend fetches it once on start and refreshes it in the background, see App boot and auth.
app/Utilities/Bootstrap/AppRequest.php

Return the changed sections

An action which changes shared data answers with the sections it changed. The frontend gets them in the same shape as on boot:
app/Http/Controllers/Auth/ProfileController.php
AppRequest::only([...]) takes any sections, with their caches and guest rules. Several of them go into one response:

Call a store action

When the frontend holds a list and only one row changed, call an action of the store instead of sending the whole section again:
app/Http/Controllers/EventController.php

Data of one component

Data used by one page only (a paginated list, a search result) goes into data and is returned to the caller:
data and store can be combined: the page gets its rows from data, while the shared counters update through store.

Login and registration

The auth controllers of crudadmin/helpers answer with an AuthResponse (driver, user, token) in data by default. Set the response to bootstrap and they answer with the authenticated sections of the bootstrap request instead, so the token, the user and all data of the logged user arrive in one response:
config/admin_helpers.php
The frontend understands both forms, see useAuth().

Patterns on the frontend

Every request goes through useAxios() and every response, including errors, through useResponse():
Components then read the stores, not the response:
The details are in Requests and responses and Pinia stores.

Checklist

  • config/autoajax.php has 'store' => true.
  • Every section of the bootstrap has a store with the same id, registered with Response.addStores().
  • Names are singular on both sides.
  • Actions changing shared data return the changed sections or call a store action.
  • Components call useResponse() on every response and error.