My Team rosters and contact access
The personal Mijn team menu opens /mijn-team. Current players, trainers, coaches, team managers, and parents of linked minor players see a compact roster with each current player’s name and photo. In teams reached only through the logged-in person’s player role or a child, rows show names and photos without contact details, parent information, or an expand control. In teams where that person has a current coaching or team-management role, contact details for players and their linked parents/guardians are collapsed by default; selecting a player row expands them. Multiple rows can remain open. Phone and email links open the corresponding app. Each visible mobile number has a WhatsApp button with an international, digits-only wa.me link; the roster has no edit or general person-profile links.
A separate Staf list shows staff photos, current roles, and expandable phone/email details to every authorized viewer of the team, including players and parents. Staff contacts do not include their own parents/guardians. Staff and player lists reuse src/components/RosterMemberCard.jsx, also used by Mijn commissies. Staff cards suppress parent sections; player cards retain their authorized parent contacts.
People with multiple current teams switch between tabs built with the shared TabButton component used on person profiles. Tabs support arrow keys, Home, and End. A single team shows its name without tabs. Switching teams closes the previous team’s contact rows. Photos use a 64-pixel square crop with rounded corners; absent or failed photos show initials, and contact columns stack on mobile.
Each selected team shows its training times and a Teamagenda card with the shared subscription popover and copy action. Switching teams switches the calendar link too. Calendar subscriptions have moved here from Mijn gegevens. The /rondo/v1/my-teams response includes a signed calendar_url for each authorized team, generated without a Sportlink request. Calendar availability does not depend on player contact permissions.
Access
Section titled “Access”Rondo\Teams\MyTeam::teams_for_user() resolves the logged-in user’s rondo_linked_person_id and current work_history. The linked person must be published. Own assignments and child assignments qualify only for published, non-former people and published teams. Roles from VolunteerStatus::get_player_roles() grant access to names and photos. Contact access is granted only by Trainer, Coach, Trainer/coach, Hoofdtrainer, Assistent-trainer, Assistent-coach, Assistent-trainer/coach, Leider, Teamleider, and Teammanager (case-insensitive, trimmed). Other staff roles do not grant access.
Permissions are resolved separately for each team as can_view_contacts. A person who coaches team A but plays in team B receives contacts only for A, even when a teammate plays in both teams. With both player and coaching assignments in one team, any current eligible coaching assignment grants contact access regardless of assignment order. Expiring that coaching role while retaining a current player role immediately reduces the next response to names and photos. Parent/guardian relationships add the current playing teams of children returned by AccessControl::get_visible_person_ids(): the same directly linked children under 18 used by Mijn gegevens. Adult children, missing birthdates, other relationships, and coaching-only assignments of a child grant no roster access. A former-member parent can still view active children’s teams, but their own old assignments grant no access. A child’s coaching role never grants player contact rights to their parent.
Rondo\People\RosterPerson shares the explicit identity/contact projections and current-position checks with Mijn commissies. Dates override stale is_current flags: future starts, expired ends, and malformed dates are excluded. Start and end dates are inclusive in the WordPress timezone. Undated assignments explicitly marked inactive are excluded. Duplicate assignments do not repeat teams or players.
The current-user response includes has_my_teams, used by both the menu and route guard. Administrator status alone does not produce a personal roster. This feature grants no new roles or general person access; existing access to other screens remains independently governed by their own permissions.
Endpoint and data boundary
Section titled “Endpoint and data boundary”GET /wp-json/rondo/v1/my-teams requires authentication and a current eligible own assignment or a linked minor child with a current playing assignment. It returns HTTP 401 for anonymous requests and HTTP 403 for users without an eligible team. The endpoint accepts no user, team, or contact-permission selector: scope always comes from the authenticated user. It provides no write methods.
The response is an array of { id, name, can_view_contacts, players, staff } teams. When can_view_contacts is false, each player contains exactly { id, name, thumbnail }: email, phone, and parent fields are omitted from the response entirely and are not read for that team’s basic roster. When true, each player contains { id, name, emails, phones, mobile_phones, thumbnail, parents }, and every parent contains only { id, name, emails, phones, mobile_phones }. The frontend also requires can_view_contacts === true to render contact controls.
Each staff entry contains exactly { id, name, emails, phones, mobile_phones, thumbnail, roles }. A current, nonempty role outside the configured player roles identifies staff; this follows the team player/staff split. Multiple staff roles in one team are combined into a unique role list. Empty roles, inactive/future/expired assignments, former members, and unpublished people are excluded. Staff roles and contact visibility are resolved per team: contacts exposed as staff in team A do not appear in the basic player entry for team B. can_view_contacts controls player and parent details only; staff contacts are available to every viewer of the returned team.
thumbnail is the existing WordPress featured image URL at thumbnail size, or null when no image is available. It is resolved only after the current-team and player/staff-role checks; parent photos and general media responses are not included. Emails and phone numbers come from the six canonical contact fields. mobile_phones identifies numbers from mobile_1 and mobile_2, including international numbers, and is included only in authorized contact records. The frontend also recognizes Dutch mobile numbers stored in telephone fields. Landlines have no WhatsApp button. The same contact component handles staff, players, and parents. Empty fields are omitted from the arrays, duplicate addresses/numbers are collapsed, and missing contacts are explained in the UI.
Published, non-former players are matched using the configured player roles from VolunteerStatus::get_player_roles() and the same date checks as coaching assignments. Parent relationships reuse the existing VolunteerEligibilityService::find_parents() resolver. Only published person records qualify as parents; a parent’s former-member status does not erase their relationship to an active child. Other relationships are not exposed.
The internal WordPress roster query is independent of household visibility so a plain member can see their team’s player identities and, when coaching, contacts. Team assignment and player-role checks precede the appropriate explicit field allowlist. Basic identities, player/parent contacts, and staff contacts are kept separate when assembling multiple teams. General person serialization, account lookups, volunteer obligations, signup history, finance fields, and other profile fields are never included.
Freshness and verification
Section titled “Freshness and verification”The endpoint sends Cache-Control: private, no-store. A specific NetworkOnly service-worker route precedes generic API caching, so rosters have no offline fallback. The page uses an account-specific query key, discards its cache on unmount, and rechecks on mount, window focus, and network reconnect. A failed recheck hides the previous roster.
MyTeamTest covers the exact basic and contact responses, player thumbnails and missing photos, exclusion of parent photos, parent filtering, duplicate assignments and contacts, mixed player/coaching roles, parent-only access to multiple child teams, household age and relationship boundaries, staff contacts for players and parents, staff-role deduplication, cross-team staff/player privacy, players shared between teams, assignment order, role downgrade, multiple teams, unlinked/anonymous users, excluded staff roles, expired and future assignments, immediate revocation, unpublished records, former members, read-only routing, and attempts to expand scope using request parameters. It also confirms that general person access remains unchanged.
Feedback #11647 is intentionally implemented only as a contact overview. Rondo registration status and volunteer-task registrations are outside this feature.