Skip to content

serve the captures awaiting the reviewer under a category #204

Description

@haribo

Part of #202.

Build

Add an endpoint listing the captures of a project that await the reviewer.
Adding an endpoint is allowed; the OpenAPI source is the truth — edit
apps/server/api/src/ and regenerate, never the bundled
apps/server/api/openapi.yaml.

Today the client can ask for cases by state (listCases, filter state,
apps/server/api/src/paths/cases.yaml) and then for one case's grid
(getCaseCaptures, apps/server/api/src/paths/case-captures.yaml). Walking a
project's work therefore costs one request per case and returns whole grids to
find two captures. Nothing lists the captures themselves.

Shape. One GET under the project, taking an optional categoryId, and
returning the queue in the order the reviewer walks it: grouped by case, cases
in catalogue order, steps in position order, variants in label order. With a
category, the queue covers that category and every one beneath it — the tree is
of unrestricted depth (docs/adr/0014-server-generated-case-identity-and-catalogue-tree.md),
so the descent is recursive. Without one, the whole project. Each entry carries enough to open the carousel
on it and to say what it is waiting for — at minimum the case, the step, the
variant, and the capture with its status — to-review or moved, the two that
await the reviewer once #192 lands. No field says why beyond that status: a
delivered fix reads to-review like anything else, and its detail is read from
the comment. Reuse the existing evidence schemas
(apps/server/api/src/components/evidence.yaml) rather than inventing a
parallel vocabulary for the same things.

Read-only. The queue is computed from stored statuses at request time. It
stores nothing, and no endpoint accepts it as input
(docs/adr/0002-server-owns-the-review-lifecycle.md).

One query, no scan. The statuses are stored precisely so this filters
without walking every capture (docs/design/product.md §3.1). It belongs with
the other aggregate reads, apps/server/db/queries/aggregates.sql. Archived
cases are never listed, exactly as listCases already excludes them.

Layering is linter-enforced (docs/backend/adr/0001-hexagonal-layers.md): a
violation is fixed with an interface, never an import shortcut.

Validation

  • The generated client exposes the operation and the web app can call it
    without a hand-written type.
  • A postgres adapter test builds a project holding both statuses — an unjudged
    capture, a delivered fix (which reads to-review), a moved capture — plus
    captures that must not appear: accepted with an unchanged image, refused
    still with the dev, an archived case, a case at not-instrumented.
  • The order is asserted, not incidental: two cases, several steps each, the
    result grouped by case and ordered by step position.
  • The scope is asserted at depth: a category two levels up returns its own
    cases plus its descendants', and excludes a sibling branch's.
  • A project with nothing to review answers an empty list, never an error.

Depends on #194

The queue selects on to-review and moved, and moved only exists as a
status once #194 lands.

Out of scope

Filtering beyond the category scope (reviewer, age, axis value), pagination
beyond what the queue naturally needs, and any write path. The carousel and its route are the web sub-issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: featurenew capability or improvement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions