Context
Current backend and frontend communicates via raw events / raw snapshots sends, which works, but introduces complications when tackling errors. For example, if an event is malformed and raises an Error, the backend closes the WS connection, which is not ideal.
What to do
- Define an atomic upgrade
Both backend and frontend needs to change the way they communicate. A proposed plan is to start on the backend and integrate frontend later on. A proposed protocol:
{
"type": "authenticate",
"access_token": "<Supabase JWT>"
}
{
"type": "command",
"request_id": "4f01c65c-4f0b-4cf7-aa3d-61d4a35b4292",
"event": {
"type": "JoinQueueEvent",
"payload": {}
}
}
{
"type": "state_snapshot",
"state": {
"...": "SessionLiveState"
}
}
{
"type": "command_result",
"request_id": "4f01c65c-4f0b-4cf7-aa3d-61d4a35b4292",
"event_type": "JoinQueueEvent",
"ok": false,
"error": {
"code": "conflict.already_queued",
"message": "This representation is already in the speakers list."
}
}
By upgrading to something like this, we enable better error handling. For a successful event command, the sender receives a command_result and a state_snapshot.
You may need to implement input/output schemas for this.
- Separate errors
Create a session-level base exception. Example hierarchy:
SessionCommandError
- InvalidMoveError
- PermissionDeniedError
- InvalidSchemaError
...
Each error may expose a code string and a message for additional details (as you see on the expected json above). Initial ones can be:
- invalid_schema
- permission_denied
- invalid_move
- internal_error
These may be condensed into an enum ErrorCode that the transport layer may use to match stuff. Base exception then becomes:
class SessionCommandError(Exception):
def __init__(self, code: CommandErrorCode, message: str):
self.code = code
self.message = message
super().__init__(message)
And later exceptions may inherit / compose of this class.
- Catch these errors on transport/view layer (in particular, in the websocket layer)
After raising an error, send an error type message to the socket, but leave the connection open. Sockets should only be disconnected on their own or if an admin kicks/bans them
- Test behaviour.
This will, surely, break existing behavior. We may need to change tests to account for this. I recommend using an AI agent for this.
If possible, add e2e tests to test if malformed/error requests keep ws open but return an error message.
Expected Behaviour
Main one is persisted WebSockets
Context
Current backend and frontend communicates via raw events / raw snapshots sends, which works, but introduces complications when tackling errors. For example, if an event is malformed and raises an Error, the backend closes the WS connection, which is not ideal.
What to do
Both backend and frontend needs to change the way they communicate. A proposed plan is to start on the backend and integrate frontend later on. A proposed protocol:
By upgrading to something like this, we enable better error handling. For a successful event command, the sender receives a
command_resultand astate_snapshot.You may need to implement input/output schemas for this.
Create a session-level base exception. Example hierarchy:
Each error may expose a
codestring and amessagefor additional details (as you see on the expected json above). Initial ones can be:These may be condensed into an enum
ErrorCodethat the transport layer may use to match stuff. Base exception then becomes:And later exceptions may inherit / compose of this class.
After raising an error, send an
errortype message to the socket, but leave the connection open. Sockets should only be disconnected on their own or if an admin kicks/bans themThis will, surely, break existing behavior. We may need to change tests to account for this. I recommend using an AI agent for this.
If possible, add e2e tests to test if malformed/error requests keep ws open but return an error message.
Expected Behaviour
Main one is persisted WebSockets