Team Testing Setup Plan — Mise Persona Switching (Revised)

Goal: Every person (Alex, Lex, Scott) wears three hats — testing the full persona matrix independently, across two restaurants.


The 9-Account Matrix

Person Email Path Team(s) Role Switch Profile Shows
Alex alex@bluehourdigital.com Team (manager) iL Bistro + Queen City Grill owner No switch — always management
Alex alexmichaelholden@gmail.com Talent iL Bistro + Queen City Grill member Personal + iL Bistro (member) + Queen City Grill (member)
Alex alex@yourmise.com Talent iL Bistro + Queen City Grill assistant_manager Personal + iL Bistro (mgmt) + Queen City Grill (mgmt)
Lex petras.lex@gmail.com Team (manager) iL Bistro + Queen City Grill owner No switch — always management
Lex lexpetras@gmail.com Talent iL Bistro + Queen City Grill member Personal + iL Bistro (member) + Queen City Grill (member)
Lex lex@yourmise.com Talent iL Bistro + Queen City Grill assistant_manager Personal + iL Bistro (mgmt) + Queen City Grill (mgmt)
Scott ssoderstrom@gmail.com Team (manager) iL Bistro + Queen City Grill owner No switch — always management
Scott scott@yourmise.com Talent iL Bistro + Queen City Grill member Personal + iL Bistro (member) + Queen City Grill (member)
Scott scott@paumalu-innovations.com Talent iL Bistro + Queen City Grill assistant_manager Personal + iL Bistro (mgmt) + Queen City Grill (mgmt)

Total: 9 Clerk accounts, 2 restaurants, 3 personas per person.


The Multi-Team Reality

A single worker can have multiple workerTeamMemberships rows:

workerId: "lex-worker"
├── teamId: "il-bistro", role: "member"
└── teamId: "queen-city-grill", role: "assistant_manager"

What the backend currently does (convex/experienceContext.ts): - Returns ALL teams in the teams[] array - Sets isManagement: true for any team where role is assistant_manager

What Switch Profile does now (Option B implemented in 0946592): - Shows all teams — both management and member teams - SubLabel shows "Management" for assistant_manager / owner roles, "Team Member" for member roles - Tapping any team switches the in-team context (messages, announcements, policies) - Management chrome (header color, forum topics, Post Deal button) only activates when the selected team has isManagement: true


Step 1: Colleagues Sign Up (9 Accounts)

Send this to Alex, Lex, Scott:

I've wiped all old accounts. Please do the following for each of your 3 emails:

  1. Open Mise and sign up with Email 1 (Google or basic email/password)
  2. Stop at the "Who are you?" screen — the three cards (Talent, Team, Vendor)
  3. Do NOT tap anything yet. Send me a screenshot so I know you reached it
  4. Sign out, repeat with Email 2, then Email 3

Which email → which card: | Your Email | Tap This Card | |---|---| | alex@bluehourdigital.com | Team | | alexmichaelholden@gmail.com | Talent | | alex@yourmise.com | Talent | | petras.lex@gmail.com | Team | | lexpetras@gmail.com | Talent | | lex@yourmise.com | Talent | | ssoderstrom@gmail.com | Team | | scott@yourmise.com | Talent | | scott@paumalu-innovations.com | Talent |

Wait for my go-ahead before tapping through. I need to prep the backend first.

Important: Everyone should pick the same metro during onboarding (e.g. Seattle or NYC) so soup deals are consistent.


Step 2: Scotty Runs Backend Setup

2a. Manager Accounts Create Their Teams

Each manager email taps Team, completes onboarding, creates a restaurant:

Manager Email Creates Team
alex@bluehourdigital.com iL Bistro
petras.lex@gmail.com Queen City Grill
ssoderstrom@gmail.com Place Pigalle (optional third team)

This automatically creates: - users row with userType = "manager" - managers row - teams row - managerTeamMemberships with role = "owner"

2b. Add Manager Cross-Memberships

If you want every manager to be on every team, run these mutations. For example, make Alex an owner on Queen City Grill too:

// Alex on Queen City Grill
await ctx.db.insert("managerTeamMemberships", {
  managerId: "<alex-manager-id>",
  teamId: "<queen-city-team-id>",
  role: "owner",
  joinedAt: Date.now(),
});

Repeat for all cross-combinations.

2c. Talent Accounts — Get Their IDs

After the 6 Talent emails have signed up and reached the "Who are you?" screen (or completed it), get their Convex IDs:

# Get all users, look for the 6 talent emails
convex data users --limit 20 --order desc | grep -E "(alexmichaelholden|lexpetras|scott@yourmise|alex@yourmise|lex@yourmise|scott@paumalu)"

# Get their worker IDs
convex data workers --limit 20 --order desc

2d. Create WorkerTeamMemberships (The Core Setup)

For each talent account, create memberships on all teams:

Alex's talent emails:

// alexmichaelholden@gmail.com — member on both teams
await ctx.db.insert("workerTeamMemberships", {
  workerId: "<alex-holden-worker-id>",
  teamId: "<il-bistro-team-id>",
  position: "server",
  role: "member",
  joinedAt: Date.now(),
});
await ctx.db.insert("workerTeamMemberships", {
  workerId: "<alex-holden-worker-id>",
  teamId: "<queen-city-team-id>",
  position: "bartender",
  role: "member",
  joinedAt: Date.now(),
});

// alex@yourmise.com — assistant_manager on both teams
await ctx.db.insert("workerTeamMemberships", {
  workerId: "<alex-yourmise-worker-id>",
  teamId: "<il-bistro-team-id>",
  position: "shift_supervisor",
  role: "assistant_manager",
  joinedAt: Date.now(),
});
await ctx.db.insert("workerTeamMemberships", {
  workerId: "<alex-yourmise-worker-id>",
  teamId: "<queen-city-team-id>",
  position: "shift_supervisor",
  role: "assistant_manager",
  joinedAt: Date.now(),
});

Repeat for Lex and Scott's talent emails.

Result: Each assistant_manager account has 2 management teams in Switch Profile.


Step 3: The Enhanced Switch Profile (Code Change Needed)

Currently, SwitchProfilePanel.tsx filters to isManagement teams only:

const managementTeams = useMemo(() => teams.filter((t) => t.isManagement), [teams]);

To show ALL teams (which you want to test):

const allTeams = useMemo(() => teams, [teams]);

And in PersonaContext.tsx, deriveDefaultActiveProfile should pick the first team (not just first management team):

function deriveDefaultActiveProfile(teams) {
  const first = teams[0]; // any team, not just management
  if (first) {
    return { kind: 'management', teamId: first.teamId, teamName: first.name };
  }
  return { kind: 'personal' };
}

But wait — a regular member on iL Bistro shouldn't default to "management". They should default to "Personal" and be able to switch to iL Bistro as a team context.

This means Switch Profile needs two sections: 1. Personal (always) 2. Teams (all teams the user belongs to, not just management ones)

When a user selects a team where isManagement: true, they get the management chrome (header, tabs, forum topics). When they select a team where isManagement: false, they get the member view of that team.

This is a product decision — do you want me to implement this expanded Switch Profile as part of testing setup, or keep the current isManagement filter and test what's there?


Step 4: Test Matrix (Per Person, Per Email)

Alex's Manager Email (alex@bluehourdigital.com)

Test Expected
Home board soup-deals, mini-feed, quick-post-box, team-metrics
Soup "Post Deal" Visible and functional
Bottom tabs Home, Messages, Perks, Hiring, My Team
Forum topics SOS!, The Line, etc.
My Team tab iL Bistro (and Queen City Grill if cross-membership added)

Alex's Talent Email (alexmichaelholden@gmail.com)

Test Expected
Switch Profile Current: Personal only (member teams hidden). Desired: Personal + iL Bistro + Queen City Grill
Home board soup-deals, mini-feed, quick-post-box
Soup "Post Deal" Not visible (member role)
Forum topics Hands!, Shift Drinks, etc.

Alex's Talent+Mgmt Email (alex@yourmise.com)

Test Expected
Default Personal profile → talent view
Switch Profile Personal + iL Bistro (mgmt) + Queen City Grill (mgmt)
Switch to iL Bistro mgmt Header ochre, forum topics SOS!, Post Deal visible
Switch to Queen City Grill mgmt Same, but team-scoped data changes
Switch back to Personal Everything flips to talent view

Repeat for Lex and Scott.


Step 5: Convex Quick Reference

# Get all users (find your 9 accounts)
convex data users --limit 50 --order desc

# Get all workers
convex data workers --limit 50 --order desc

# Get all managers
convex data managers --limit 10 --order desc

# Get all teams
convex data teams --limit 10 --order desc

# Get memberships
convex data workerTeamMemberships --limit 50 --order desc
convex data managerTeamMemberships --limit 50 --order desc

# Clear all mock data (if you want pristine)
convex run devTools:clearAllMockData '{}'

Option B Changes (Implemented & Pushed)

Commit: ddc3ffc on main

Files Modified

File Change
expo-app/src/contexts/PersonaContext.tsx Added isManagement: boolean to ActiveProfile type; updated deriveDefaultActiveProfile to pick first team (any team); updated deriveShellVariantFromActive to check active.isManagement; added effect to sync isManagement flag when role changes
expo-app/src/hooks/useUserPermissions.ts isWorkerPlus now requires activeProfile.isManagement === true, not just kind === 'management'
expo-app/src/components/persona/SwitchProfilePanel.tsx Shows all teams with subLabel "Management" or "Team Member"; passes isManagement flag on pick
expo-app/src/components/mobile/MobileAvatarMenu.tsx Subtitle reflects "Management" or "Team Member" based on isManagement flag

Behavior

Testing Multi-Team

With Option B, a worker on both iL Bistro (member) and Queen City Grill (assistant_manager) sees:

  1. Personal
  2. iL Bistro · Team Member
  3. Queen City Grill · Management

Tapping iL Bistro switches team-scoped data to iL Bistro but keeps talent chrome. Tapping Queen City Grill switches team-scoped data AND activates management chrome.