Extend login flow with party selection

Table of Contents

This page is a capture in the next bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.

After authentication, look up the user's associated parties from account_parties. If one party, auto-select. If multiple, return the party list to the client for selection. The client displays a party picker widget. After selection, compute the visible party set and bind to the session.

Acceptance Criteria

  • Login response includes available parties.
  • Party picker displayed when user has multiple parties.
  • Selected party stored in session and displayed in application window (title bar shows username @ party_name).
  • Party context immutable for session lifetime.

Design Notes

Protocol changes

Extend login_response (0x2006) with two fields appended to the wire format:

  • available_parties: vector<{uuid id, string name}> — empty when 0 or 1 party (auto-selected); populated when ≥2 parties.
  • selected_party_id: uuid — non-nil only when the server auto-selected exactly one party; nil when the client must choose.

Add two new messages:

  • select_party_request (0x2015): {uuid party_id}
  • select_party_response (0x2016): {bool success, string error_message}

Server changes (handle_login_request)

The party resolution block (lines 488-520 of accounts_message_handler.cpp) currently always auto-selects parties.front(). Change to:

  • 0 parties → leave session unbound; no change.
  • 1 party → auto-select as now; set selected_party_id in response.
  • ≥2 parties → do NOT bind party_id yet; return available_parties list; leave session unbound until select_party_request arrives.

Add handle_select_party_request: validate chosen party_id is in account's account_parties, bind session->party_id, recompute visible_party_ids, update both in-memory session and DB record.

Client changes

  • LoginResult gains available_parties and selected_party_id.
  • ClientManager gains current_party_id_, current_party_name_, and a selectParty(uuid) method.
  • LoginDialog::onLoginResult gains a new branch after the password-reset check: if available_parties.size() > 1, show PartyPickerDialog (modal, same pattern as ChangePasswordDialog). On reject → disconnect, re-enable form. On accept → call clientManager_->selectParty(id).
  • Main window title set to username @ party_name after login completes.

Session state machine

Not connected
  → Connected
  → Authenticated  (party-unbound, only when ≥2 parties)
  → Party selected (fully operational)

0 or 1 party: Authenticated → Party selected in one step (no picker shown).

Emacs 29.1 (Org mode 9.6.6)