User Request
Implement the organization switching feature in chat-app as described in the product spec (agynio/product/product/chat/chat.md). The backend now supports organization_id on CreateChat and GetChats (merged in agynio/chat#21). This includes the org switcher UI, no-organizations gate, org context state management, and comprehensive e2e tests without mocks.
Specification
Overview
Three areas of work:
- API layer — Add
organizationId to chat types/hooks to match the updated backend proto
- UI & state — Organization context provider, user menu org switcher, no-orgs screen
- E2E tests — Update existing tests + add new tests for org switching behavior
1. API Layer Changes
src/api/types/chat.ts
Add organizationId to:
Chat type — organizationId: string (returned by backend)
CreateChatRequest — organizationId: string (required by backend)
GetChatsRequest — organizationId: string (required by backend)
src/api/modules/chat.ts
Update normalizeChat and request serialization to handle organizationId field (snake_case ↔ camelCase).
src/api/hooks/chat.ts
useChats() → accepts organizationId parameter, includes it in query key and request payload. Disabled when organizationId is undefined.
useCreateChat() → passes organizationId in the mutation request.
2. Organization Context Provider
Create src/organization/ (following the src/user/ pattern):
OrganizationContext + OrganizationProvider + useOrganization hook
- On mount: fetches
listAccessibleOrganizations
- State:
{ organizations, selectedOrganizationId, selectOrganization, isLoading }
selectedOrganizationId defaults to first org; persisted to localStorage for session continuity
selectOrganization(id) updates state and invalidates org-scoped queries (chats, agents)
- Place in provider hierarchy: inside
UserProvider, outside App (in src/main.tsx)
3. User Menu — Organization Switcher
In the UserMenu component (currently in ChatsScreen.tsx):
Replace the current menu content with:
- Organization switcher section — list all orgs, highlight current, click to switch
- Use
DropdownMenuRadioGroup + DropdownMenuRadioItem (existing pattern from status toggle in ChatDetailHeader)
- Current org is the selected radio item
- Separator
- Sign out button (existing, OIDC only)
Remove the disabled "Account" menu item (not in the product spec).
Behavior on org switch:
- Conversation list reloads for new org
- Selected conversation is cleared (navigate to
/chats)
- Agent list reloads
4. No Organizations Screen
When organizations.length === 0:
- Replace the entire chat interface (both list and detail panels) with an onboarding screen
- Content: inform user they need to either get an invite or create a new organization
- This is a hard gate — no chat functionality until they belong to an org
- Add
data-testid="no-organizations-screen" for e2e testing
5. Chats Page Changes (src/pages/Chats.tsx)
- Consume
useOrganization() context instead of ad-hoc useAccessibleOrganizations()
- Pass
organizationId to useChats() and useCreateChat()
- On org change (via
useEffect on selectedOrganizationId): clear selectedChatId, navigate to /chats
- Guard: if no orgs, render
NoOrganizationsScreen instead of ChatsScreen
6. E2E Test Changes
Update existing helpers (test/e2e/chat-api.ts)
createChat(page, organizationId, participantId?) — add required organizationId parameter
Update existing tests
All tests that call createChat must create an organization first and pass it:
chats-list.spec.ts
chat-detail.spec.ts
chat-exchange.spec.ts
chat-with-agent.spec.ts (already creates org for agent — reuse for chat)
New e2e tests (test/e2e/organization-switching.spec.ts)
Tests must run against real backend (no mocks):
- Org switcher displays organizations — Sign in, verify the user menu shows available organizations
- Org switcher highlights current org — Verify the currently selected org is visually indicated
- Switching orgs reloads chat list — Create chats in org A and org B via API, switch orgs via UI, verify the chat list changes
- Switching orgs clears selected conversation — Select a chat in org A, switch to org B, verify no chat is selected
- No-organizations screen — User with zero orgs sees the onboarding screen instead of chat interface (use a fresh user email that has no orgs)
Data-testid Attributes
Add these for e2e targeting:
data-testid="user-menu-trigger" — user menu button
data-testid="org-switcher" — org radio group container
data-testid="org-item-{orgId}" — individual org radio item
data-testid="no-organizations-screen" — no-orgs onboarding screen
data-testid="current-org-name" — displays current org name (for assertions)
Reference Patterns
- Status toggle dropdown in
ChatDetailHeader — shows how DropdownMenuRadioGroup is used
src/user/ — pattern for context provider structure
test/e2e/chat-with-agent.spec.ts — shows createOrganization + createAgent flow
User Request
Implement the organization switching feature in chat-app as described in the product spec (
agynio/product/product/chat/chat.md). The backend now supportsorganization_idonCreateChatandGetChats(merged inagynio/chat#21). This includes the org switcher UI, no-organizations gate, org context state management, and comprehensive e2e tests without mocks.Specification
Overview
Three areas of work:
organizationIdto chat types/hooks to match the updated backend proto1. API Layer Changes
src/api/types/chat.tsAdd
organizationIdto:Chattype —organizationId: string(returned by backend)CreateChatRequest—organizationId: string(required by backend)GetChatsRequest—organizationId: string(required by backend)src/api/modules/chat.tsUpdate
normalizeChatand request serialization to handleorganizationIdfield (snake_case ↔ camelCase).src/api/hooks/chat.tsuseChats()→ acceptsorganizationIdparameter, includes it in query key and request payload. Disabled whenorganizationIdis undefined.useCreateChat()→ passesorganizationIdin the mutation request.2. Organization Context Provider
Create
src/organization/(following thesrc/user/pattern):OrganizationContext+OrganizationProvider+useOrganizationhooklistAccessibleOrganizations{ organizations, selectedOrganizationId, selectOrganization, isLoading }selectedOrganizationIddefaults to first org; persisted tolocalStoragefor session continuityselectOrganization(id)updates state and invalidates org-scoped queries (chats, agents)UserProvider, outsideApp(insrc/main.tsx)3. User Menu — Organization Switcher
In the
UserMenucomponent (currently inChatsScreen.tsx):Replace the current menu content with:
DropdownMenuRadioGroup+DropdownMenuRadioItem(existing pattern from status toggle inChatDetailHeader)Remove the disabled "Account" menu item (not in the product spec).
Behavior on org switch:
/chats)4. No Organizations Screen
When
organizations.length === 0:data-testid="no-organizations-screen"for e2e testing5. Chats Page Changes (
src/pages/Chats.tsx)useOrganization()context instead of ad-hocuseAccessibleOrganizations()organizationIdtouseChats()anduseCreateChat()useEffectonselectedOrganizationId): clearselectedChatId, navigate to/chatsNoOrganizationsScreeninstead ofChatsScreen6. E2E Test Changes
Update existing helpers (
test/e2e/chat-api.ts)createChat(page, organizationId, participantId?)— add requiredorganizationIdparameterUpdate existing tests
All tests that call
createChatmust create an organization first and pass it:chats-list.spec.tschat-detail.spec.tschat-exchange.spec.tschat-with-agent.spec.ts(already creates org for agent — reuse for chat)New e2e tests (
test/e2e/organization-switching.spec.ts)Tests must run against real backend (no mocks):
Data-testid Attributes
Add these for e2e targeting:
data-testid="user-menu-trigger"— user menu buttondata-testid="org-switcher"— org radio group containerdata-testid="org-item-{orgId}"— individual org radio itemdata-testid="no-organizations-screen"— no-orgs onboarding screendata-testid="current-org-name"— displays current org name (for assertions)Reference Patterns
ChatDetailHeader— shows howDropdownMenuRadioGroupis usedsrc/user/— pattern for context provider structuretest/e2e/chat-with-agent.spec.ts— showscreateOrganization+createAgentflow