2026-02-21 16:42:42 -05:00
# Protocol Notes
This is a behavior guide for packet semantics beyond raw schemas.
## Direction
- Client packet schema lives in `server/app/models.py` (`ClientPacket` ).
- Browser-side validation/parsing lives in `client/src/network/protocol.ts` .
- Keep these synchronized on every protocol change.
## Client -> Server
2026-02-24 22:03:10 -05:00
- `auth_register` : create account with username/password and optional email.
- `auth_login` : authenticate with username/password.
- `auth_resume` : resume prior session via stored session token.
- `auth_logout` : revoke current session and disconnect.
2026-02-28 20:58:23 -05:00
- `welcome_ready` : client confirms it accepted `welcome` preflight and is ready to join active roster.
2026-02-27 03:37:20 -05:00
- `admin_roles_list` : request server role list (with user counts + permission sets).
- `admin_role_create` : create role.
- `admin_role_update_permissions` : replace one role permission set.
- `admin_role_delete` : delete role with replacement role reassignment.
2026-02-28 20:06:43 -05:00
- `admin_users_list` : request user list for admin actions (`action` : `set_role | ban | unban | delete_account` ).
2026-02-27 03:37:20 -05:00
- `admin_user_set_role` : set target user role.
- `admin_user_ban` / `admin_user_unban` : disable/enable user account.
2026-02-28 20:06:43 -05:00
- `admin_user_delete` : permanently delete target account.
2026-02-24 19:52:38 -05:00
- `update_position` : client movement intent; server enforces world bounds and movement rate policy.
2026-02-24 20:55:02 -05:00
- `teleport_complete` : client signals teleport landing; server rebroadcasts spatial landing cue.
2026-02-21 16:42:42 -05:00
- `update_nickname` : nickname change request (server enforces uniqueness).
- `chat_message` : player chat.
- `ping` : latency measurement.
- `item_add` , `item_pickup` , `item_drop` , `item_delete` , `item_use` , `item_update` : item actions.
2026-02-28 20:24:37 -05:00
- `item_transfer_targets` : request transfer target accounts for one item (includes online + offline active users, excluding current owner).
2026-02-28 20:26:40 -05:00
- `item_transfer` : transfer item ownership to another account (`targetUserId` required).
2026-02-25 01:11:47 -05:00
- `item_secondary_use` : trigger type-specific secondary action when implemented.
2026-02-22 23:42:17 -05:00
- `item_piano_note` : realtime piano note on/off for active piano use mode.
2026-02-23 00:45:17 -05:00
- `item_piano_recording` : piano record/playback control (`toggle_record` , `playback` , `stop_playback` ).
2026-02-21 16:42:42 -05:00
## Server -> Client
2026-02-24 22:03:10 -05:00
- `auth_required` : authentication challenge after websocket connect.
- `auth_result` : auth success/failure and session/account metadata.
2026-02-27 03:37:20 -05:00
- `auth_permissions` : server-pushed live role/permission refresh for current session.
- `admin_roles_list` : role list response payload.
- `admin_users_list` : user list response payload.
- `admin_action_result` : structured result for admin actions.
2026-02-28 20:06:43 -05:00
- admin mutations include `user_delete` for account deletion.
2026-02-21 19:12:58 -05:00
- `welcome` : initial snapshot with users/items plus server UI/world metadata.
2026-02-28 20:58:23 -05:00
- Server delays roster activation/login broadcast until `welcome_ready` is received.
2026-02-21 16:42:42 -05:00
- `signal` : forwarded WebRTC offer/answer/ICE.
- `update_position` , `update_nickname` , `user_left` : presence updates.
2026-02-24 20:55:02 -05:00
- `teleport_complete` : peer teleport landing event with spatial coordinates.
2026-02-21 16:42:42 -05:00
- `chat_message` : system and user chat stream.
- `pong` : ping response.
- `nickname_result` : accepted/rejected nickname result.
- `item_upsert` : full item replacement after mutation.
- `item_remove` : item deletion.
- `item_action_result` : action success/failure and user-facing message.
2026-02-28 20:24:37 -05:00
- `item_transfer_targets` : transfer target account list for one item.
2026-02-21 16:42:42 -05:00
- `item_use_sound` : spatial one-shot sound on successful item use (if `useSound` configured).
2026-02-27 01:05:23 -05:00
- `item_clock_announce` : ordered list of clock speech samples to play sequentially as spatial audio.
2026-02-22 23:42:17 -05:00
- `item_piano_note` : broadcast piano note on/off with resolved instrument/envelope/spatial params.
2026-02-24 19:56:44 -05:00
- `item_piano_status` : structured piano mode/record/playback state events for client runtime control.
2026-02-21 16:42:42 -05:00
## Item Packet Behavior
- `item_upsert` is full-state replacement for one item, not partial patch.
2026-02-27 02:27:16 -05:00
- `item_upsert.item.display` is server-owned display text for readonly/system properties (for example: `createdBy` , `updatedBy` , `createdAt` , `updatedAt` , `capabilities` , `useSound` , `emitSound` ).
2026-02-21 16:42:42 -05:00
- `item_action_result` messages are intended for direct screen-reader/user status feedback.
2026-02-28 05:11:49 -05:00
- `action` includes: `add` , `pickup` , `drop` , `delete` , `transfer` , `use` , `secondary_use` , `update`
2026-02-27 02:39:25 -05:00
- Successful `item_pickup` and `item_drop` also emit system chat lines to other users in the room.
2026-02-28 20:24:37 -05:00
- Item transfer ownership is account-based; target accounts do not need to be currently connected.
2026-02-24 19:56:44 -05:00
- Piano runtime control no longer depends on parsing `item_action_result.message` text.
- `item_piano_status` carries machine-readable piano events (`use_mode_entered` , record/playback transitions).
2026-02-21 16:42:42 -05:00
- `item_use_sound` contains absolute item world coordinates (`x` , `y` ) and sound path.
2026-02-24 20:34:48 -05:00
- For carried items, source coordinates resolve to the carrier's current position.
2026-02-27 01:05:23 -05:00
- `item_clock_announce` contains:
- `itemId`
- `sounds` : ordered sample URLs (EL640 phrase parts)
- absolute source coordinates `x` , `y`
2026-02-27 02:06:51 -05:00
- generated by server for manual clock `use` , top-of-hour auto announce, and alarm auto announce (when enabled)
2026-02-24 20:55:02 -05:00
- `teleport_complete` contains absolute player world coordinates (`x` , `y` ) at teleport landing.
2026-02-25 00:52:28 -05:00
- Radio metadata (`params.stationName` , `params.nowPlaying` ) is server-managed and delivered through normal `item_upsert` updates.
2026-02-22 23:42:17 -05:00
- `item_piano_note` contains:
- `itemId` , `senderId` , `keyId` , `midi` , `on`
2026-02-23 00:22:36 -05:00
- resolved `instrument` , `voiceMode` , `octave` , `attack` , `decay` , `release` , `brightness` , `emitRange`
2026-02-22 23:42:17 -05:00
- absolute source coordinates `x` , `y`
2026-02-21 16:42:42 -05:00
2026-02-21 19:12:58 -05:00
## Welcome Metadata
2026-02-24 22:03:10 -05:00
- `welcome.auth` : authenticated account identity:
- `authenticated`
- `userId`
- `username`
- `role`
2026-02-27 03:37:20 -05:00
- `permissions`
2026-02-24 22:35:29 -05:00
- `policy` (`usernameMinLength` , `usernameMaxLength` , `passwordMinLength` , `passwordMaxLength` )
- `auth_required.authPolicy` : server auth limits advertised before login/register submit.
- `auth_result.authPolicy` : server auth limits echoed on auth success/failure responses.
2026-02-28 04:29:57 -05:00
- `auth_result.sessionToken` is used by the client to call server HTTP endpoint `GET /auth/session/set` (`Authorization: Bearer <sessionToken>` , `X-Chgrid-Auth-Client: 1` ) so the server can issue `Set-Cookie: chgrid_session_token=...; HttpOnly` .
2026-02-21 19:12:58 -05:00
- `welcome.worldConfig.gridSize` : server-authoritative grid size used by clients for bounds/drawing.
2026-02-24 19:52:38 -05:00
- `welcome.worldConfig.movementTickMs` : server movement-rate window used for client movement pacing.
- `welcome.worldConfig.movementMaxStepsPerTick` : max allowed grid steps per movement window.
- `welcome.player` : server-assigned spawn/current self position at connect time.
2026-02-22 18:20:13 -05:00
- `welcome.serverInfo` : server process identity/version metadata:
- `instanceId` : unique id generated at server startup
- `version` : server package version (or `unknown` fallback)
2026-02-21 19:12:58 -05:00
- `welcome.uiDefinitions` : server-provided item UI definitions:
- `itemTypeOrder` : add-item menu order
2026-02-21 20:47:02 -05:00
- `itemTypes[].tooltip` : item-level tooltip/help text
2026-02-24 18:48:08 -05:00
- `itemTypes[].capabilities` : server-declared actions supported by the type
2026-02-21 19:12:58 -05:00
- `itemTypes[].editableProperties` : editable property keys by item type
2026-02-24 18:48:08 -05:00
- `itemTypes[].propertyMetadata` : property-level metadata (`valueType` , optional `label` , optional `range` , optional `tooltip` , optional `maxLength` , optional `options` , optional `visibleWhen` )
2026-02-28 03:21:55 -05:00
- `itemTypes[].globalProperties` : non-editable global values (`useSound` , `emitSound` , `useCooldownMs` , `emitRange` , `directional` , `emitSoundSpeed` , `emitSoundTempo` , `emitInitialDelay` , `emitLoopDelay` )
2026-03-08 19:35:04 -04:00
- `commandMetadata.mainModeActions` : server-authored labels/tooltips for server-backed main-mode commands used by the client command palette
- `itemManagement.actions` : server-authored labels/tooltips and permission-key metadata for item-management actions (`transfer` , `delete` )
- `adminMenu.actions` : server-authored admin root menu labels/tooltips/ordering for the authenticated user
2026-02-24 02:49:17 -05:00
- Client item UI requires this metadata from the server; there is no fallback item definition map.
2026-02-24 19:57:05 -05:00
- Client property help/type rendering is metadata-driven; it does not infer fallback types/tooltips from hardcoded key heuristics.
2026-02-25 00:52:28 -05:00
- `visibleWhen` supports equality checks and string negation via `!` prefix (example: `{"mediaEffect": "!off"}` ).
2026-02-21 19:12:58 -05:00
2026-02-21 16:42:42 -05:00
## Validation Boundaries
- Server is authoritative for all action validation and normalization.
2026-02-24 19:52:38 -05:00
- Server is authoritative for movement acceptance (bounds + rate/delta checks).
2026-02-24 23:37:10 -05:00
- Server persists account state (last nickname + last position) and restores spawn from that state on auth login/resume.
2026-02-28 04:29:57 -05:00
- Server also supports websocket handshake cookie resume:
- reads `chgrid_session_token` from websocket `Cookie` header
- attempts resume before sending `auth_required`
- exposes `GET /auth/session/clear` to expire the `HttpOnly` cookie (`X-Chgrid-Auth-Client: 1` required)
2026-02-25 00:17:05 -05:00
- Server applies auth hardening before accepting login/register/resume:
- login/register PBKDF2 work runs off the event loop in bounded worker concurrency
- repeated auth failures are rate-limited by IP and IP+identity windows
- auth failures include small randomized response jitter to reduce high-resolution probing
2026-02-21 16:42:42 -05:00
- Client validates incoming packet shapes and applies runtime behavior.
2026-02-27 03:37:20 -05:00
- Server is authoritative for role/permission checks on every privileged packet.
- `voice.send` permission changes are pushed at runtime via `auth_permissions` .
2026-02-24 20:34:48 -05:00
- Sound/media field normalization uses shared server policy helpers:
- `none/off` normalize to empty values
- bare filenames normalize to `sounds/<name>` for sound-reference fields
- media URL-like fields are trimmed/validated consistently
2026-02-21 16:42:42 -05:00
- Client-side item edit validation is convenience only; server remains source of truth.
2026-02-22 18:20:13 -05:00
## Heartbeat/Stale Recovery
- Client sends automatic heartbeat `ping` packets every 10 seconds while connected.
- Heartbeat pings use negative `clientSentAt` ids and are internal (not user-visible ping status).
2026-02-22 18:47:09 -05:00
- If websocket close is observed unexpectedly, client starts reconnect flow.
- If a heartbeat `pong` is missed for one interval (10 seconds), client also starts reconnect flow.
2026-02-22 18:52:06 -05:00
- Reconnect flow waits 5 seconds and retries up to 3 times before stopping.
2026-02-22 18:40:26 -05:00
- After reconnect, if `welcome.serverInfo.instanceId` changed, client announces `Server restarted.`
2026-02-22 18:52:06 -05:00
- Client emits `Connected to server. Version <version>.` on initial `welcome` and
`Reconnected to server. Version <version>.` after reconnect.
2026-02-22 18:40:26 -05:00
- If `welcome.serverInfo.version` differs from running client version, client auto-reloads.