FIGURE 17

Team / Brokerage Hierarchy & Access Model

OFFRPORTL — Multi-Level Agent Hierarchy, Email-Based Membership Scoping, Invite Flow, and Role-Based Page Access Control
Abstract
A computer-implemented system for managing agent team and brokerage hierarchies within a real estate offer portal. The system defines five account roles (Individual Agent, Team Leader, Team Member, Brokerage Owner, Brokerage Member) persisted via email-reference fields on the User entity (team_leader_email, brokerage_owner_email, is_team_leader, account_type). Membership is established via a two-step invite-acceptance flow: an invitation email with encoded parameters followed by an identity-verified acceptance that performs atomic dual writes to both invitee and leader user records. A ProtectedRoute component blocks Subscription page access for team and brokerage members. Team roster management is gated to leaders and owners. Both team and brokerage modes share identical backend logic, differentiated only by user entity field and UI label.
§1 — Account Types & Role Definitions
INDIVIDUAL AGENT
account_type = "individual"
Default account type for all new registrations. Full access to their own listings and offers. Cannot manage other agents. Subscription page accessible. No shared roster.
is_team_leader: false team_leader_email: null brokerage_owner_email: null
TEAM LEADER
account_type = "team" is_team_leader = true
Pro subscriber who has activated team leader status. Can invite agents via sendTeamInviteEmail. Manages team roster via TeamRoster page. Sees team join notifications. Team members are scoped under their email.
is_team_leader: true team_leader_email: null brokerage_owner_email: null
TEAM MEMBER
account_type = "team" team_leader_email = set
Agent invited and accepted by a team leader via completeTeamInvite. Restricted from Subscription page (ProtectedRoute). Full offer/listing access for their own data. Cannot access admin or billing features.
is_team_leader: false team_leader_email: "<leader email>" brokerage_owner_email: null
BROKERAGE OWNER
account_type = "brokerage" is_team_leader = true
Pro subscriber operating a brokerage account. Functionally equivalent to Team Leader but scoped under "brokerage" account_type. Sees "Brokerage Roster" label instead of "Team Roster". Can invite brokerage agents.
is_team_leader: true team_leader_email: null brokerage_owner_email: null
BROKERAGE MEMBER
account_type = "brokerage" brokerage_owner_email = set
Agent under a brokerage owner. Invited and accepted via completeTeamInvite with brokerage context. Restricted from Subscription page. Cannot access billing or roster management.
is_team_leader: false team_leader_email: null brokerage_owner_email: "<owner email>"
§2 — Hierarchy Structure Diagram
Team Account Type
TEAM LEADER
account_type = team · is_team_leader = true
sendTeamInviteEmail ↓ / completeTeamInvite ↑
Agent A
team_leader_email = set
Agent B
team_leader_email = set
Agent C
team_leader_email = set
Brokerage Account Type
BROKERAGE OWNER
account_type = brokerage · is_team_leader = true
same flow, brokerage_owner_email written
Agent X
brokerage_owner_email = set
Agent Y
brokerage_owner_email = set
Agent Z
brokerage_owner_email = set
Both hierarchy types use identical backend functions and access control logic · Differentiated only by user entity field written and UI label rendered
§3 — Team Invite & Acceptance Flow (8 Steps)
1
TEAM LEADER / BROKERAGE OWNER
Initiates Team Invite
Leader navigates to TeamRoster page. Enters invitee email and optional name. Clicks "Invite". sendTeamInviteEmail backend function called with: leader_email, leader_name, invitee_email, account_type (team | brokerage). Function sends invitation email with unique accept link.
2
SYSTEM
Generates Accept Link & Sends Email
sendTeamInviteEmail constructs an accept URL containing encoded parameters: leader_email, invitee_email, account_type. URL routes to /AcceptInvite page. Email sent via Resend API with branding and accept CTA. No pre-registration required for invitee.
3
INVITEE (Agent)
Clicks Accept Link → AcceptInvite Page
Invitee opens email and clicks accept CTA. Redirected to /AcceptInvite page with URL params: leader_email, invitee_email, account_type. Page reads params via URLSearchParams. If invitee is not logged in, prompted to authenticate first.
4
SYSTEM
Authenticates Invitee & Verifies Email Match
AcceptInvite page calls base44.auth.me() to get current authenticated user. Verifies user.email matches invitee_email from URL param. If mismatch: shows error "You must be logged in as [invitee_email] to accept this invite." Prevents cross-account acceptance.
5
INVITEE
Confirms Acceptance
AcceptInvite page renders confirmation UI showing team leader name and account type. Invitee clicks "Accept Invitation". completeTeamInvite backend function called with: leader_email, member_email, account_type.
6
SYSTEM
completeTeamInvite Updates Both User Records
Function performs two atomic writes: (1) On invitee user: sets team_leader_email (or brokerage_owner_email) to leader_email, sets account_type to "team" or "brokerage". (2) On leader user: appends to team_join_notifications array: {member_email, member_name, joined_at, acknowledged: false}.
7
SYSTEM
Leader Notified of New Member
Layout component reads team_join_notifications on the leader user. Unacknowledged entries increment unread notification count badge. Leader sees notification: "👥 New Member Joined — [name] joined your team/brokerage." Clicking acknowledges the notification (sets acknowledged: true on user entity).
8
TEAM LEADER
Manages Roster & Can Remove Members
TeamRoster page calls getLeaderProfile backend function to retrieve all members scoped under leader_email. Leader sees member list with email, join date, and last access. Can remove a member via removeTeamMember function, which clears team_leader_email (or brokerage_owner_email) on the member user record.
§4 — Feature Access Control Matrix by Account Role
Feature / PageIndividualTeam LeaderTeam MemberBrok. OwnerBrok. MemberImplementation Note
Subscription Page✗ Blocked✗ BlockedProtectedRoute checks team_leader_email and brokerage_owner_email
TeamRoster PageNav item conditionally shown: is_team_leader OR account_type=brokerage OR role=admin
Invite Team MemberssendTeamInviteEmail only callable by leaders/owners
Remove Team MembersremoveTeamMember clears membership fields on member user
Team Join NotificationsStored in team_join_notifications array on leader user entity
Own Listings & OffersAll agents manage their own data regardless of hierarchy
Admin Pagesrole = "admin" required, independent of team hierarchy
Analytics DashboardStarter+✓ ProStarter+✓ ProStarter+Gated by subscription_tier, not team role
§5 — User Entity: Team & Hierarchy Fields
FieldTypeDescription
account_typeenumAccount type. Controls navigation labels and roster scoping.Values: individual | team | brokerage
is_team_leaderbooleanTrue for team leaders and brokerage owners. Enables TeamRoster page and invite features.Values: true | false
team_leader_emailstringSet on team members when invite accepted. Restricts Subscription page. Used to scope team roster queries.Values: leader email | null
brokerage_owner_emailstringSet on brokerage members when invite accepted. Same restrictions as team_leader_email.Values: owner email | null
team_join_notificationsarrayArray on leader user. Appended by completeTeamInvite. Drives unread count in notification bell.Values: [{member_email, member_name, joined_at, acknowledged}]
§6 — Backend Functions
sendTeamInviteEmail
Trigger: Leader clicks Invite on TeamRoster page
Sends invite email with accept URL containing leader_email, invitee_email, account_type params. Uses Resend API.
completeTeamInvite
Trigger: Invitee clicks Accept on /AcceptInvite page
Sets team_leader_email or brokerage_owner_email on invitee user. Appends to team_join_notifications on leader user. Atomic dual write.
getLeaderProfile
Trigger: TeamRoster page load
Returns all user records where team_leader_email or brokerage_owner_email = leader email. Used to render member list.
removeTeamMember
Trigger: Leader clicks Remove on TeamRoster page
Clears team_leader_email (or brokerage_owner_email) on the member user record. Member reverts to individual access.
§7 — Key Patentable Claims Summary
Claim 1.A computer-implemented method for managing agent team hierarchies within a real estate offer portal comprising: storing team membership as a foreign-key-style email reference (team_leader_email or brokerage_owner_email) on the member user entity, enforcing subscription page access restrictions via a ProtectedRoute component that evaluates the presence of these fields before rendering, and providing a roster management page accessible only to users where is_team_leader = true or account_type = "brokerage".
Claim 2.The method of claim 1, wherein team membership is established via a two-step invite-acceptance flow: a sendTeamInviteEmail function dispatches an invitation email containing encoded parameters (leader_email, invitee_email, account_type), and a completeTeamInvite function atomically writes team membership fields to the invitee user entity and appends a join notification record to the leader user entity's team_join_notifications array.
Claim 3.The method of claim 2, wherein the AcceptInvite page enforces identity verification by comparing the authenticated user's email to the invitee_email URL parameter before allowing acceptance, preventing cross-account team membership assignment without server-side secret infrastructure.
Claim 4.A system for dual-mode team hierarchy management comprising: a "team" account_type for agent teams under a team leader and a "brokerage" account_type for agents under a brokerage owner, wherein both modes share identical access control logic and backend functions, and are distinguished only by the label rendered in the UI ("Team Roster" vs "Brokerage Roster") and the user entity field written (team_leader_email vs brokerage_owner_email).
Fig. 17 — Team / Brokerage Hierarchy & Access Model. Five account roles (Individual Agent, Team Leader, Team Member, Brokerage Owner, Brokerage Member) are persisted via email-reference fields on the User entity. Membership established via two-step email invite + identity-verified acceptance with atomic dual writes via completeTeamInvite. ProtectedRoute blocks Subscription page for members. TeamRoster page gated to leaders and owners. Both team and brokerage modes share identical backend logic, differentiated only by user entity field written (team_leader_email vs brokerage_owner_email) and UI label ("Team Roster" vs "Brokerage Roster").