From 01ebe351116f32d8d485491cbdbbbd6c3885ab6a Mon Sep 17 00:00:00 2001 From: Rowan Stein Date: Thu, 26 Feb 2026 01:09:14 +0000 Subject: [PATCH 1/3] feat(notifications): add gRPC contract (v1) --- .../api/notifications/v1/notifications.proto | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 proto/agynio/api/notifications/v1/notifications.proto diff --git a/proto/agynio/api/notifications/v1/notifications.proto b/proto/agynio/api/notifications/v1/notifications.proto new file mode 100644 index 0000000..ebd906d --- /dev/null +++ b/proto/agynio/api/notifications/v1/notifications.proto @@ -0,0 +1,92 @@ +syntax = "proto3"; + +package agynio.api.notifications.v1; + +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +// NotificationsService v1 +// +// Internal notifications contract. Producers publish events; a future +// gateway subscribes and bridges to external transports (e.g., sockets). +service NotificationsService { + // Publish a single notification to rooms. + rpc Publish(PublishRequest) returns (PublishResponse); + + // Publish a batch of notifications; each item returns success or error. + rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse); + + // Subscribe to envelopes filtered by rooms and/or events. + rpc Subscribe(SubscribeRequest) returns (stream SubscribeResponse); +} + +// Envelope emitted to subscribers and used as the canonical notification. +message NotificationEnvelope { + string id = 1; // server-generated UUID v4 + google.protobuf.Timestamp ts = 2; // server-generated acceptance time + string source = 3; // optional origin (e.g., "platform-server") + string event = 4; // stable event name + repeated string rooms = 5; // non-empty list of target rooms + google.protobuf.Struct payload = 6; // JSON payload (event-specific schema) + string trace_id = 7; // optional trace identifier + map attributes = 8; // optional opaque key/value pairs +} + +message PublishRequest { + string event = 1; + repeated string rooms = 2; + google.protobuf.Struct payload = 3; + string source = 4; + string trace_id = 5; + map attributes = 6; +} + +message PublishResponse { + string id = 1; + google.protobuf.Timestamp ts = 2; +} + +message PublishBatchRequest { + repeated PublishRequest items = 1; +} + +message PublishBatchResponse { + repeated PublishResult results = 1; +} + +message PublishResult { + oneof result { + string id = 1; + Error error = 2; + } + google.protobuf.Timestamp ts = 3; // present on success; optional on error +} + +message SubscribeRequest { + repeated string rooms = 1; // must be non-empty + repeated string events = 2; // optional filter (empty = all) + string cursor = 3; // optional resume token +} + +message SubscribeResponse { + NotificationEnvelope envelope = 1; +} + +message Error { + enum Code { + CODE_UNSPECIFIED = 0; + CODE_INVALID_ARGUMENT = 1; + CODE_UNAVAILABLE = 2; + CODE_INTERNAL = 3; + } + Code code = 1; + string message = 2; + google.protobuf.Struct details = 3; +} + +// Stability notes: +// - Event names, room names, and payload shapes remain compatible with +// current consumers. Payload is Struct to preserve existing JSON. +// - Producers set event/rooms/payload; server generates id/ts. +// - Subscribe is for internal gateway usage; filtering may evolve while +// maintaining wire compatibility within v1. From 7dbb246b7d74a8167c13e0d122559b32d7e27b11 Mon Sep 17 00:00:00 2001 From: Rowan Stein Date: Thu, 26 Feb 2026 02:03:30 +0000 Subject: [PATCH 2/3] chore(notifications): drop trace_id and attributes to align with current envelope/publish --- proto/agynio/api/notifications/v1/notifications.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/proto/agynio/api/notifications/v1/notifications.proto b/proto/agynio/api/notifications/v1/notifications.proto index ebd906d..385e9a8 100644 --- a/proto/agynio/api/notifications/v1/notifications.proto +++ b/proto/agynio/api/notifications/v1/notifications.proto @@ -37,7 +37,6 @@ message PublishRequest { repeated string rooms = 2; google.protobuf.Struct payload = 3; string source = 4; - string trace_id = 5; map attributes = 6; } From b00076e28ee07a494744007a53cacefdfd4e7430 Mon Sep 17 00:00:00 2001 From: Rowan Stein Date: Thu, 26 Feb 2026 13:52:00 +0000 Subject: [PATCH 3/3] fix(proto): restore minimal v1 (Publish + Subscribe), remove extras; keep source as string --- .../api/notifications/v1/notifications.proto | 61 ++----------------- 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/proto/agynio/api/notifications/v1/notifications.proto b/proto/agynio/api/notifications/v1/notifications.proto index 385e9a8..1ab06a0 100644 --- a/proto/agynio/api/notifications/v1/notifications.proto +++ b/proto/agynio/api/notifications/v1/notifications.proto @@ -5,18 +5,11 @@ package agynio.api.notifications.v1; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; -// NotificationsService v1 -// -// Internal notifications contract. Producers publish events; a future -// gateway subscribes and bridges to external transports (e.g., sockets). +// NotificationsService v1 (minimal) +// - Publish: producers send events to rooms +// - Subscribe: gateway receives a live stream of envelopes service NotificationsService { - // Publish a single notification to rooms. rpc Publish(PublishRequest) returns (PublishResponse); - - // Publish a batch of notifications; each item returns success or error. - rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse); - - // Subscribe to envelopes filtered by rooms and/or events. rpc Subscribe(SubscribeRequest) returns (stream SubscribeResponse); } @@ -24,12 +17,10 @@ service NotificationsService { message NotificationEnvelope { string id = 1; // server-generated UUID v4 google.protobuf.Timestamp ts = 2; // server-generated acceptance time - string source = 3; // optional origin (e.g., "platform-server") + string source = 3; // origin (e.g., "platform-server") string event = 4; // stable event name - repeated string rooms = 5; // non-empty list of target rooms + repeated string rooms = 5; // target rooms (non-empty) google.protobuf.Struct payload = 6; // JSON payload (event-specific schema) - string trace_id = 7; // optional trace identifier - map attributes = 8; // optional opaque key/value pairs } message PublishRequest { @@ -37,7 +28,6 @@ message PublishRequest { repeated string rooms = 2; google.protobuf.Struct payload = 3; string source = 4; - map attributes = 6; } message PublishResponse { @@ -45,47 +35,8 @@ message PublishResponse { google.protobuf.Timestamp ts = 2; } -message PublishBatchRequest { - repeated PublishRequest items = 1; -} - -message PublishBatchResponse { - repeated PublishResult results = 1; -} - -message PublishResult { - oneof result { - string id = 1; - Error error = 2; - } - google.protobuf.Timestamp ts = 3; // present on success; optional on error -} - -message SubscribeRequest { - repeated string rooms = 1; // must be non-empty - repeated string events = 2; // optional filter (empty = all) - string cursor = 3; // optional resume token -} +message SubscribeRequest {} message SubscribeResponse { NotificationEnvelope envelope = 1; } - -message Error { - enum Code { - CODE_UNSPECIFIED = 0; - CODE_INVALID_ARGUMENT = 1; - CODE_UNAVAILABLE = 2; - CODE_INTERNAL = 3; - } - Code code = 1; - string message = 2; - google.protobuf.Struct details = 3; -} - -// Stability notes: -// - Event names, room names, and payload shapes remain compatible with -// current consumers. Payload is Struct to preserve existing JSON. -// - Producers set event/rooms/payload; server generates id/ts. -// - Subscribe is for internal gateway usage; filtering may evolve while -// maintaining wire compatibility within v1.