Business logic in the relay handlers (side_effects.rs, ingest.rs, command_executor.rs) is embedded in functions that take &Arc<AppState>, mixing authorization checks with DB calls and notification emission. For example, handle_put_user does: parse event tags → check member role → validate last-owner → check channel_add_policy → call db.add_member → invalidate cache → emit system message → emit discovery events → emit notification. The ownership/role validation logic (last-owner guards, policy enforcement, role-change authorization) can be extracted into pure functions that take data parameters rather than &AppState, making them unit-testable without Postgres or Redis. Same validation is duplicated between WebSocket ingest and HTTP bridge paths. Priority: Medium — improves testability and removes duplication between transport paths.
🤖 AI review update (2026-08-23)
The goal is clear: make authorization decisions independently testable. Start with narrow pure decisions such as last-owner protection, role transitions, and channel-add policy, returning typed decisions/errors while keeping data loading and mutation orchestration outside. Correct the transport premise: HTTP POST /events already enters the same ingest_event path as WebSocket ingestion, so only proven duplication should be removed.
Business logic in the relay handlers (
side_effects.rs,ingest.rs,command_executor.rs) is embedded in functions that take&Arc<AppState>, mixing authorization checks with DB calls and notification emission. For example,handle_put_userdoes: parse event tags → check member role → validate last-owner → check channel_add_policy → call db.add_member → invalidate cache → emit system message → emit discovery events → emit notification. The ownership/role validation logic (last-owner guards, policy enforcement, role-change authorization) can be extracted into pure functions that take data parameters rather than&AppState, making them unit-testable without Postgres or Redis. Same validation is duplicated between WebSocket ingest and HTTP bridge paths. Priority: Medium — improves testability and removes duplication between transport paths.🤖 AI review update (2026-08-23)
The goal is clear: make authorization decisions independently testable. Start with narrow pure decisions such as last-owner protection, role transitions, and channel-add policy, returning typed decisions/errors while keeping data loading and mutation orchestration outside. Correct the transport premise: HTTP POST /events already enters the same ingest_event path as WebSocket ingestion, so only proven duplication should be removed.