Skip to content

Front End State

Use this page when a frontend change is mostly about state ownership, serialization, persistence, query controls, saved views, workflow draft state, or media draft boundaries.

Use Front End Components when the main question is reusable UI behavior, layout composition, page/domain wrappers, workflow hooks, labels, or component testing posture.

Use the narrowest state layer that matches the behavior.

State LayerUse For
Component-local stateOpen/closed state, focused item, draft input text, drag hover, local UI affordances.
Page frame stateCurrent view mode, selected filters before apply, active search query, active table/gallery view.
API/query cache stateServer-backed data, loading, refetching, stale data, mutation status.
URL stateReloadable and shareable browsing state such as page, limit, filters, sorts, search, view mode.
Saved-view stateDurable named browsing presets, typed by page key and schema version.
Workflow draft stateMulti-step create/edit state such as selected media files before persistence.
Auth/current-user stateSession-derived user identity, roles, permissions, and permission-aware UI checks.

Do not promote state upward just because a nearby component can see it. Promote state when another layer must coordinate it, persist it, serialize it, or use it for a side effect.

Examples:

  • Popover open state belongs inside the popover or typeahead component unless a page needs to coordinate it with another surface.
  • Search, filters, sorts, pagination, and view mode belong to the collection page because table and gallery views render the same server-backed result set.
  • Current user and permissions belong to the auth query/hooks described in Authentication And Authorization, not to local navbar or button state.
  • Relationship assignment drafts can remain page/workflow state until they need to become persisted association rows; the modeling rules live in Domain Relationships.

Queryable collection pages should derive available controls from endpoint capabilities in @wavemap/api-contracts.

The frontend draft model can be richer than the API model. Draft query state may carry editing-only fields such as selected option keys, condition type, UI IDs, typeahead metadata, or incomplete clauses. The apply boundary should normalize that draft into QueryFilterGroupDTO and QuerySortInstructionDTO shapes before it reaches:

  • API requests.
  • URL serialization.
  • Saved views.
  • Backend route tests.

Current page rules:

  • Search, filter, sort, page, page size, and view mode belong to the page frame, not individual table or gallery views.
  • Reset pagination to page 1 when search, filters, sorts, or page size changes the dataset.
  • Drop unsupported criteria or invalid URL values using endpoint capabilities.
  • Keep stable fallback sorting on the backend so pagination stays deterministic.
  • Keep display-only preferences out of saved views until the page exposes them as first-class controls.

For example, if an endpoint only supports filtering artists by name, genre, and city, the page may still keep a richer draft UI object for editing chips and typeahead selections. The apply boundary should remove incomplete or unsupported criteria before building the DTO sent to the API, URL, or saved-view layer. The deeper contract guidance lives in API Contracts, and the collection/query UX model lives in Query Controls And Browsing State.

URL state is reloadable, shareable, and transient. Saved views are durable named presets above URL state.

Use URL state for:

  • page
  • limit
  • filters
  • sorts
  • Page-owned browsing state such as submitted search and view mode.

Use saved views when a user intentionally names and reuses a browsing setup. Saved views should be typed by page and schema version through @wavemap/api-contracts so future migrations are deliberate.

Guest users can keep saved views in local storage. Authenticated users can persist them through the page query preset API. When both sets exist after login, the import path should copy local presets to the account without deleting the device-local versions.

Example split:

  • A URL like ?page=2&limit=24&search=jazz&view=gallery should be enough to reload or share the current browsing posture.
  • A saved view named “Montreal venues to review” should store a typed preset for later reuse, not just a copied URL string.
  • A stale saved view should be migrated or rejected through its page key and schema version, not silently patched in the rendering component.

Workflow hooks are covered in Front End Components because they are a rendering-boundary tool: they keep page and layout components from owning request choreography. Their output is also a state contract.

Treat workflow state as the coordination layer for multi-step UI intent:

  • Draft state before persistence, such as selected media files, reordered gallery items, or relationship assignments.
  • UI-facing pending, success, partial-success, warning, and failure state.
  • Retry posture and recovery hints after a partial failure.
  • Diff state between persisted backend rows and the user’s current browser-side draft.
  • Side-effect readiness, such as when a form can submit or when the next workflow command is allowed.

Keep workflow state local to the page or workflow hook until it must cross a durable boundary. When it crosses a boundary, make the boundary explicit: API request DTO, URL serialization, saved-view schema, persisted row, or generated artifact.

Media is the clearest example of why frontend draft state must stay separate from persisted contracts.

The front end may hold:

  • Browser File objects.
  • Object URLs or local previews.
  • Upload ordering and profile/gallery intent before persistence.
  • Persisted media already loaded from the backend.
  • Pending removals, reorders, and alt-text edits.

The backend owns persisted media records, canonical locator fields, ingest, thumbnails, blur previews, and render-ready URLs. Frontend code should not treat temporary browser draft state as the same thing as artist_media records or media DTOs.

Generic upload components should keep UI behavior reusable. Artist-specific wrappers and workflows should decide how draft items become artist-media uploads, sync requests, warnings, or recovery hints.

Treat object URLs, drag order, selected files, and unsaved alt text as browser draft state. Treat storageLocation, thumbnailStorageLocation, public render URLs, lifecycle status, and metadata as backend-owned persisted state. The durable storage, ingest, delivery, and deployed-dev boundaries live in Media Storage And Delivery.