Send a notification straight to connected SSE clients (test route)
AUTHENTICATED BY X-API-Key, not by a bearer token — auth.APIKeyMiddleware replaces the usual chain, so none of the RBAC or licence refusals apply and no user context exists. Bypasses the queue and writes to connected clients directly. Recipients are every currently connected SSE client UNIONED with user_ids; supplying user_ids does not exclude connected users. When there are no connected clients AND no user_ids, the route answers 200 {"message": "No connected users to notify"} having done nothing. The body is not validated at all — no struct validator, no field checks.
Authorization
ApiKeyAuth In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Body of both API-key routes. Nothing is validated: there is no struct validator and no field check, so an empty body decodes successfully and is processed.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/notifications/sse" \ -H "Content-Type: application/json" \ -d '{}'{
"message": "Notification sent to all connected users"
}{
"status": 400,
"message": "Failed to serialize data",
"code": "common.failed_to_serialize",
"class": "validation"
}{
"status": 401,
"message": "API key required",
"code": "common.api_key_required",
"class": "business"
}{
"status": 403,
"message": "Invalid API key",
"code": "common.invalid_api_key",
"class": "business"
}{
"status": 429,
"message": "Rate limit for 203.0.113.10 to 8f1d2c34-5b6e-4a70-9c81-2d3e4f5a6b7c exceeded.",
"code": "rate_limits_m.exceeded",
"class": "temporary",
"retryable": true
}{
"status": 500,
"message": "Record not found",
"code": "common.record_not_found",
"class": "business"
}MARKS READ ONLY, AND read IS A PRESENCE FLAG RATHER THAN A VALUE. Whatever the field carries, true or false, the row is written SET read = true, read_at = now(): the service only nil-checks patch.Read and never passes it down, and the storage statement hard-codes the column. There is no way to mark a notification unread through this API — no other route clears the flag. AN ABSENT read FIELD IS A NO-OP THAT STILL ANSWERS 200 null. The service returns (nil, nil) when the decoded patch has no read member, and the handler serialises that nil pointer, so the body is the four bytes null and nothing was written. {} and {"read": null} both do this. Send true; sending false does the same thing.
Opens a text/event-stream connection. NOT a JSON route: the 200 body is a stream, not a document. Frames: an initial `event: open` with data {"message": "Connection established"}; one frame per notification; a `: keepalive` comment every notifications.sse.heartbeat_seconds (default 25, and a non-positive configured value falls back to 25); and, on graceful shutdown, a final `event: close` with data {"reason": "server_shutdown"} that the manager flushes to every connected client BEFORE cancelling them. Treat that frame as "do not reconnect immediately" — it exists so a client can back off instead of retrying into a draining server. On connect the server replays system notifications the client missed, in two passes around registration so the handshake window is not skipped. THIS ROUTE HAS TWO 503 SHAPES AND THE SHUTDOWN MAP IS NEITHER. health.LifecycleMiddleware explicitly SKIPS /v1/notifications/sse, so that map never appears here. See the 503 below for the two that do. ACCESS-CONTROL-ALLOW-ORIGIN IS ECHOED FROM THE REQUEST'S Origin HEADER VERBATIM on the stream itself. The handler's OPTIONS branch, however, is dead code and no preflight ever reaches it: auth.CORSMiddleware is mounted on the root router ahead of everything and answers a preflight carrying an Origin itself — a bodiless 200 when the origin is allowed, 403 when it is not — while a preflight WITHOUT an Origin header falls through to chi, which has only GET and POST registered for this pattern and answers 405.