Skip to content
Design Engineering
Product Structure

From a click to saved data

Follow an action through the browser, server, and database.

Why this matters

Follow one action from the screen to what lasts. That's the fastest way to see which parts of your product are real and which are only pixels. Take the foreman assigning tomorrow's shift — if you can't say where the save is checked and what survives, you don't know what you built.

What to understand

The browser can explain permissions and skip bad requests. It can never enforce access — that check lives on the server. Every protected read and save needs a server boundary; a crew name from a form field doesn't prove membership. Ask your agent: "where exactly does the server check this, and what happens if I call it directly?"

Watch for

  • Permission checks that exist only in the UI — hidden actions with no server check.
  • Treating "request succeeded" as "everything downstream finished" — saved is not delivered.
  • Showing "Failed — try again" after a timeout that landed after a successful save.
  • Retries that duplicate side effects because no safe-retry contract exists.
  • Stale views after a write, with no freshness story.

Strong default

Agree on the API contract up front: what you send, what comes back, errors, access rules, and side effects. Write down paging and ordering for lists, what happens when two edits clash, and how saves may retry. Use an operation ID, a safe-retry key, or a result lookup where the stakes warrant it.

When this doesn't apply

Not every action needs conflict recovery, operation IDs, and queue progress. A simple saved message suits a low-stakes single-editor setting; "reject the stale edit or take the last save" only needs a designed answer when two foremen can actually rename tomorrow's assignment at the same time.

In practice

For an illustrative "Assign crew" flow:

  1. The browser collects a crew member and site, and flags bad input right away.
  2. The server proves who you are and checks what you're allowed to do for this crew.
  3. The server checks the submitted input again, whatever the browser said.
  4. The database saves the record while enforcing its rules.
  5. The server returns the final result, including its ID.
  6. The screen updates the right list, moves on if it should, and explains what happened.

If a notification or email follows, tell "saved" apart from "delivered." A successful request doesn't prove everything downstream finished.

A save travels through three parts of the productThe browser asks to save. The server checks access and input, then writes to the database. Show “Saved” after the server confirms the result.BrowserServerDatabaseCreate projectCheck accessValidate inputWrite recordStored resultShow “Saved”
The browser asks to save. The server checks access and input, then writes to the database. Show “Saved” after the server confirms the result.
ConceptPlain-language meaningInterface consequence
Database constraintA rule the stored data cannot violate.Duplicate prevention must survive concurrent requests.
TransactionRelated changes commit together or do not commit.A partial operation should not look fully successful.
AuthenticationEstablishing who is making the request.An expired session needs a safe return path.
AuthorizationDeciding whether that actor may perform this operation on this resource.A hidden action still needs a server check.
CacheA reusable copy of data with a freshness policy.Users may see stale results after a write.
IdempotencyRepeating the same logical operation does not repeat its effect.A retry can be safe when the server enforces the contract.
QueueWork that continues outside the current request.Show progress and eventual outcome separately.

If this project uses Drizzle with Postgres, the same flow has concrete homes: the schema declares the rules (a unique assignment per crew per day, foreign keys to crew and site), queries join assignments to crew names in one round trip, and your identity provider's session is what the server checks before any write. Ask your agent: "which table and constraint stops a double-booking, and where does the server check crew membership?"

Treat uncertainty as a state. Decide which drafts survive, for how long, and whether shared phones or sensitive fields change where you keep them.

Verify

Replay the happy path and a direct unauthorized request with safe test data. Check the saved result survives reload, errors keep the right input, and failures leave a trace your team can find.

Use $flow to map the whole action before or after implementation. Continue with data fetching for freshness, forms for input, and observability for support after launch.

Last updated on

On this page