Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Web Control Plane

The web control plane is the deployed, network-facing HTTP service for TRE Browser. It is distinct from the local daemon and from the separate TypeScript frontend that consumes its JSON contract. This Rust workspace owns the service, its protocol DTOs, and the versioned fixtures; it does not contain the frontend product.

Service Boundary

The service exposes a deliberately bounded browser surface:

  • ORCID/OIDC login and a server-side browser session;
  • datastore, study, resource, dictionary, and semantic/provenance discovery metadata, including bounded catalogue search across those discovery families;
  • study access-request submission, requester status and withdrawal, and the custodian queue, rejection, and approval actions;
  • /health, /ready, /diagnostics, /version, and a limited /protocol diagnostic surface.

The browser does not receive a daemon Session, raw database access, dataset rows, datafile bytes, live runtime handles, or lake access. Discovery is metadata-only. An approved request is a governed datastore workflow entry; it is not asset-level access control and does not itself expose protected content.

The local daemon and CLI remain the interfaces for local live-session and automation workflow execution. The C ABI remains the lower-level interface for language bindings. All three faces use the same domain and application boundaries, but they have different callers, authority, and operational scope. Every substantive Web route crosses the authenticated stable-protocol boundary to the Trusted runtime; the Web process does not open PostgreSQL or Lake capabilities.

Identity And Authority

Five identity tiers must not be conflated:

Identity or authorityPurposeDoes not imply
Web service identityDedicated mTLS identity used by Web to invoke its allowlisted stable-protocol operations.Browser visitor identity, a Runtime login, arbitrary Session creation, or user/admin authority.
ORCID-authenticated browser visitorEstablishes a protected server-side browser session and identifies the requester.Authenticated TRE user status, a Runtime client credential, or study access.
Runtime client credentialServer-held credential created by ordinary Runtime login when a visitor enters the custodian path.The Web service identity, a live Datastore Session, or custodianship.
Live SessionDatastore-scoped capability opened under the Runtime credential and retained in matching server-side Web session state.Authority after closure or expiry, or authority for a different user or datastore.
Authenticated TRE userDatastore identity established by the live Session, used for custodianship checks, governance, and audit attribution.Browser metadata or custodial authority without the matching live Session.

The Trusted runtime alone resolves and uses the read-only browser and narrow access-request datastore authorities. The invoking Web service identity is recorded separately from the represented visitor. Custodian approval runs the governed study-access workflow through the matching live Session and remains auditable under the Authenticated TRE user.

Browser Contract

The substantive routes are resource routes, not a browser wrapper around the local daemon protocol. Their representative, synthetic responses are versioned under docs/contracts/web-control-plane/v2. The fixture manifest and stable IDs are the frontend handoff for the separate web-application repository.

The companion web application specification and handoff maps supported browser journeys to these routes, specifies the same-origin session integration, and gives the receiving repository fixture and release expectations without prescribing its frontend stack.

Network responses provide X-Request-Id and X-Protocol-Version for support and protocol correlation. POST /protocol is limited to daemon version and doctor diagnostics; it is not a second grammar for discovery or access requests. Public error responses use the documented stable error shape and do not reveal authorization details.

The authenticated Domain collection route supports server-owned filtering with optional text and text_mode parameters plus repeatable tag labels and tag_id public references. Text matches the browser-safe name, description, or URI using exact, prefix, or contains mode. Text and tags combine as text AND any tag; filtering occurs before deterministic ordering and paging. The response returns normalized active filters, page count, has_more, and cursors bound to the selected Datastore, Domain collection, filters, limit, and protocol version. No client-side partial-page filtering is required.

Catalogue search is a Web v2 discovery capability. It lets an ORCID-authenticated browser visitor submit structured, protocol-owned search queries to one selected ready datastore; it is not a daemon search API, a federated/global catalogue, or an unbounded client-side filter over a downloaded catalogue.

Search familyRouteBrowser-safe result boundary
StudiesPOST /browser/datastores/{datastore_id}/studies/searchStudy Discovery metadata.
DatasetsPOST /browser/datastores/{datastore_id}/datasets/searchDataset Discovery metadata with Study context.
DatafilesPOST /browser/datastores/{datastore_id}/datafiles/searchDatafile Discovery metadata with Study context.
Dictionary variablesPOST /browser/datastores/{datastore_id}/dictionary/variables/searchDictionary Discovery metadata.
Model entitiesPOST /browser/datastores/{datastore_id}/model/entities/searchSemantic Discovery metadata.
Model relationsPOST /browser/datastores/{datastore_id}/model/relations/searchSemantic Discovery metadata.

Each route accepts the corresponding stable protocol search request as JSON. Study search uses query.text and the nested facets.any_tags and facets.any_domains groups; the other families preserve their noun-specific predicates. This keeps text modes, selectors, validation, page bounds, and deterministic ordering protocol-owned. Empty queries or predicate sets are rejected. The existing unfiltered discovery routes remain the way to browse an entire available collection. Where a reused request DTO has a daemon Session field, a client-supplied value is rejected: the browser session and server-held Discovery authority are the only Web identity and authority inputs.

Search is scoped to the path’s selected ready Datastore and uses server-held, read-only Discovery authority. It requires an ORCID-authenticated browser session, but its visibility is the broad TRE Browser Discovery view: Study access grants, TRE OAuth-group membership, custodianship, and access-request state neither broaden nor narrow results. A search result must be eligible for the equivalent browser Discovery projection, so search cannot bypass the ordinary route’s visibility or redaction decisions.

Results, Pagination, And Privacy

Every successful response identifies the selected datastore and search family, returns the normalized active query or predicates, a deterministic ordering identifier and description, the returned-page count, requested limit, has_more, and an optional opaque next_cursor. It does not provide an exact total count. An empty result is a successful 200 with an empty result array, zero returned records, has_more: false, no next cursor, and a neutral server-provided empty state.

Treat a returned cursor as opaque and use it only with the same search family, datastore, normalized query or predicates, page limit, and protocol version. Do not decode, manufacture, modify, silently substitute, or persist it beyond the active pagination journey. A malformed or mismatched cursor is a 400 validation error; the caller must handle that explicitly before restarting pagination.

Results remain metadata-only. Resource versions expose authoritative available or withdrawn lifecycle state. Datafile resource and search records may expose safe creation dates, stored size, format, and compression/encryption booleans. They exclude daemon session state, protected rows or bytes, previews and downloads, dataset row counts, datafile digests, Content-derived summaries, storage paths, credentials, raw SQL, diagnostics, membership lists, and custodian internals. Operational logging retains only correlation and bounded operational data—such as request ID, search family, datastore identity, status, duration, page count, and control outcome—not bodies, predicates, search text, cursors, result identifiers, cookies, ORCID identity, or authority details.

Failure And Resource Boundaries

Search requests are JSON bodies capped at 64 KiB. A request has at most 20 query terms or predicates and each text value is at most 256 characters; the family-specific page bounds remain protocol-owned. The default controls are 300 searches per minute per browser session with burst capacity 30, six concurrent searches, and a ten-second datastore timeout; an operator may tighten these controls without changing protocol limits.

Public situationContract behaviourCaller response
Malformed JSON, an invalid query or predicates, a client session, invalid page, or invalid cursor400 public validation error with safe field issues where usefulCorrect the request; do not retry unchanged.
Request body exceeds 64 KiB413 / browser_search_body_too_largeReduce or correct the request; do not retry unchanged.
No authenticated visitor state401 / browser_session_requiredRe-establish ORCID login, then retry on user action.
No Discovery authority403 / browser_discovery_forbiddenDo not retry automatically or infer access or governance state.
Unknown or ineligible datastoreNeutral 404 / browser_datastore_not_foundRefresh datastore discovery without probing.
Datastore/discovery unavailability or a safe timeoutRetryable 503 search failureRetry on user action or bounded backoff; never expose adapter detail.
Rate or concurrency limit429 with Retry-AfterHonour the delay; do not fan out retries.
Unsupported protocol version400 / unsupported_protocol_versionStop the affected workflow and resolve compatibility.

Search requests may send the protocol version accepted from /version in X-Protocol-Version; omission uses the current supported version. All responses are Cache-Control: no-store and continue to provide X-Request-Id and X-Protocol-Version for safe support correlation.

The Web control-plane v2 contract is the authoritative payload and fixture index. Its companion web-application handoff defines frontend consumption, fixture-driven tests, and retry presentation. The protocol 2.0.0 cutover replaces the prior reference encoding and fixture IDs. The companion must adopt web-control-plane.v2; a v1 image is incompatible. The existing HTTP route structure and authority classes are preserved.

Domain Browsing

Domain browsing is the datastore-scoped discovery journey for moving from a Domain to its associated Studies, canonical Variables, and their Vocabulary metadata. In the Web control-plane v2 contract, every reference returned by a route is a stable, opaque public reference to use in the next route. It is not a daemon Session API and it does not expose Dataset or Datafile content.

All Domain-browser routes start with a selected ready datastore and require an ORCID-authenticated browser visitor. The Trusted runtime resolves that datastore through its Runtime-held discovery authority before reading metadata. An ORCID-authenticated browser visitor does not send a datastore credential, OIDC token, role, or other authority.

JourneyRouteNavigation relationship
Find a DomainGET /browser/datastores/{datastore_id}/domainsEach row supplies a Domain reference for its detail, Studies, and Variables routes.
Inspect a DomainGET /browser/datastores/{datastore_id}/domains/{domain_id}Returns the canonical Domain facts; it does not embed child collections.
Browse associated StudiesGET /browser/datastores/{datastore_id}/domains/{domain_id}/studiesEach row carries the same browser-safe Study reference used by the ordinary Study discovery journey.
Browse canonical VariablesGET /browser/datastores/{datastore_id}/domains/{domain_id}/variablesA row provides a Variable reference and, when present, a Vocabulary reference.
Inspect a VariableGET /browser/datastores/{datastore_id}/domains/{domain_id}/variables/{variable_id}Returns the canonical Variable facts, including its owning Domain and optional Vocabulary link.
Inspect a VocabularyGET /browser/datastores/{datastore_id}/domains/{domain_id}/vocabularies/{vocabulary_id}Returns the Vocabulary’s owning Domain and descriptive facts; categories and mappings remain separate collections.
Browse Vocabulary categoriesGET /browser/datastores/{datastore_id}/domains/{domain_id}/vocabularies/{vocabulary_id}/itemsReturns the bounded category collection for that Vocabulary.
Browse Vocabulary mappingsGET /browser/datastores/{datastore_id}/domains/{domain_id}/vocabularies/{vocabulary_id}/mappingsReturns every mapping in which that Vocabulary is either endpoint.

The public projection is deliberately narrow. Domain rows contain only their descriptive facts and tags. Domain Study rows contain shared browser-safe Study facts, not access-request actions or search-match evidence. Domain Variable rows are canonical definitions—not Dataset-version membership—and expose name, value type, description, and an optional Vocabulary link. Variable detail can add value format, tags, and ontology identifiers, but never Dataset membership, key role, note, or Dataset row role.

Collection Traversal

The Domain list, Domain Study list, Domain Variable list, Vocabulary item list, and Vocabulary mapping list are independently paginated collections. Each response has a returned count, requested limit, stable ordering identifier and description, optional opaque previous_cursor and next_cursor, and an optional neutral empty_state. The contract intentionally does not publish an exact total count.

Use limit and a returned cursor only on the same collection route. The default limit is 100 and the maximum is 500; zero, oversized, malformed, or otherwise invalid page parameters produce a public validation error. A returned cursor is bound to its datastore, route family, parent references, limit, ordering, direction, boundary, and protocol version. It must not be edited, decoded, or replayed for a different Domain, Vocabulary, collection direction, or page size.

The first page has no Previous cursor; the terminal page has no Next cursor; an empty collection has neither. An empty collection is a successful 200 response with an empty item array, returned count zero, and a stable neutral empty-state code and message. A collection URL with its returned cursor and unchanged limit is bookmarkable while the catalogue remains unchanged, but it is not a permanent snapshot. If the catalogue changes, the service returns 409 with browser_domain_cursor_stale; restart only that collection from its first page. Keep the Study and Variable cursors independent of each other and of the Domain list, so moving between these tables never changes another table’s traversal state.

Vocabulary Categories And Mappings

A Vocabulary category uses product-facing fields: integer code, string label, and optional definition. The projection is explicit: stored integer value becomes public code, stored string code becomes public label, and optional stored description becomes public definition. The storage field names are not alternative API fields. Categories are ordered by code then stable item identity and contain no observed frequencies, counts, percentages, distributions, or other Content-derived summaries.

Mappings retain their stored source and target orientation. A mapping row includes its own stable reference and, at each endpoint, the Vocabulary reference, item reference, integer code, and label. It does not duplicate item definitions. The selected Vocabulary can therefore appear as the source or the target, and the opposite Vocabulary can belong to a different Domain. This is not a claim that the mapping is symmetric. Mapping ordering is stable across source Vocabulary and item, target Vocabulary and item, then mapping identity.

Authority, Privacy, And Failure Boundaries

Domain browsing is broad Discovery metadata. It is independent of Study access grants, custodianship, TRE OAuth-group membership, and access-request state; those facts do not broaden or narrow a result. The service applies permission trimming before public projection and uses neutral not-found responses for unknown, cross-parent, unauthorized, or trimmed objects so the route cannot be used to probe hidden metadata.

Responses are metadata-only and must not expose protected rows or bytes, previews, downloads, Dataset memberships, Content-derived summaries, storage or Restricted local references, credentials, raw SQL, adapter detail, runtime handles, private governance data, Study membership, custodianship, or access-request state. They are Cache-Control: no-store. Operational logs retain only request ID, route family, datastore identity, response status, duration, returned-page count, requested limit, and limit outcome—not object references or names, cursors, bodies, cookies, ORCID identity, tags, ontology values, or category or mapping content.

Public situationContract behaviourCaller response
Invalid page or cursor400 public validation errorCorrect the request; do not retry it unchanged.
Changed catalogue409 / browser_domain_cursor_staleRestart the affected collection from its first page.
No authenticated visitor state401 / browser_session_requiredRe-establish ORCID login, then retry on user action.
No discovery authority403 / browser_discovery_forbiddenDo not retry automatically or infer governance state.
Unknown or ineligible datastore, or hidden objectNeutral 404Refresh discovery or return to the parent without probing.
Discovery unavailable or a safe read timeoutRetryable 503Retry on user action or bounded backoff; never show adapter detail.
Per-session rate or concurrency limit429 with Retry-AfterHonour the delay; do not fan out retries.
Incompatible protocol version400 / unsupported_protocol_versionStop the affected workflow and resolve compatibility.

Domain-browser callers may send the protocol version accepted from /version in X-Protocol-Version; omission uses the current supported version. A malformed or unsupported value fails safely. The operational defaults are 300 reads per minute per authenticated session with a burst capacity of 30, six concurrent reads, and a ten-second datastore timeout; deployments may tighten those values without changing protocol page maxima.

Separate Discovery Journeys

Domain Study browsing is not Study search. It has no search predicate, search-specific result evidence, aggregate search result, or access-request action; it simply follows the Domain–Study association and returns the shared safe Study facts. Its HTTP route has no runtime dependency on the Study search route.

Likewise, Domain Variables are canonical Domain-owned definitions, not the Dataset-scoped dictionary. The dictionary journey is GET /browser/datastores/{datastore_id}/studies/{study_id}/datasets/{dataset_version_id}/dictionary and describes its owning Dataset version. Datafiles do not own dictionaries. The legacy Datafile-shaped URL remains recognized as an explicit obsolete-route error and returns 410 / browser_datafile_dictionary_deprecated; new navigation must not offer it. Neither journey calls or depends on the other’s HTTP route. A Variable reused by Dataset versions or Studies is still represented once through its owning Domain rather than by a reverse Dataset or Study usage listing.

Deployment And Operations

Deploy the frontend and service at the same HTTPS origin. Browser session cookies are server-side, HttpOnly, Secure, and SameSite=Lax or Strict. The short-lived login-state cookie always uses SameSite=Lax so it can return on the external provider’s top-level GET redirect. Both callback routes require that cookie to match the pending transaction before consuming state or exchanging a code, and clear it on success. With Strict session cookies, the frontend landing page loads first and then fetches /session from the same origin; the callback itself does not need a session cookie.

Pending logins are bounded by services.web.max_pending_logins (default 1,024). Each new login reclaims expired records before admission; live transactions remain usable. Capacity rejection returns 503 orcid_login_capacity_exceeded with Retry-After: 60 and no cookie or redirect. Honour the delay before a fresh attempt. The deployment security guide details expiry, idle retention, and configuration limits.

Unsafe requests require a matching Origin; cross-origin credentialed CORS is not enabled. The complete operator policy is in the web control-plane deployment security guide. The datastore deployment guide describes the reverse-proxy and Runtime topology, identity and authority split, configuration categories, verification, and current session-store constraint.

The standalone service starts only with explicit confidential-client OIDC configuration: issuer, client ID, externally visible callback URI, scopes, cookie policy, and a server-side client-secret file reference. It exchanges the callback code and keeps token material in the service process. The callback is the same-origin /auth/orcid/callback URL; production deployments require HTTPS and secure cookies. The frontend never receives OIDC tokens or the secret.

The diagnostics operator guide describes request correlation, the ten-second Runtime check, shared admission limits, evidence bases and Local TRE log commands. /diagnostics retains HTTP 200 even when a returned check fails; /ready returns 200 or 503 for its check result. Admission can reject either route. Neither surface exposes owner-Session findings.

/health is a process-liveness check. /ready authenticates to the Trusted runtime and verifies the required stable-protocol capabilities, returning failure when that sole substantive path is unavailable or incomplete. It does not probe PostgreSQL and has no direct fallback. /diagnostics exposes only stable check names and status, redacting credentials, runtime references, Restricted local references, Lake locations, and protected content.

Scope And Follow-up

This MVP is a browser discovery and access-request surface, not a general remote control plane or a content viewer. It intentionally excludes cross-origin browser deployment, frontend framework choices, Rust/Wasm, dataset/datafile content delivery, and asset-level grants. The frontend repository specification and release handoff are tracked in issue 20.