ADR-0017: Supervisor Team Scope Resolved by Scanning the Shared Member Table
Status
AcceptedTags
fieldforce, teams, supervisor, better-auth, adr-0006Decision
Fieldforce supervisor scope (which tasks a supervisor can see) is resolved by reading the supervisor’steam_ids from the shared member table (a JSONB column after the prerequisite migration), then querying all members in the org and filtering to those sharing at least one team ID. This runs in the Go HTTP handler on every list request for a supervisor-role caller. No team data is replicated into the Go schema.
Why
Teams are owned by the Bun backend. Themember table is part of the Better Auth schema — read-only from Go (ADR-0006). There is no teams join table accessible from Go. Replicating team membership into a Go-owned table requires a sync mechanism between Bun and Go that does not exist and violates the bounded context boundary.
Rejected alternatives:
- Replicate teams into a Go-owned table: Violates ADR-0006. Requires ongoing synchronization with no existing infrastructure. Rejected.
- Dedicated teams API endpoint in Go: Phase 1 scope. Revisit in Phase 4 if org sizes exceed thousands of members. Rejected for Phase 1.
How it works
team_ids is JSONB after the prerequisite migration (Task 0 in Phase 1). The @> containment operator uses the GIN index for efficient lookup. For orgs with hundreds of members, the O(n) scan is one indexed query — acceptable.
Known limitations
- Scale threshold: At > 1,000 members per org, the full-member scan may degrade beyond 200ms P95. At > 200ms P95 on supervisor list requests, revisit with a Go-side teams cache or a dedicated teams service.
- Stale team membership: If a member is added to or removed from a team in Bun, the change is reflected on the next Go request — no cache invalidation needed because Go always reads the current
membertable.
Rules for agents
- Never write to the
membertable from Go — SELECT only (ADR-0006) resolveAllowedUserIDsmust returnnil(no filtering) for non-supervisor roles — nil means “see all org tasks”TaskFilter.AllowedUserIDsnon-nil means “restrict to this set” — the repository appliesAND user_id = ANY(?)on the assignments join- Do not cache the result of
resolveAllowedUserIDsin application memory — team membership changes must be reflected immediately