Problem
Two structural issues in src/api/groups/:
useUserGroups.ts (137 lines) hides a wide behaviour swing behind one boolean: fetchUserGroups(userId, { all }) flips the auth model (admin-gated) and the is_member semantics (line 55), a shallow interface over a branchy implementation. It also fires an N+1 count query per Group (addMemberCounts, lines 44-59).
- The "resolve profiles for a set of member ids" join is hand-stitched in at least three modules —
useGroupVotes.ts (members → votes → profiles), useInviteToGroup.ts (members → profiles), useGroupMembers.ts — each re-deciding error handling (in useGroupVotes a profiles failure is swallowed with username: null).
No tests anywhere in src/api/groups/.
Proposed deepening
Split the flag into two query modules (useUserGroupsQuery / useAllGroupsQuery for admin), and put member/profile/count resolution behind one shared resolver that all group and group-vote modules consume.
Relations
Umbrella over two perf tickets whose fixes would land inside the resolver instead of per-file:
Also relates to #123 (Active Group foundation), which will lean on group membership reads.
Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 6). Design to be settled in a grilling session before implementation. Vocabulary per /codebase-design.
Problem
Two structural issues in
src/api/groups/:useUserGroups.ts(137 lines) hides a wide behaviour swing behind one boolean:fetchUserGroups(userId, { all })flips the auth model (admin-gated) and theis_membersemantics (line 55), a shallow interface over a branchy implementation. It also fires an N+1countquery per Group (addMemberCounts, lines 44-59).useGroupVotes.ts(members → votes → profiles),useInviteToGroup.ts(members → profiles),useGroupMembers.ts— each re-deciding error handling (inuseGroupVotesa profiles failure is swallowed withusername: null).No tests anywhere in
src/api/groups/.Proposed deepening
Split the flag into two query modules (
useUserGroupsQuery/useAllGroupsQueryfor admin), and put member/profile/count resolution behind one shared resolver that all group and group-vote modules consume.Relations
Umbrella over two perf tickets whose fixes would land inside the resolver instead of per-file:
addMemberCountsanduseGroupMembers)useGroupVotes' three sequential round-trips → one embedded selectAlso relates to #123 (Active Group foundation), which will lean on group membership reads.
Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 6). Design to be settled in a grilling session before implementation. Vocabulary per
/codebase-design.