Skip to content

feat: suggest custom subject ids from a dedicated endpoint instead of the full subject list - #1566

Merged
joshunrau merged 6 commits into
DouglasNeuroInformatics:mainfrom
david-roper:feat/subject-custom-ids-endpoint
Sep 27, 2026
Merged

joshunrau merged 6 commits into
DouglasNeuroInformatics:mainfrom
david-roper:feat/subject-custom-ids-endpoint

Conversation

@david-roper

Copy link
Copy Markdown
Collaborator

Closes #1536

Why

The start-session form's identifier combobox was built from GET /v1/subjects?groupId=, which
returns every subject in the group, including names, dates of birth and sex. The page kept only the
ids of subjects without full personal information. That meant:

  • Data minimization: each visit sent the whole group's personal information to the browser,
    though the page never showed it.
  • Size: the response had no pagination or field selection (about 4.5 MB for 15,000 subjects),
    and it refetched on every visit and whenever the tab became visible again.
  • No group: groupId was optional, so an admin with no current group received every subject in
    the instance.

What changed

  • API: new GET /v1/subjects/groups/:groupId/custom-ids
    (@RouteAccess({ action: 'read', subject: 'Subject' }), groupId through ValidObjectIdPipe).
    SubjectsService.findCustomIds filters in MongoDB and returns only ids (select: { id: true }).
    Its where has three parts:
    • accessibleQuery(ability, 'read', 'Subject'), so callers only see subjects they may read;
    • { groupIds: { has: groupId } };
    • an OR matching a subject where any of dateOfBirth, firstName, lastName or sex is null
      or { isSet: false }. On MongoDB a Prisma null filter does not match a missing field, and
      a custom-id subject's name fields are missing, not null.
  • Schemas: $SubjectCustomIds, derived from $Subject.shape.id.
  • Web: new useSubjectCustomIdsQuery and subjectCustomIdsQueryOptions, keyed on
    ['subjects', 'custom-ids', groupId]. The start-session route and its loader use them in place of
    useSubjectsQuery. With no current group, the hook makes no request and there are no suggestions.

The new route has three segments, so @Get(':id') cannot shadow it even though eslint --fix
orders it after that handler.

Tests

  • API unit tests (apps/api/src/subjects/__tests__/subjects.service.spec.ts,
    findCustomIds): only ids are selected and returned; the ability's filter is applied (checked
    with a conditional rule); the group is filtered on; the null / isSet: false clause covers all
    four fields.

  • Web unit tests (apps/web/src/hooks/__tests__/useSubjectCustomIdsQuery.test.ts): the endpoint
    URL; no request without a group; a response that is not a list of ids is rejected; switching
    groups does not reuse another group's cached list.

  • E2E (testing/src/specs/start-session.spec.ts, custom identifier suggestions):

    • personal-info subjects are left out, and custom-id subjects are listed, with and without date of
      birth and sex;
    • other groups' subjects are left out;
    • a group manager asking about a group they are not in gets [].

    These use a new findSubjectCustomIds method in testing/src/support/api-client.ts. The
    existing test that picks a suggested id in the UI still passes.

  • Checked against broken code: with the isSet: false clause removed, the first e2e test fails.
    With the ability dropped, the group-manager test fails.

pnpm lint and pnpm test pass. pnpm test:e2e passes except
subject-detail.spec.ts › should plot a selected measure on the graph tab…, which is flaky and
unrelated to this change. It also failed on another branch before this work, and passed on reruns.

Not in scope

The data hub still loads the full subject list with the same query, plus a second list filtered by
hasRecord. This change does not touch it.

@david-roper
david-roper force-pushed the feat/subject-custom-ids-endpoint branch from b97bfda to b271908 Compare September 25, 2026 18:16
@david-roper
david-roper force-pushed the feat/subject-custom-ids-endpoint branch from b271908 to 4b4b13e Compare September 25, 2026 19:39
@joshunrau
joshunrau merged commit e58df91 into DouglasNeuroInformatics:main Sep 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Start-session page downloads every subject in the group, with personal information, to list custom IDs

2 participants