1---2name: chatto-api-rules3description: Design rules concerning Chatto's ConnectRPC API, both resources and realtime4---56### ConnectRPC Resource API78- Define one canonical public protobuf for each resource. Reuse that protobuf9 across list, get, batch, and mutation-response surfaces when the10 authorization and lifecycle semantics are the same.11- Keep services complete for their resource and scope. Add bounded batch reads12 when events or related resources commonly expose IDs that clients must13 hydrate.14- Keep commands, explicit reads, pagination, history, and read-your-writes15 responses in ConnectRPC. Realtime delivery does not replace these APIs.16- Resource `Update*` RPCs must use `google.protobuf.FieldMask update_mask`.17 Unselected fields stay unchanged; selected fields can be set or cleared,18 subject to validation. Apply masks before validation. Omitted masks infer19 populated fields; explicit empty masks are invalid. Clients should send20 explicit paths. Commands use specific verbs such as `Set`, `Change`, or21 `Refresh`.2223### Realtime API2425- Cover the complete useful product event surface for integrations, bots, and26 clients. Do not limit the public event catalogue to events used by the27 bundled frontend.28- Use `chatto.core.evt.v1.Event` for durable EVT facts and29 `chatto.core.pubsub.v1.PubSubEvent` for transient NATS Core signals. Use the30 dedicated `chatto.realtime.v1.RealtimeEvent` union and domain payload catalog31 for public delivery. Keep a semantic one-to-one relationship for selected32 public events without importing core payload types into the public schema.33 Client-facing `PubSubEvent` variants should reference public payload types34 directly. Keep the restricted private union as the allow-list for cursorless35 delivery.36- Keep transport concerns in `chatto.realtime.v1` wrappers. Handshakes,37 subscriptions, catch-up, cursors, heartbeats, errors, and close38 guidance are not domain events.39- Create a fresh authorized `RealtimeEvent` for each public delivery. The40 public payload schema must omit internal variants and storage-only fields.41 Never send stored bytes or mutate a stored event during mapping.42- Keep current resources in ConnectRPC. Let a resource client bind reads to an43 opaque realtime start cursor, then close the interval with event catch-up.44 Do not attach resource sidecars to normal event frames.45- Keep public cursors opaque, confidential, integrity-protected, and bound to46 their viewer and scope. Do not expose NATS or JetStream coordinates.47- Keep wire volume bounded. Resume must have sequence, event-count, time, and48 concurrency limits. Large and lazy collections stay in paginated ConnectRPC49 APIs.50- Use consistent product terminology and names. Public comments must not51 depend on backend terms such as projections, NATS, or JetStream.52- Use a new behavioral protocol version when a change requires all clients to53 change their behavior. Do not use a capability matrix to restate required54 frame semantics.55- When an `Event` or `PubSubEvent` variant must reach clients, update the56 dedicated payload, public union member, authorization and mapper coverage,57 consuming reducers, generated clients, architecture inventory, public58 documentation, and compatibility notes in the same change. Keep public names59 and compact union numbers independent from the internal event source. Use60 independent public payload field numbers and explicit typed mapping for EVT.61 Reference the public payload directly from client-facing pubsub variants and62 deep-copy it at the delivery boundary.63- Keep protobuf comments, public API overviews, tutorials, compatibility64 guidance, and release notes current.