Extend login flow with party selection
Table of Contents
This page is a capture in the discarded bucket of the product backlog.
Resolved (deep backlog refinement, 2026-07-11): Fully implemented: login_protocol.hpp has available_parties/selected_party_id fields (projects/ores.iam/api/include/ores.iam.api/messaging/login_protocol.hpp:61-62); select_party_request/response handled in auth_handler (registrar.cpp:185-186 wires select_party_request); Qt has PartyPickerDialog (projects/ores.qt/api/src/PartyPickerDialog.cpp) invoked from LoginDialog.cpp:706, and ClientManager::selectParty (ClientManager.cpp:392) calls into it. The described design has shipped.
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_idin response. - ≥2 parties → do NOT bind
party_idyet; returnavailable_partieslist; leave session unbound untilselect_party_requestarrives.
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
LoginResultgainsavailable_partiesandselected_party_id.ClientManagergainscurrent_party_id_,current_party_name_, and aselectParty(uuid)method.LoginDialog::onLoginResultgains a new branch after the password-reset check: ifavailable_parties.size() > 1, showPartyPickerDialog(modal, same pattern asChangePasswordDialog). On reject → disconnect, re-enable form. On accept → callclientManager_->selectParty(id).- Main window title set to
username @ party_nameafter 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).