feat(shared-queues): group-keyed queue store + enqueue service + SDK (D3.1)

The producer side of shared durable queues:
- migration 0065 group_queue_messages (mirrors 0034, keyed by (group_id,
  collection); CASCADE on group delete).
- GroupQueueRepo/PostgresGroupQueueRepo: enqueue + the competing-consumer
  claim (FOR UPDATE SKIP LOCKED) + ack/nack/drop_exhausted/reclaim/depth.
- GroupQueueService trait (shared) + GroupQueueServiceImpl: resolve owning
  group (kind='queue') from cx.app_id's chain, require editor+
  (GroupQueueEnqueue, fails closed on anon), size-cap, enqueue.
- SDK: `queue::shared_collection("name")` -> GroupQueueHandle with
  `.enqueue(msg[, opts])` / `.depth()` / `.depth_pending()`; wired through
  Services + the picloud binary.
- authz: Capability::GroupQueueEnqueue(GroupId), editor+ / script:write.

Deterministic test proves competing consumers claim each message exactly
once. Consumption wiring (materialized consumers + dispatcher branch) lands
in D3.2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-02 22:08:21 +02:00
parent 19ba6dbfb4
commit ccd3644aa4
12 changed files with 929 additions and 28 deletions

View File

@@ -20,6 +20,7 @@ pub mod group_docs;
pub mod group_files;
pub mod group_kv;
pub mod group_pubsub;
pub mod group_queue;
pub mod http;
pub mod ids;
pub mod inbox;
@@ -73,6 +74,7 @@ pub use group_docs::{GroupDocsError, GroupDocsService, NoopGroupDocsService};
pub use group_files::{GroupFilesError, GroupFilesService, NoopGroupFilesService};
pub use group_kv::{GroupKvError, GroupKvService, NoopGroupKvService};
pub use group_pubsub::{GroupPubsubError, GroupPubsubService, NoopGroupPubsubService};
pub use group_queue::{GroupQueueError, GroupQueueService, NoopGroupQueueService};
pub use http::{HttpError, HttpRequest, HttpResponse, HttpService, NoopHttpService};
pub use ids::{
AdminUserId, ApiKeyId, AppId, AppUserId, ExecutionId, GroupId, InvitationId, QueueMessageId,