Recipes
Step-by-step changes. Run commands from the repo root of grandstack-web-aura. Each recipe ends with how to check it.
Where to run this. Commands on this page run inside a clone of this repository:
git clone https://github.com/grand-stack/grandstack-web-aura, thencd grandstack-web-aura(Node 22 or later; runnpm cionce). Commands that need the running stack usepodman composeordocker composewith the compose files in this repo. Never point a recipe at a real Aura account unless it says so.
Start the stack for development
Clone grandstack, grandstack-server, grandstack-federation and this repository side by side (the first three on their aura-model branch until MODEL and READ_ONLY are merged), then from the grandstack folder:
(cd ../grandstack-web-aura && scripts/init-env.sh) # once: SECRET_KEY into grandstack/.env
docker compose -f compose.yaml -f compose.aura.yaml -f compose.aura-mock.yaml up --build # the fake Aura, for development
This talks to your real Aura account. For development and tests start the fake Aura instead, by adding -f compose.aura-mock.yaml (connect with mock-client and mock-secret; it publishes mock-aura on 4020). The app is at http://localhost:3000. The overlay publishes the gateway (4000), the read-only server (4001), the Aura subgraph (4010) and Neo4j (7474, 7687), on this machine only. down -v deletes the Aura data and the sealed secrets; it does not touch the Movies setup’s data.
Show a new field Aura returns
Example: Aura adds example_field to the instance details, and you want it on the instance page.
- Put the field in
docs/aura_api_spec_v1-2.yamland runnpm run generate:api. Compare a real response too: real Aura has differed from its spec (graph_nodesis a number, not a string), and mock-aura follows the spec so it cannot catch that. - In
aura/src/sync.ts, add it toinstanceProperties. Store text fields withString(value)if the type is uncertain. - In
models/aura/schema.graphql, addexampleField: StringtoInstance, with a description. The servers read the model at start, so restart them (docker compose ... up -d --force-recreate server store-writer). - With the stack up, run
npm run compose:supergraph, then commitgateway/supergraph.graphql, and recreate the gateway so it picks the file up. - In
web/src/graphql/documents.ts, addexampleFieldtoDetailQuery, runnpm run codegen -w web, and render it inweb/src/pages/Detail.tsx. - Add a case to
aura/test/sync-shapes.test.tsfor each shape you have seen (number, string, missing). - Check:
npm run typecheck && npm test, then look at the instance page.
Make another field editable
Example: let example_setting be changed with Aura’s PATCH. A change touches every layer, and the compiler lists most of them.
aura/src/operations/diff.ts: add it toSnapshotandChanges, todescribe(the plain-words diff row, and any warning), toshowsChangesand tosameSnapshot(so a plan goes stale when it changes).aura/src/operations/plan.ts: validate and normalise it innormaliseChanges, and keep it only if it differs from now.aura/src/operations/store.ts: select it inloadInstanceand copy it insnapshotOf.aura/src/operations/run.ts: send it intoAuraBody, and add it toexpectation’smatches. Done means Aura shows the value, not only that the instance is running again.aura/src/schema.ts: add it toInstanceChange, with a description.- Web:
web/src/lib/changes.ts(EditOriginal,EditForm,buildChange), then the control inweb/src/pages/Edit.tsxand the field inEditQuery. - Tests: cases in
aura/test/operations.test.ts(plan, normalise, stale),aura/test/integration/operations.test.ts(an edit that changes it, end to end against mock-aura), andweb/src/lib/changes.test.ts. Extend mock-aura’s PATCH inmock-aura/src/server.tsif it does not know the field, and keep its contract test passing. - Recompose the supergraph and run codegen as in the previous recipe.
Add a kind of change
Example: a new operation such as a snapshot. Follow how Pause was added.
models/aura/schema.graphql: add the value toOperationKind(if it is not there) and recompose the supergraph.aura/src/operations/state.ts: add it toOperationKind(orPlannableKindif it targets an existing instance).aura/src/operations/diff.ts: say what the review shows.plan.ts: add the checks it needs (which statuses it is allowed in) inguardKind.aura/src/client.ts: add the request. A change must not be retried after a 5xx or a lost connection. UserequestorrequestWithStatuswith a method other than GET: a 5xx is retried only for GET.aura/src/operations/run.ts: add what it sends and what “done” looks like toexpectation. If “done” is an absence (like a delete’s 404), usegone.aura/src/operations/service.ts: aplan...method, and what recovery does after a restart if it was possibly sent. When in doubt, fail and say so; never send twice.aura/src/schema.ts: aplan...mutation that returns only an id. Update the exact mutation list ingateway/test/supergraph.test.ts.- Web: a button on
Detail.tsxthat plans it, a verb inoperationVerb(web/src/lib/changes.ts) and a label inweb/src/lib/operations.ts. - Tests for each layer, including: nothing is sent before a confirm, confirming twice sends once, and a possibly-sent change is not sent again after a restart.
Add a gallery filter
Example: filter by region.
web/src/lib/filters.ts: add the field toFilters, read it inparseFilters, write it inserializeFilters, count it inactiveCount, and add its clause inbuildWhere(use theomitparameter if its counts should ignore itself). Add it toemptyFilterswith an explicit value, or “Clear all” will not clear it.web/src/FilterPanel.tsx: add the group, andweb/src/pages/Results.tsx: a removable chip.- Add cases to
web/src/lib/filters.test.ts(URL round trip, where clause, counts, clearing). - Check:
npm test -w web, then open/instances?...with the new parameter, and reload to confirm it persists.
Add a page
- Create
web/src/pages/Thing.tsx, with its operation written inweb/src/graphql/documents.ts. - Add a
<Route>inweb/src/App.tsx. - Run
npm run codegen -w web(needs the stack with the dev file) andnpm run typecheck. - Operation names must be unique across the app (codegen fails on duplicates).
- Add the page to the browser run (
web/e2e/run.mjs) so it is checked on a phone-sized screen for sideways scrolling and for control names.
Add a tier or a cloud
aura/src/status.ts(TIER_LABELS) andweb/src/lib/create.ts(TIER_LABELSand its order) for a tier.web/src/lib/format.ts(CLOUDS) andweb/src/lib/poster.ts(GRADIENTS) for a cloud.- Add the value to the tests that list them (
aura/test/status.test.ts,web/src/lib/create.test.ts).
Make the fake Aura misbehave
mock-aura has fault injection for testing failure paths. Set it in a test with w.mock.state.faults = {...}, or over HTTP with POST /__faults (and DELETE /__faults to clear).
| Fault | Effect |
|---|---|
rejectNext: { status, message, reason } | The next change (create, edit, pause, resume, delete) is refused with that error, once, and nothing is done. |
dropNext: true | The next change is done, but the connection is cut before the answer, so the caller cannot tell. |
endAs: "loading failed" | Asynchronous steps end in that status instead of the expected one. |
stall: true | Asynchronous steps never finish. |
GET /__passwords/:id returns the password Aura showed for a created instance, so a test can compare it with what the app shows. reset() clears the faults. Use dropNext to test “never sent twice”.
Change the sign-in password, or serve a phone
EDGE_PASSWORD=your-password scripts/init-env.sh --new-password # or leave it out for a random one (run from this repository)
EDGE_SAN="IP:192.168.0.5,DNS:mylaptop.local" scripts/init-env.sh --new-cert
echo "EDGE_BIND=0.0.0.0" >> ../grandstack/.env
(cd ../grandstack && docker compose -f compose.yaml -f compose.aura.yaml -f compose.aura-edge.yaml up -d --force-recreate edge)
Then open https://192.168.0.5:8443 on the phone and accept the certificate warning. A password you choose is as strong as you make it: the edge only limits guessing to about 20 requests a second per address. Read deploying.md first.
Use a real Aura account
This is the default. Read real-account-checklist.md, then start the stack without the fake-Aura overlay (compose.yaml and compose.aura.yaml). Connect with a client ID and secret from the Aura Console, read first, and create, change or delete only what you can afford to lose. Pass credentials in the browser form or the environment; never write them to a file or a commit. Tear the stack down with down -v afterwards so the sealed secret does not stay in a volume.
Before you commit
npm run typecheck && npm test && npm run docs:check
# with a Neo4j and ../grandstack-server built (see testing.md), for changes to aura/ or models/:
NEO4J_TEST_URI=bolt://localhost:7688 NEO4J_TEST_PASSWORD=... npm test
# with a fresh stack:
npm run e2e -w web
If you changed a subgraph’s schema, recompose the supergraph and commit it. If you changed a GraphQL document, run codegen and commit web/src/graphql/generated/.
Source: grandstack-web-aura/docs/recipes.md (this page is a copy; edit it in the repository)