GET /app/{orgCode}/list/{entity} is the query layer. It picks its engine per request: DynamoDB for structural queries (always available, immediately consistent) and OpenSearch for full-text search, arbitrary field filters, and facets (when search is enabled for the entity).

Common query parameters

http
GET /list/order                      default list
GET /list/order?sortby=name          sort by a structural field
GET /list/order?status=active        filter by a field
GET /list/order?price=100&price_op=gt   range filter
GET /list/order?q=urgent             full-text search (OpenSearch)
GET /list/order?facets=status|category   bucket counts
GET /list/order?pagesize=20&nexttoken=…  cursor pagination
GET /list/order?view=compact         apply a named view

Which engine runs

A query that uses only structural fields (name, created_at, updated_at, created_by, updated_by, parent key, owner field) always runs on DynamoDB. The moment you add ?q=, ?facets=, or a filter on a non-structural field, OpenSearch is used — if it's enabled for the entity.

text
GET /list/order                  -> DDB primary scan
?sortby=name                     -> DDB NameIndex
?created_by=alice                -> DDB (structural)
?{parentKey}=val                 -> DDB ParentIndex
?q=urgent                        -> OpenSearch (full-text)
?status=active                   -> OpenSearch if enabled, else DDB filter
?facets=status                   -> OpenSearch

Search is opt-in per entity

Full-text and facets need OpenSearch enabled. With it off, a non-structural filter falls back to a best-effort DynamoDB filter; ?q= and facets are unavailable. Structural filters and sorting always work without it.

Scoping a list

  • Owner-scoped — if the entity has an owner index, a plain GET /list/{entity} returns only the caller's records.
  • `?all=true` — skip the owner filter and return all of the org's records (needs a broad ACL).
  • `?owner=user456` — filter to a specific owner (needs a broad ACL).
  • Parent-scoped?{parentKey}={value} returns only children of that parent.

ACL applies to both engines

The authorizer checks list{entity} before the handler runs and sets a mandatory workspace scope. Search never widens what a user is allowed to see.

Pagination & counts

Both engines paginate by cursor: pass the nexttoken from the previous response to fetch the next page (?pagesize= up to 500). OpenSearch can also return a true totalcount; DynamoDB returns the page count only.