These patterns combine flows and routes with the rest of Pawabase. Each is a full design you can copy.

Checkout

Goal: the user presses “Pay”. You must create an order, charge a card with a secret you cannot expose, and tell the user the result. Design:
  1. The browser calls a route: POST /orders/{id}/pay.
  2. The route runs a flow that loads the order from the database (never trusting a price from the browser), charges the card through the provider’s API with a secret, marks the order paid, and returns { status, receiptUrl }.
  3. The browser shows the result.
The key lets the flow recognise a repeat of the same attempt and return the earlier result instead of charging twice. That is what makes idempotent: true safe. Without it, never set that flag on a payment.

Long-running work

Goal: “Export all my data” takes two minutes. A browser request should not wait that long. Design:
  1. The browser calls flows.run("start-export"). The flow creates an exports record with status: "preparing", queues the real work in the background, and returns { exportId } immediately.
  2. The background work builds the file, uploads it to storage, and updates the record to status: "ready" with the file’s key.
  3. The browser watches that record (or a channel) and shows a download button when it is ready.
Keeping the state in a record is the key. If the person reloads the page or loses their connection, the app reads the record and shows the right thing, instead of losing track.

Safe retries

A network drop can leave you not knowing whether a POST arrived. Decide, per feature: The client already retries rate limits and 502/503/504 for you. The flag only matters for repeating a POST after the connection broke.

Cancel a request

Give long calls an AbortSignal so the user can back out, and so a component that unmounts does not leave work behind.

Optimistic UI

For quick actions, change the screen first, call the server, and undo if it fails.

Validate on the server, show on the client

The flow checks the input and answers with ValidationError and a field name. The client shows it next to the right input:
Keep the same rules in the browser for quick feedback, but treat the server’s as the truth.

Act for the user on a server

When your own backend calls Pawabase for someone who is signed in to your app, send their token, so the same access rules apply:
See Node.js.

Testing

  • Unit-test the logic itself where it is written.
  • Integration-test the contract from a script against a development environment: sign in as a test user, call the route, assert the result and the error codes.
  • Test refusals as carefully as successes: call with no sign-in, with the wrong user, with bad input. The access rule is a feature.

Access rules

How a route or flow decides who may call it.

Errors

Every error type.