Filter and Sort Semantics for /projects
Context
Handlers expose the /projects list endpoint with several query parameters used by frontends to filter and sort project lists. The repository provides a generic in-memory adapter that centralizes filtering, search and sorting. The behavior must be explicit so adapters and frontend developers have a stable contract.
Decision
customer_idquery param accepts either a single id or a comma-separated list of ids. When multiple ids are provided the adapter treats them as an OR for customer membership: a project matches if it belongs to any of the listed customers.- Different query parameters (for example
customer_idandperson_id) are combined using AND semantics: a project must satisfy every provided filter to be returned. - The
/projectsendpoint supportssort=progressin addition tonameandpriority. Whensort=progressis used projects are ordered numerically by their clampedprogressvalue (ascending). progressvalues returned by adapters are clamped to the inclusive range[0,100]by the generic in-memory adapter duringRefresh.
This ADR documents and formalizes the behavior already implemented in memory.GenericAdapter and described in SPEC.md.
Consequences
- Adapter implementors must map upstream DTOs into the normalized
model.*shapes and may provide raw progress values; the generic adapter will clamp them onRefresh. - Frontends relying on multi-customer filtering must pass comma-separated ids in
customer_idwhen they want the OR semantics. - Clients that want OR semantics across different fields must issue multiple requests or this API must be extended; the current decision is AND across fields.
Implementation
- The
memory.GenericAdapterimplements the decision. Handlers populateQueryOptionsfrom URL params (including comma-splittingcustomer_id) and callListProjects(ctx, opts). SPEC.mdhas been updated to record these semantics in the canonical spec.
Alternatives considered
- OR semantics across different fields (e.g., projects matching either person OR customer) — rejected because it complicates frontends and backend filtering logic; explicit AND semantics are simpler and match typical UI filter behavior.
Related
SPEC.md— updated to document these semantics.internal/adapter/memory/memory.go— contains the implementation of the filtering, sorting and clamping behavior.