From 7cd01df68c164b092b6a441ee99417994b23af00 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Sat, 23 May 2026 04:21:02 -0400 Subject: [PATCH] fix(nats): prefer account tenancy Signed-off-by: Yordis Prieto --- .../skills/nats-design-subject/SKILL.md | 57 +-- .../references/anti-patterns.md | 29 +- .../references/jetstream.md | 102 +++--- .../references/patterns.md | 140 ++++--- .../references/security.md | 346 ++++++++++-------- .../references/use-cases.md | 81 ++-- 6 files changed, 443 insertions(+), 312 deletions(-) diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/SKILL.md b/plugins/trogonstack-nats/skills/nats-design-subject/SKILL.md index 13e44e4..93caa68 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/SKILL.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/SKILL.md @@ -4,11 +4,12 @@ description: >- Design NATS subject hierarchies for messaging patterns (pub/sub, request/reply, streaming). Apply naming conventions, segmentation strategies, and wildcard patterns to create scalable subject architectures. Use when designing NATS - messaging systems, planning multi-tenant communication, or auditing existing - subject hierarchies. Do not use for: (1) NATS server configuration or cluster - setup, (2) client library implementation or connection code, (3) debugging - connectivity or performance issues, (4) choosing between NATS and other - messaging systems. + messaging systems, choosing account-vs-subject namespace boundaries for + multi-tenant communication, designing export/import subjects, or auditing + existing subject hierarchies. Do not use for: (1) NATS server or account + provisioning, (2) cluster setup, (3) client library implementation or + connection code, (4) debugging connectivity or performance issues, (5) + choosing between NATS and other messaging systems. allowed-tools: - AskUserQuestion - Write @@ -18,7 +19,7 @@ allowed-tools: # Design NATS Subject Hierarchy -Design a subject architecture that subscribers can efficiently navigate using wildcards, with proper segment ordering, tenant isolation, and growth path. +Design a subject architecture that subscribers can efficiently navigate using wildcards, with proper segment ordering, account-aware tenant isolation, and growth path. ## Interview Phase @@ -35,14 +36,14 @@ Design a subject architecture that subscribers can efficiently navigate using wi 1. **Scope** — "Is this greenfield design or migrating existing subjects?" - Impact: Migration needs anti-pattern audit first (see [references/anti-patterns.md](references/anti-patterns.md)) -2. **Multi-Tenancy & Scale** — "Do you need: (A) Single tenant, (B) Multi-tenant with isolation, (C) Massive scale with regions/shards?" - - Impact: Determines whether tenant prefix is needed and segmentation depth +2. **Multi-Tenancy & Scale** — "Do you need: (A) Single tenant, (B) Account-per-tenant isolation, (C) Shared account with subject prefixes, (D) Massive scale with regions/shards?" + - Impact: Determines whether tenant identity belongs in the NATS account boundary, the subject, or both 3. **Messaging Patterns** — "Which patterns do you use? (A) Pub/Sub only, (B) Request/Reply, (C) Streaming/JetStream, (D) All/mix?" - Impact: JetStream needs stream-aware subject design; request/reply has its own conventions -4. **Security** — "Do you need subject-based authorization or tenant isolation?" - - Impact: Determines whether tenant/role prefixes are needed and permission boundaries +4. **Security** — "Do you need account-level isolation, subject-based authorization, or both?" + - Impact: Determines account boundaries, exports/imports, tenant prefixes, and permission boundaries 5. **Persistence** — "Do you need JetStream persistence or core NATS only?" - Impact: Determines stream/consumer subject design and retention considerations @@ -52,7 +53,7 @@ Design a subject architecture that subscribers can efficiently navigate using wi ## When to Use - Designing a new NATS messaging system -- Planning multi-tenant subject isolation +- Planning account-aware multi-tenant subject isolation - Organizing device telemetry or event streams - Setting up request/reply patterns across microservices - Defining event subject structure for event-sourced systems @@ -71,7 +72,9 @@ Design a subject architecture that subscribers can efficiently navigate using wi ### 1. Identify Domain Boundaries -List all business domains involved (orders, payments, inventory, etc.). Each domain becomes a top-level subject segment. +List all NATS account boundaries and business domains involved. For strict multi-tenancy, use one account per tenant first; then design short, domain-first subjects inside each account. + +Use subject tenant prefixes only when accounts are intentionally unavailable or when designing a shared/platform surface that must carry tenant provenance. ### 2. Choose a Pattern @@ -81,8 +84,9 @@ Match the user's scenario to a pattern: |----------|---------|---------| | **Simple Domain** | `{domain}.{action}.{scope}` | `orders.created.us-west` | | **Multi-Region** | `{domain}.{action}.{region}.{id}` | `devices.telemetry.us-east.sensor-456` | -| **Multi-Tenant SaaS** | `{tenant}.{domain}.{action}.{id}` | `acme-corp.analytics.processed.report-123` | -| **Multi-Tenant AI** | `agents.{action}.{tenant}.{agent-id}.{task-id}` | `agents.task-assigned.tenant-abc.agent-xyz.task-123` | +| **Multi-Tenant SaaS** | Account per tenant, subjects: `{domain}.{action}.{id}` | `analytics.processed.report-123` in account `acme-corp` | +| **Shared Account Fallback** | `{tenant}.{domain}.{action}.{id}` | `acme-corp.analytics.processed.report-123` | +| **Multi-Tenant AI** | Account per tenant, subjects: `agents.{action}.{agent-id}.{task-id}` | `agents.task-assigned.agent-xyz.task-123` in account `tenant-abc` | | **Request/Reply** | `{service}.request` / `{service}.reply` | `orders.request` / `orders.reply` | | **Event Sourcing** | `{aggregate}.{action}.v{version}.{id}` | `orders.order.created.v1.order-123` | @@ -90,7 +94,7 @@ For full pattern details with subscriber paths and scaling guidance, read [refer ### 3. Order Segments Strategically -Apply these rules when ordering segments left-to-right: +Apply these rules when ordering subject segments left-to-right inside the selected account: - **Broad to specific**: Domain → Action → Scope → Identifier - **Low-cardinality left, high-cardinality right**: Regions (few values) before IDs (millions of values) @@ -127,19 +131,24 @@ Design subjects for subscribers, not publishers. Subscribers determine how you o If the user needs tenant isolation or role-based access: -- Tenant ID as first segment enables subject-based authorization (`acme-corp.>`) -- Separate admin subjects from user operations (`_admin.>` for platform ops) +- Prefer NATS Accounts for tenant isolation; each tenant gets its own subject namespace +- Use exports/imports for cross-account federation instead of assuming cross-tenant visibility +- Use tenant IDs in subjects only for shared-account fallbacks or platform aggregation surfaces +- Separate admin/platform subjects from user operations (`_admin.>` or platform account subjects) - Apply least-privilege permissions per service -For authorization patterns and tenant isolation examples, read [references/security.md](references/security.md). +For account-based tenancy, authorization patterns, and tenant isolation examples, read [references/security.md](references/security.md). ### 6. Design JetStream Streams (if persistence needed) If the user needs JetStream: -- One stream per domain (or per tenant for isolation) +- Treat JetStream streams, consumers, and KV buckets as account-scoped resources +- Reuse stream/KV names across tenant accounts when the topology is identical +- Use one stream per domain inside each tenant account +- Use per-tenant streams in one shared account only as a fallback - Consumer filters for fine-grained routing -- Retention policies per domain (financial: years, telemetry: days) +- Account and domain retention limits (financial: years, telemetry: days) - Keep to 4-6 subject segments — use consumer filters instead of deeper hierarchies For stream design, consumer patterns, and migration from core NATS, read [references/jetstream.md](references/jetstream.md). @@ -167,13 +176,13 @@ Subscriber paths: [Repeat for each domain] ## Multi-Tenancy Model -[How tenant isolation works via subjects, if applicable] +[NATS Accounts, exports/imports, or shared-account subject prefixes] ## Security Model [Authorization rules per role/service, if applicable] ## JetStream Streams -[Stream definitions and consumer filters, if applicable] +[Account-scoped stream definitions and consumer filters, if applicable] ## Quality Validation [Run checklist below] @@ -284,7 +293,7 @@ Don't read all references upfront — use them progressively as the workflow req - [ ] Naming consistent (all lowercase, hyphens, no underscores) - [ ] Documented subscriber wildcard paths for each domain - [ ] No subjects deeper than 6 segments -- [ ] Multi-tenancy isolation is clear (tenant ID positioning documented) +- [ ] Multi-tenancy boundary is clear (account-per-tenant, shared-account prefix fallback, or both) - [ ] Security subjects defined for admin/monitoring access - [ ] No conflicting patterns (e.g., `orders.created.123` vs `orders.123.created`) - [ ] High-cardinality decision documented (why ID placement chosen) @@ -323,7 +332,7 @@ nats server check connection --account ## Reference Documentation - **[Patterns](references/patterns.md)**: 6 hierarchy patterns with subscriber paths and scaling guidance -- **[Anti-Patterns](references/anti-patterns.md)**: 8 common mistakes with detection, fixes, and migration strategies +- **[Anti-Patterns](references/anti-patterns.md)**: common mistakes with detection, fixes, and migration strategies - **[Security & Multi-Tenancy](references/security.md)**: Authorization patterns and tenant isolation - **[JetStream Design](references/jetstream.md)**: Stream filters, consumer subjects, and retention policies - **[Use Cases](references/use-cases.md)**: Complete examples for microservices, IoT, SaaS, event sourcing, agentic AI diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/references/anti-patterns.md b/plugins/trogonstack-nats/skills/nats-design-subject/references/anti-patterns.md index fe2d5e7..a71fef8 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/references/anti-patterns.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/references/anti-patterns.md @@ -577,12 +577,35 @@ Fix: --- +## Anti-Pattern 13: Subject Prefix as Primary Tenant Boundary + +Using `{tenant}.>` as the main isolation boundary in a system that needs strict multi-tenancy leaves all tenants in one subject namespace. A bad permission pattern or broad service credential can leak data across tenants. + +**Principle**: Use NATS Accounts as the tenant boundary when isolation, account-scoped auth, native quotas, JetStream, or KV matter. Use tenant subject prefixes only for shared-account fallbacks or platform/export subjects that need tenant provenance. + +``` +✗ RISKY DEFAULT: + acme-corp.a2a.gateway.support-bot.message.send + startup-inc.a2a.gateway.support-bot.message.send + → Both tenants share one account and depend on ACL correctness + +✓ BETTER: + account acme-corp: a2a.gateway.support-bot.message.send + account startup-inc: a2a.gateway.support-bot.message.send + → Same subject, separate account namespaces +``` + +**Prevention**: Before adding a tenant token to the subject, decide whether the tenant should be a NATS account. If cross-tenant discovery, audit, or federation is required, model it with explicit exports/imports and platform-account subjects. + +--- + ## Anti-Pattern Prevention **In Code Review, Check For**: ``` -✓ All subjects start with domain -✓ Action/event type is always L2 (or L3 for multi-tenant) +✓ Subjects start with domain inside tenant accounts +✓ Tenant tokens appear only for shared-account fallbacks or platform/export subjects +✓ Action/event type is always L2 unless a fixed namespace token is required ✓ No IDs or UUIDs before action/scope ✓ Consistent casing (lowercase) and separators (hyphens) ✓ Max 5-6 segments per subject @@ -603,5 +626,5 @@ Fix: ✓ Do any wildcard pairs overlap for any realistic ID value? ✓ Can I subscribe per-session/per-entity for affinity routing? ✓ Can NATS permissions cleanly separate read/write per direction? +✓ If this is multi-tenant, did I choose Accounts before subject prefixes? ``` - diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/references/jetstream.md b/plugins/trogonstack-nats/skills/nats-design-subject/references/jetstream.md index 8697d6e..27f9913 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/references/jetstream.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/references/jetstream.md @@ -125,70 +125,77 @@ consumer: { --- -## Pattern 3: Multi-Tenant Streams +## Pattern 3: Account-Scoped Multi-Tenant Streams -**Use when**: Multi-tenant SaaS, separate streams per tenant, complete isolation. +**Use when**: Multi-tenant SaaS, strict tenant isolation, account-scoped JetStream/KV, per-tenant limits, or identical stream topology across tenants. + +Prefer one NATS account per tenant. Streams and KV buckets are account-scoped, so each tenant can reuse the same stream names without putting the tenant into every subject. **Stream Naming**: ```nats +# Account: acme-corp stream: { - name: "tenant-acme-corp" # One stream per tenant - subjects: ["acme-corp.>"] + name: "orders" + subjects: ["orders.>"] } +# Account: startup-inc stream: { - name: "tenant-startup-inc" - subjects: ["startup-inc.>"] + name: "orders" + subjects: ["orders.>"] } +# Account: big-enterprise stream: { - name: "tenant-big-enterprise" - subjects: ["big-enterprise.>"] + name: "orders" + subjects: ["orders.>"] } ``` **Subjects**: ``` -# Tenant A -acme-corp.orders.created.us-west.order-123 -acme-corp.payments.authorized.us-west.payment-456 +# Tenant A account +orders.created.us-west.order-123 +payments.authorized.us-west.payment-456 -# Tenant B -startup-inc.orders.created.eu-central.order-789 -startup-inc.payments.authorized.eu-central.payment-101 +# Tenant B account +orders.created.eu-central.order-789 +payments.authorized.eu-central.payment-101 -# Tenant C -big-enterprise.orders.created.us-east.order-abc -big-enterprise.payments.authorized.us-east.payment-def +# Tenant C account +orders.created.us-east.order-abc +payments.authorized.us-east.payment-def ``` **Consumers (Tenant-Scoped)**: ```nats -# Tenant A - Orders only -stream: "tenant-acme-corp" +# Tenant A account - Orders only +stream: "orders" consumer: { - name: "acme-orders-consumer" - filter_subject: "acme-corp.orders.>" + name: "orders-consumer" + filter_subject: "orders.>" } -# Tenant B - Payments only -stream: "tenant-startup-inc" +# Tenant B account - Orders only +stream: "orders" consumer: { - name: "startup-payments-consumer" - filter_subject: "startup-inc.payments.>" + name: "orders-consumer" + filter_subject: "orders.>" } ``` **Advantages**: -- Complete tenant isolation +- Complete account-level tenant isolation - Different retention per tenant - Different redundancy per tenant +- Native account resource limits - Easy to add/remove tenants - Per-tenant backups **Scaling Considerations**: -- With 100 tenants = 100 streams (scalable with modern hardware) -- With 1000 tenants = consider sharding or hierarchical streams +- With 100 tenants and one `orders` stream each = 100 account-scoped stream instances +- With 1000 tenants = consider account placement, sharding, and account resource limits +- Use shared-account tenant prefixes only when account-per-tenant is not available --- @@ -352,22 +359,24 @@ Output: orders.region-eu-central.created.order-456 ## Pattern 7: Multi-Tenant Stream Isolation -**Scenario**: SaaS with multi-tenant streams where subjects are tenant-prefixed. +**Scenario**: SaaS with strict tenant isolation and a repeated stream topology per tenant. **Stream Design**: ```nats -# Option A: One stream per tenant (recommended) +# Recommended: same stream names in separate tenant accounts +# Account: acme-corp stream: { - name: "tenant-acme-corp" - subjects: ["acme-corp.>"] # All acme events + name: "orders" + subjects: ["orders.>"] } +# Account: startup-inc stream: { - name: "tenant-startup-inc" - subjects: ["startup-inc.>"] + name: "orders" + subjects: ["orders.>"] } -# Option B: Single stream, multiple tenants +# Fallback: one shared account with tenant-prefixed subjects stream: { name: "all-tenants" subjects: [ @@ -378,16 +387,17 @@ stream: { } ``` -**Consumer (Option A - Recommended)**: +**Consumer (Recommended)**: ```nats -stream: "tenant-acme-corp" +# Connected to account acme-corp +stream: "orders" consumer: { - name: "acme-orders" - filter_subject: "acme-corp.orders.>" + name: "order-created" + filter_subject: "orders.created.>" } ``` -**Consumer (Option B - Less Recommended)**: +**Consumer (Fallback)**: ```nats stream: "all-tenants" consumer: { @@ -396,11 +406,14 @@ consumer: { } ``` -**Recommendation**: Option A (one stream per tenant) is better: -- Easier scaling -- Tenant isolation +**Recommendation**: Account-scoped streams are better: +- Account-level isolation +- Native account limits +- Same stream/KV names per tenant account - Different retention per tenant -- Better disaster recovery +- Better disaster recovery and account movement + +Use the shared-account fallback only when NATS Accounts are not available or when a platform projection intentionally combines tenants. --- @@ -594,4 +607,3 @@ Consumer: filter_subject: "orders.created.>" ``` **No subject changes needed** if your subjects are well-designed! - diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/references/patterns.md b/plugins/trogonstack-nats/skills/nats-design-subject/references/patterns.md index 837e6bd..4798f08 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/references/patterns.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/references/patterns.md @@ -61,49 +61,63 @@ orders.>.us-west.> # All order actions in US West (less efficient) --- -## Pattern 3: Multi-Tenant Pattern (4-6 Segments) +## Pattern 3: Account-Scoped Multi-Tenant Pattern -**Use when**: SaaS platform, multi-tenant app, shared infrastructure. +**Use when**: SaaS platform, multi-tenant app, strict tenant isolation, account-scoped auth, account-scoped JetStream/KV, or native quota boundaries. + +Prefer one NATS account per tenant. Subjects inside each tenant account stay short because the account is the isolation boundary. ``` -{tenant}.{domain}.{action}.{id} +Account: {tenant} +Subject: {domain}.{action}.{id} Examples: -- acme-corp.orders.created.order-123 -- acme-corp.orders.updated.order-456 -- startup-inc.analytics.processed.report-789 -- startup-inc.users.registered.user-101 +- account acme-corp: orders.created.order-123 +- account acme-corp: orders.updated.order-456 +- account startup-inc: analytics.processed.report-789 +- account startup-inc: users.registered.user-101 ``` **Subscriber Paths**: ```nats -acme-corp.> # All events for tenant (admin dashboard) -acme-corp.orders.> # All order events for tenant -acme-corp.orders.created.> # All order creations for tenant +> # All events in the connected tenant account +orders.> # All order events in this tenant account +orders.created.> # All order creations in this tenant account ``` **Authorization** (with NATS auth): ``` User from acme-corp: - Publish: acme-corp.> - Subscribe: acme-corp.> + Account: acme-corp + Publish: orders.>, analytics.>, users.> + Subscribe: orders.>, analytics.>, users.> User from startup-inc: - Publish: startup-inc.> - Subscribe: startup-inc.> + Account: startup-inc + Publish: orders.>, analytics.>, users.> + Subscribe: orders.>, analytics.>, users.> -Admin user: - Publish: > - Subscribe: > +Platform analytics: + Import explicit streams/services from tenant accounts + Publish aggregate results to a platform account subject ``` **Best For**: Multi-tenant SaaS, white-label platforms, shared NATS clusters. -**Variation with Region** (5 segments): +**Variation with Region**: +``` +{domain}.{action}.{region}.{id} + +orders.created.us-west.order-123 ``` -{tenant}.{domain}.{action}.{region}.{id} -acme-corp.orders.created.us-west.order-123 +**Shared Account Fallback**: + +Use a tenant prefix only when all tenants intentionally share one NATS account or when an exported/platform subject needs tenant provenance. + +``` +{tenant}.{domain}.{action}.{id} +acme-corp.orders.created.order-123 ``` --- @@ -243,22 +257,33 @@ shipping.{action}.{id} --- -### Strategy 2: Tenant-Based (Multi-Tenancy) +### Strategy 2: Account-Based (NATS Multi-Tenancy) -Organize by tenant with domains nested: +Organize tenants as NATS accounts. Keep tenant identity out of normal subjects inside the tenant account: ``` -{tenant}.{domain}.{action}.{id} +Account: acme-corp +orders.{action}.{id} +payments.{action}.{id} +inventory.{action}.{id} ``` -**When**: SaaS platforms, multi-tenant apps. +**When**: SaaS platforms, multi-tenant apps, strict isolation, per-tenant JetStream/KV, native quotas. **Subscribers**: -- `acme-corp.>` - All events for ACME Corp -- `acme-corp.orders.>` - ACME Corp orders -- `startup-inc.orders.>` - StartUp Inc orders +- `>` - All events visible in the connected account +- `orders.>` - Orders in the connected account +- `payments.>` - Payments in the connected account + +**Authorization**: NATS account identity provides the tenant boundary. Use subject permissions inside the account for least privilege. + +**Shared Account Fallback**: + +``` +{tenant}.{domain}.{action}.{id} +``` -**Authorization**: Tenant prefix enables subject-based auth. +Use this only when account-per-tenant is not available or for exported/platform subjects that must encode tenant provenance. --- @@ -374,22 +399,24 @@ Regional Dashboard (EU): >.eu-central.> ### Multi-Tenant SaaS Platform -Combines: Tenant-based + Domain-based + Regional +Combines: Account-based tenancy + domain-based + regional ``` -acme-corp.orders.created.us-west.order-123 -acme-corp.analytics.processed.report-456 -startup-inc.orders.created.eu-central.order-789 -startup-inc.analytics.processed.report-101 +Account acme-corp: +orders.created.us-west.order-123 +analytics.processed.report-456 + +Account startup-inc: +orders.created.eu-central.order-789 +analytics.processed.report-101 ``` **Subscribers**: ``` -ACME Corp Admin Dashboard: acme-corp.> -StartUp Inc Admin: startup-inc.> -Orders Service: >.orders.> -Analytics Service: >.analytics.> -Regional Monitor (US West): >.>.us-west.> +Tenant Admin Dashboard: > +Orders Service: orders.> +Analytics Service: analytics.> +Regional Monitor (US West): orders.*.us-west.> ``` --- @@ -432,29 +459,33 @@ Filter: devices.telemetry.>.sensor-456.> ### Multi-Tenant Agentic AI Platform -Combines: Tenant-based + Agent-centric + Task-based +Combines: Account-based tenancy + agent-centric + task-based subjects ``` -agents.task-assigned.tenant-abc.agent-xyz.task-123 -agents.task-completed.tenant-abc.agent-xyz.task-123 -agents.capabilities.tenant-abc.llm-agent -agents.collaborate.tenant-abc.session-456.agent-xyz -platform.monitoring.all-tenants.agent-health -platform.monitoring.tenant-abc.agent-metrics +Account: tenant-abc +agents.task-assigned.agent-xyz.task-123 +agents.task-completed.agent-xyz.task-123 +agents.capabilities.llm-agent +agents.collaborate.session-456.agent-xyz + +Platform account: +monitoring.all-tenants.agent-health +monitoring.tenant-abc.agent-metrics ``` **Subscribers**: ``` -AI Agent (xyz) for tenant-abc: agents.>.tenant-abc.agent-xyz.> -All agents in tenant-abc: agents.>.tenant-abc.> -Platform Monitor: platform.monitoring.> -LLM agent capability discovery: agents.capabilities.tenant-abc.llm-agent +AI Agent (xyz) in tenant account: agents.*.agent-xyz.> +All tenant agents: agents.> +Platform Monitor: monitoring.> +LLM agent capability discovery: agents.capabilities.llm-agent ``` -**Security via Subjects**: -- Tenant A's agents: `agents.>.tenant-a.>` (cannot see tenant-b) -- Tenant B's agents: `agents.>.tenant-b.>` (cannot see tenant-a) -- Admin monitor: `platform.monitoring.>` +**Security via Accounts**: +- Tenant A's agents connect to tenant-a account +- Tenant B's agents connect to tenant-b account +- Platform monitoring imports explicit streams/services from tenant accounts +- Tenant IDs appear only on platform/export subjects that aggregate across accounts --- @@ -464,8 +495,7 @@ LLM agent capability discovery: agents.capabilities.tenant-abc.llm-agent |---------|----------|-----------|-------------|--------------| | Simple | Learning, single domain | Low | 100k events/sec | Good | | Multi-Region | Global systems | Medium | 1M+ events/sec | Good | -| Multi-Tenant | SaaS, shared infra | Medium-High | 1M+ events/sec | Excellent | +| Multi-Tenant | SaaS, account isolation | Medium-High | 1M+ events/sec | Excellent | | Request/Reply | Sync services | Low | 10k req/sec | Good | | Event Sourcing | CQRS, event-sourced | Medium | 100k events/sec | Good | | Temporal | IoT, time-series | High | 10M+ events/sec | Good | - diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/references/security.md b/plugins/trogonstack-nats/skills/nats-design-subject/references/security.md index 467b650..4bd2296 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/references/security.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/references/security.md @@ -1,9 +1,20 @@ -# NATS Subject-Based Security and Multi-Tenancy +# NATS Accounts, Subject-Based Security, and Multi-Tenancy -This reference covers authorization patterns, tenant isolation, and security best practices using NATS subject hierarchies. +This reference covers account-based tenant isolation, subject authorization, and security best practices for NATS subject hierarchies. **Related references**: For subject hierarchy patterns see [patterns.md](patterns.md). For JetStream stream-level isolation see [jetstream.md](jetstream.md). For common security mistakes see [anti-patterns.md](anti-patterns.md). +## Account-First Rule + +NATS Accounts are the native multi-tenancy boundary. Each account has its own subject namespace, users, account-scoped JetStream resources, and resource limits. Cross-account traffic should be explicit through exports/imports. + +Use account-per-tenant when the system needs strict tenant isolation, account-scoped auth/JWTs, native quotas, tenant-local JetStream streams, or tenant-local KV buckets. + +Use tenant prefixes in subjects only when: +- All tenants intentionally share one NATS account +- A platform/export subject needs tenant provenance after data leaves the tenant account +- A migration cannot introduce accounts yet + ## Subject-Based Authorization Basics NATS authorization works by allowing/denying subjects via permissions. Your subject hierarchy directly enables or blocks access. @@ -40,75 +51,111 @@ Matches: --- -## Pattern 1: Tenant Isolation with Prefix +## Pattern 1: Tenant Isolation with NATS Accounts (Default) -**Subject Format**: +**Account and Subject Format**: ``` -{tenant}.{domain}.{action}.{scope}.{id} +Account: {tenant} +Subject: {domain}.{action}.{scope}.{id} ``` **Examples**: ``` -acme-corp.orders.created.us-west.order-123 -acme-corp.orders.shipped.us-west.order-456 -startup-inc.orders.created.eu-central.order-789 -startup-inc.payments.authorized.eu-central.payment-101 +Account acme-corp: +orders.created.us-west.order-123 +orders.shipped.us-west.order-456 +payments.authorized.us-west.payment-101 + +Account startup-inc: +orders.created.eu-central.order-789 +payments.authorized.eu-central.payment-101 ``` **Authorization Configuration**: ```nats -# ACME Corp user +# ACME Corp user in account acme-corp user acme-admin { username: "admin@acme-corp.com" permissions { publish { - allow: ["acme-corp.>"] # Can only publish to own tenant + allow: ["orders.>", "payments.>"] } subscribe { - allow: ["acme-corp.>"] # Can only subscribe to own tenant + allow: ["orders.>", "payments.>"] } } } -# StartUp Inc user +# StartUp Inc user in account startup-inc user startup-admin { username: "admin@startup-inc.com" permissions { publish { - allow: ["startup-inc.>"] # Can only publish to own tenant + allow: ["orders.>", "payments.>"] } subscribe { - allow: ["startup-inc.>"] # Can only subscribe to own tenant + allow: ["orders.>", "payments.>"] } } } -# Platform admin (multi-tenant) +# Platform admin lives in a platform account and imports only approved tenant exports user platform-admin { username: "platform-admin" permissions { publish { - allow: [">"] # Can publish anywhere + allow: ["monitoring.>", "analytics.>"] } subscribe { - allow: [">"] # Can subscribe anywhere + allow: ["monitoring.>", "analytics.>"] } } } ``` -**Effectiveness**: ✓ Excellent. Complete tenant isolation with prefix-based auth. +**Effectiveness**: Excellent. Account-level isolation means tenant subjects are not globally visible. **Pros**: -- Simple to understand -- Direct authorization mapping +- Stronger isolation than subject prefixes +- Shorter tenant-local subjects +- Account-scoped users, JWTs, JetStream, KV, and quotas - Built on NATS native permissions -- Easy to add/remove tenants +- Cross-tenant traffic is opt-in through exports/imports **Cons**: -- Admin operations need separate subjects (see Pattern 3) -- Cross-tenant analytics harder (see Pattern 3) +- Requires account lifecycle management +- Cross-tenant analytics/federation needs explicit exports/imports +- Shared platform services must define import/export contracts + +--- + +## Pattern 1b: Shared Account Tenant Prefix (Fallback) + +**Use when**: Account-per-tenant is unavailable, or a shared/platform account needs tenant provenance in subjects. + +**Subject Format**: +``` +{tenant}.{domain}.{action}.{scope}.{id} +``` + +**Examples**: +``` +acme-corp.orders.created.us-west.order-123 +startup-inc.orders.created.eu-central.order-789 +``` + +**Authorization**: +```nats +user acme-user { + permissions { + publish { allow: ["acme-corp.>"] } + subscribe { allow: ["acme-corp.>"] } + } +} +``` + +**Effectiveness**: Useful fallback, but weaker than accounts because all tenants still share one subject namespace. --- @@ -116,50 +163,50 @@ user platform-admin { **Subject Format**: ``` -{tenant}.{role}.{domain}.{action}.{scope}.{id} +{role}.{domain}.{action}.{scope}.{id} ``` **Examples**: ``` -acme-corp.admin.orders.created.us-west.order-123 -acme-corp.user.orders.status.us-west.order-456 -acme-corp.service.orders.shipped.us-west.order-789 +admin.orders.created.us-west.order-123 +user.orders.status.us-west.order-456 +service.orders.shipped.us-west.order-789 ``` **Authorization**: ```nats -# Admin user (full access within tenant) +# Admin user (full access within connected account) user acme-admin { permissions { publish { - allow: ["acme-corp.admin.>", "acme-corp.user.>"] + allow: ["admin.>", "user.>"] } subscribe { - allow: ["acme-corp.admin.>", "acme-corp.user.>"] + allow: ["admin.>", "user.>"] } } } -# Regular user (limited to user tier) +# Regular user (limited to user tier in connected account) user acme-user { permissions { publish { - allow: ["acme-corp.user.orders.>"] # Only user-level order operations + allow: ["user.orders.>"] } subscribe { - allow: ["acme-corp.user.orders.>"] + allow: ["user.orders.>"] } } } -# Internal service (full access) +# Internal service (full access in connected account) user acme-service { permissions { publish { - allow: ["acme-corp.service.>"] + allow: ["service.>"] } subscribe { - allow: ["acme-corp.>"] # Subscribe to all tiers + allow: [">"] } } } @@ -175,66 +222,67 @@ user acme-service { **Cons**: - More complex subject hierarchy (6-7 segments) - Harder for subscribers to navigate (see Anti-Pattern 3 in anti-patterns.md) +- Often better modeled as account users and permissions without putting role in the subject --- -## Pattern 3: Separate Admin Subjects for Multi-Tenancy +## Pattern 3: Separate Platform/Admin Subjects **Subject Format**: ``` -# Tenant-scoped (normal operations) -{tenant}.{domain}.{action}.{scope}.{id} +# Tenant account (normal operations) +{domain}.{action}.{scope}.{id} -# Admin/monitoring (platform-wide, separate root) +# Platform account (monitoring/audit after import/export) _admin.{operation}.{tenant}.{resource}.{details} -platform.monitoring.{tenant}.{metric} +monitoring.{tenant}.{metric} ``` **Examples**: ``` -# User-facing operations -acme-corp.orders.created.us-west.order-123 -startup-inc.orders.shipped.eu-central.order-456 +# User-facing operations in tenant accounts +account acme-corp: orders.created.us-west.order-123 +account startup-inc: orders.shipped.eu-central.order-456 -# Admin operations (monitoring, platform ops) +# Platform operations in platform account _admin.audit.acme-corp.orders.created.order-123 _admin.audit.startup-inc.orders.shipped.order-456 -platform.monitoring.acme-corp.event-count -platform.monitoring.startup-inc.event-latency +monitoring.acme-corp.event-count +monitoring.startup-inc.event-latency ``` **Authorization**: ```nats -# Tenant user (normal operations only) +# Tenant user in account acme-corp (normal operations only) user acme-user { permissions { publish { - allow: ["acme-corp.>"] + allow: ["orders.>"] } subscribe { - allow: ["acme-corp.>"] + allow: ["orders.>"] } } } -# Platform admin (admin and monitoring only) +# Platform admin in platform account (admin and monitoring only) user platform-admin { permissions { publish { - allow: ["_admin.>", "platform.monitoring.>"] + allow: ["_admin.>", "monitoring.>"] } subscribe { - allow: ["_admin.>", "platform.monitoring.>"] + allow: ["_admin.>", "monitoring.>"] } } } -# System service (publishes audit logs and metrics) +# System service in platform account (publishes audit logs and metrics) user system-service { permissions { publish { - allow: ["_admin.>", "platform.monitoring.>"] + allow: ["_admin.>", "monitoring.>"] } subscribe { allow: [] @@ -249,10 +297,11 @@ user system-service { - Tenant subjects remain simple (4-5 segments) - Admin operations completely separate - Platform observability isolated +- Tenant accounts do not need broad platform-admin credentials **Cons**: - Two parallel subject hierarchies to maintain -- Audit trails in separate subjects from operations +- Exports/imports or mirror/source topology must be maintained --- @@ -262,19 +311,19 @@ user system-service { **Subject Format**: ``` -# Tenant-specific operations -{tenant}.{domain}.{action}.{scope}.{id} +# Tenant account operations +{domain}.{action}.{scope}.{id} -# Analytics aggregation (admin-only) +# Platform account analytics aggregation (admin-only) analytics.all-tenants.{metric}.{dimension} analytics.{tenant}.{metric}.{dimension} ``` **Examples**: ``` -# User operations (tenant-isolated) -acme-corp.orders.created.us-west.order-123 -startup-inc.orders.created.eu-central.order-789 +# User operations in tenant accounts +account acme-corp: orders.created.us-west.order-123 +account startup-inc: orders.created.eu-central.order-789 # Analytics (aggregated) analytics.all-tenants.total-orders.created @@ -291,8 +340,8 @@ analytics.all-tenants.top-customers.by-spend ┌─────────────────────────────┐ │ Tenant Events │ ├─────────────────────────────┤ -│ acme-corp.orders.created.> │ -│ startup-inc.orders.created >│ +│ acme-corp account: orders.>│ +│ startup account: orders.> │ └────────────┬────────────────┘ │ (read) ┌─────┴──────┐ @@ -316,9 +365,7 @@ user aggregator-service { allow: ["analytics.>"] # Write to analytics } subscribe { - allow: ["acme-corp.orders.>", - "startup-inc.orders.>", - "other-tenant.orders.>"] # Read all tenant order events + allow: ["orders.>"] # In each imported tenant stream scope } } } @@ -369,93 +416,95 @@ user platform-admin { **Subject Format**: ``` -agents.{action}.{tenant}.{agent-id}.{details} -agents.capabilities.{tenant}.{agent-type} -agents.collaborate.{tenant}.{session}.{agent-id} -platform.monitoring.all-tenants.agent-health -platform.monitoring.{tenant}.agent-metrics +Tenant account: +agents.{action}.{agent-id}.{details} +agents.capabilities.{agent-type} +agents.collaborate.{session}.{agent-id} + +Platform account: +monitoring.all-tenants.agent-health +monitoring.{tenant}.agent-metrics ``` **Examples**: ``` -# Agent operations (tenant-isolated) -agents.task-assigned.tenant-acme.agent-llm-1.task-abc -agents.task-completed.tenant-acme.agent-llm-1.task-abc -agents.task-assigned.tenant-startup.agent-code-1.task-xyz -agents.task-completed.tenant-startup.agent-code-1.task-xyz +# Tenant ACME account +agents.task-assigned.agent-llm-1.task-abc +agents.task-completed.agent-llm-1.task-abc -# Capability discovery (tenant-scoped) -agents.capabilities.tenant-acme.llm -agents.capabilities.tenant-acme.code -agents.capabilities.tenant-startup.llm +# Tenant Startup account +agents.task-assigned.agent-code-1.task-xyz +agents.task-completed.agent-code-1.task-xyz -# Agent collaboration (within tenant) -agents.collaborate.tenant-acme.session-123.agent-llm-1 -agents.collaborate.tenant-acme.session-123.agent-code-1 +# Capability discovery and collaboration inside a tenant account +agents.capabilities.llm +agents.capabilities.code +agents.collaborate.session-123.agent-llm-1 +agents.collaborate.session-123.agent-code-1 -# Platform monitoring (admin only) -platform.monitoring.all-tenants.agent-health -platform.monitoring.all-tenants.task-success-rate -platform.monitoring.tenant-acme.agent-metrics -platform.monitoring.tenant-acme.error-rate +# Platform monitoring after explicit imports +monitoring.all-tenants.agent-health +monitoring.all-tenants.task-success-rate +monitoring.tenant-acme.agent-metrics +monitoring.tenant-acme.error-rate ``` **Authorization**: ```nats -# Agent in Tenant A (complete isolation) +# Agent in Tenant A account user agent-tenant-acme { permissions { publish { - allow: ["agents.task-assigned.tenant-acme.>", - "agents.task-completed.tenant-acme.>", - "agents.collaborate.tenant-acme.>"] + allow: ["agents.task-assigned.>", + "agents.task-completed.>", + "agents.collaborate.>"] } subscribe { - allow: ["agents.task-assigned.tenant-acme.>", - "agents.task-completed.tenant-acme.>", - "agents.capabilities.tenant-acme.>", - "agents.collaborate.tenant-acme.>"] + allow: ["agents.task-assigned.>", + "agents.task-completed.>", + "agents.capabilities.>", + "agents.collaborate.>"] } } } -# Agent in Tenant B (isolated from Tenant A) +# Agent in Tenant B account; same subject permissions, different account boundary user agent-tenant-startup { permissions { publish { - allow: ["agents.task-assigned.tenant-startup.>", - "agents.task-completed.tenant-startup.>", - "agents.collaborate.tenant-startup.>"] + allow: ["agents.task-assigned.>", + "agents.task-completed.>", + "agents.collaborate.>"] } subscribe { - allow: ["agents.task-assigned.tenant-startup.>", - "agents.task-completed.tenant-startup.>", - "agents.capabilities.tenant-startup.>", - "agents.collaborate.tenant-startup.>"] + allow: ["agents.task-assigned.>", + "agents.task-completed.>", + "agents.capabilities.>", + "agents.collaborate.>"] } } } -# Platform monitoring (admin) +# Platform monitoring in platform account user platform-monitor { permissions { publish { - allow: ["platform.monitoring.>"] + allow: ["monitoring.>"] } subscribe { - allow: ["platform.monitoring.>"] + allow: ["monitoring.>"] } } } -# System orchestrator (manages agents) +# System orchestrator in one tenant account; cross-tenant orchestration uses exports/imports user system-orchestrator { permissions { publish { - allow: ["agents.>", "platform.monitoring.>"] + allow: ["agents.>"] } subscribe { - allow: ["agents.>", "platform.monitoring.>"] + allow: ["agents.>"] } } } @@ -464,17 +513,17 @@ user system-orchestrator { **Security Model**: ``` Tenant A Agents: -✓ Can publish/subscribe to: agents.*.tenant-acme.> -✗ Cannot see: agents.*.tenant-startup.> -✗ Cannot see: platform.monitoring.> +✓ Can publish/subscribe to: agents.> in tenant-a account +✗ Cannot see tenant-b account subjects +✗ Cannot see platform monitoring account unless explicitly imported Tenant B Agents: -✓ Can publish/subscribe to: agents.*.tenant-startup.> -✗ Cannot see: agents.*.tenant-acme.> -✗ Cannot see: platform.monitoring.> +✓ Can publish/subscribe to: agents.> in tenant-b account +✗ Cannot see tenant-a account subjects +✗ Cannot see platform monitoring account unless explicitly imported Platform Admin: -✓ Can see all agent activity +✓ Can see explicitly exported agent activity ✓ Can see metrics and health ✓ Cannot directly control agents (separate admin service) ``` @@ -482,15 +531,14 @@ Platform Admin: **Effectiveness**: ✓ Excellent for agentic AI platforms. **Pros**: -- Complete tenant isolation at subject level +- Complete tenant isolation at account level - Platform visibility without tenant access - Inter-agent collaboration within tenant - Scales to many agents and tenants **Cons**: -- More complex subject hierarchy -- Requires careful permission management -- Audit trail needs separate subjects +- Requires account and export/import lifecycle management +- Audit trail needs platform account subjects --- @@ -498,32 +546,33 @@ Platform Admin: **Scenario**: Single NATS cluster serves dev, staging, and production. Complete isolation needed. -**Subject Format**: +**Account and Subject Format**: ``` -{environment}.{tenant}.{domain}.{action}.{scope}.{id} +Account: {environment}.{tenant} +Subject: {domain}.{action}.{scope}.{id} ``` **Examples**: ``` -dev.acme-corp.orders.created.us-west.order-123 -staging.acme-corp.orders.created.us-west.order-456 -prod.acme-corp.orders.created.us-west.order-789 +account dev.acme-corp: orders.created.us-west.order-123 +account staging.acme-corp: orders.created.us-west.order-456 +account prod.acme-corp: orders.created.us-west.order-789 -dev.startup-inc.orders.created.eu-central.order-abc -staging.startup-inc.orders.created.eu-central.order-def -prod.startup-inc.orders.created.eu-central.order-ghi +account dev.startup-inc: orders.created.eu-central.order-abc +account staging.startup-inc: orders.created.eu-central.order-def +account prod.startup-inc: orders.created.eu-central.order-ghi ``` **Authorization**: ```nats -# Dev team (dev environment only) +# Dev team connects to dev accounts only user dev-team { permissions { publish { - allow: ["dev.>"] + allow: [">"] } subscribe { - allow: ["dev.>"] + allow: [">"] } } } @@ -532,10 +581,10 @@ user dev-team { user staging-team { permissions { publish { - allow: ["staging.>"] + allow: [">"] } subscribe { - allow: ["staging.>"] + allow: [">"] } } } @@ -544,22 +593,22 @@ user staging-team { user prod-team { permissions { publish { - allow: ["prod.>"] + allow: [">"] } subscribe { - allow: ["prod.>"] + allow: [">"] } } } -# CI/CD (can promote between environments) +# CI/CD gets explicit credentials/imports for each environment account it promotes user ci-cd { permissions { publish { - allow: ["dev.>", "staging.>", "prod.>"] + allow: [">"] } subscribe { - allow: ["dev.>", "staging.>", "prod.>"] + allow: [">"] } } } @@ -568,13 +617,13 @@ user ci-cd { **Effectiveness**: ✓ Good for environment isolation. **Pros**: -- Single cluster, fully isolated environments -- Subject-based auth prevents cross-environment leakage +- Single cluster, fully isolated environment accounts +- Account-based auth prevents cross-environment leakage - Easy to promote from dev → staging → prod **Cons**: -- Adds subject layer (more segments) -- Complex permissions for multi-role users +- Requires account lifecycle for each environment/tenant pair +- CI/CD needs carefully scoped credentials or imports --- @@ -671,14 +720,15 @@ user security-team { When designing multi-tenant subject architecture: -- [ ] **Tenant Isolation**: Tenant prefix prevents cross-tenant access? +- [ ] **Tenant Isolation**: Tenant account boundary prevents cross-tenant access? +- [ ] **Shared Account Justification**: Any tenant prefix fallback has an explicit reason? +- [ ] **Exports/Imports**: Cross-account traffic is explicit and least-privilege? - [ ] **Least Privilege**: Each user/service has minimum permissions? - [ ] **Admin Subjects**: Admin operations separate from user operations? - [ ] **Audit Trail**: All sensitive operations logged to audit subjects? -- [ ] **Environment Separation**: Dev/staging/prod isolated by subject? +- [ ] **Environment Separation**: Dev/staging/prod isolated by account or documented fallback? - [ ] **Role-Based**: Roles clearly separated (user/service/admin)? - [ ] **Denial Rules**: Explicit deny rules for sensitive subjects? - [ ] **Monitoring**: Platform metrics isolated from tenant operations? - [ ] **Credential Rotation**: Plan for credential management? - [ ] **Documentation**: Permission matrix documented for audit? - diff --git a/plugins/trogonstack-nats/skills/nats-design-subject/references/use-cases.md b/plugins/trogonstack-nats/skills/nats-design-subject/references/use-cases.md index 5ede505..2f11c15 100644 --- a/plugins/trogonstack-nats/skills/nats-design-subject/references/use-cases.md +++ b/plugins/trogonstack-nats/skills/nats-design-subject/references/use-cases.md @@ -184,28 +184,29 @@ Analytics SaaS serving 100 customers. Each tenant has events, queries, reports. ### Subject Architecture ``` -{tenant}.{domain}.{action}.{scope}.{id} +Account: {tenant} +Subject: {domain}.{action}.{scope}.{id} Tenant A (ACME Corp): -- acme-corp.events.ingested.2026-01-24.event-123 -- acme-corp.queries.created.2026-01-24.query-456 -- acme-corp.reports.generated.2026-01-24.report-789 +- account acme-corp: events.ingested.2026-01-24.event-123 +- account acme-corp: queries.created.2026-01-24.query-456 +- account acme-corp: reports.generated.2026-01-24.report-789 Tenant B (StartUp Inc): -- startup-inc.events.ingested.2026-01-24.event-101 -- startup-inc.queries.created.2026-01-24.query-202 +- account startup-inc: events.ingested.2026-01-24.event-101 +- account startup-inc: queries.created.2026-01-24.query-202 ``` ### Subscriber Paths ``` Tenant-scoped: -ACME Dashboard: acme-corp.> -ACME Query Engine: acme-corp.queries.created.> +ACME Dashboard: > +ACME Query Engine: queries.created.> Cross-tenant (admin only): -Platform Monitor: analytics.> -Usage Tracker: analytics.usage.daily.> +Platform Monitor account: analytics.> +Usage Tracker account: analytics.usage.daily.> ``` ### Analytics Aggregation Flow @@ -214,10 +215,10 @@ This is the unique challenge for multi-tenant SaaS — how to aggregate across t ``` Individual tenant events: -acme-corp.events.ingested.2026-01-24.event-123 -startup-inc.events.ingested.2026-01-24.event-456 +account acme-corp: events.ingested.2026-01-24.event-123 +account startup-inc: events.ingested.2026-01-24.event-456 - ↓ Aggregator service (reads all tenants, writes analytics) + ↓ Aggregator service (imports explicit tenant exports, writes analytics) Aggregated analytics (admin only): analytics.usage.acme-corp.events-per-day @@ -228,13 +229,14 @@ analytics.cost.all-tenants.monthly-revenue ### GDPR Compliance via Region Filtering ``` -{tenant}.{domain}.{action}.{region}.{id} +Account: {tenant} +Subject: {domain}.{action}.{region}.{id} -EU customers: startup-inc.*.*.eu-central.> -US customers: startup-inc.*.*.us-*.> +EU customers: events.*.eu-central.> in the tenant account +US customers: events.*.us-*.> in the tenant account ``` -For authorization configuration see [security.md](security.md) Pattern 1 (Tenant Isolation) and Pattern 4 (Cross-Tenant Analytics). For stream-per-tenant setup see [jetstream.md](jetstream.md) Pattern 3. +For authorization configuration see [security.md](security.md) Pattern 1 (Tenant Isolation with NATS Accounts) and Pattern 4 (Cross-Tenant Analytics). For account-scoped stream setup see [jetstream.md](jetstream.md) Pattern 3. --- @@ -322,10 +324,13 @@ Multi-tenant platform where AI agents autonomously process tasks. Each tenant ha ### Subject Architecture ``` -agents.{action}.{tenant}.{agent-id}.{task-id} -agents.capabilities.{tenant}.{agent-type} -agents.collaborate.{tenant}.{session-id}.{agent-id} -platform.monitoring.{tenant}.{metric} +Account: {tenant} +agents.{action}.{agent-id}.{task-id} +agents.capabilities.{agent-type} +agents.collaborate.{session-id}.{agent-id} + +Platform account: +monitoring.{tenant}.{metric} ``` ### Multi-Agent Workflow @@ -336,24 +341,24 @@ This is the unique value of the agentic AI pattern — orchestrated multi-step t User Request (Tenant ACME): "Implement OAuth2 in our API" Orchestrator publishes: -agents.task-assigned.tenant-acme.agent-planning-1.task-001 +agents.task-assigned.agent-planning-1.task-001 → Planning Agent analyzes requirements Planning Agent collaborates: -agents.collaborate.tenant-acme.session-001.agent-planning-1 +agents.collaborate.session-001.agent-planning-1 → Requests code agents for implementation Orchestrator fans out: -agents.task-assigned.tenant-acme.agent-code-1.task-002 -agents.task-assigned.tenant-acme.agent-code-2.task-003 +agents.task-assigned.agent-code-1.task-002 +agents.task-assigned.agent-code-2.task-003 → Code agents implement + test in parallel Code agents report: -agents.task-completed.tenant-acme.agent-code-1.task-002 -agents.task-completed.tenant-acme.agent-code-2.task-003 +agents.task-completed.agent-code-1.task-002 +agents.task-completed.agent-code-2.task-003 Orchestrator routes to review: -agents.task-assigned.tenant-acme.agent-review-1.task-004 +agents.task-assigned.agent-review-1.task-004 → Review agent checks quality → done ``` @@ -361,26 +366,26 @@ agents.task-assigned.tenant-acme.agent-review-1.task-004 ``` Agent Task Queue: -Agent LLM-1: agents.task-assigned.tenant-acme.agent-llm-1.> +Agent LLM-1: agents.task-assigned.agent-llm-1.> Inter-Agent Collaboration: -All agents in session: agents.collaborate.tenant-acme.session-001.> +All agents in session: agents.collaborate.session-001.> Orchestrator Tracking: -Completions: agents.task-completed.tenant-acme.> -Failures: agents.task-failed.tenant-acme.> +Completions: agents.task-completed.> +Failures: agents.task-failed.> Capability Discovery: -All agents: agents.capabilities.tenant-acme.> +All agents: agents.capabilities.> Platform Monitoring: -Admin: platform.monitoring.> +Admin: monitoring.> ``` ### Message Example ```json -Subject: agents.task-assigned.tenant-acme.agent-llm-1.task-abc-123 +Subject: agents.task-assigned.agent-llm-1.task-abc-123 Headers: X-Priority: high X-Deadline: 2026-01-24T14:00:00Z @@ -399,6 +404,8 @@ Payload: { } ``` +Tenant identity comes from the account/JWT, not the normal task subject. Put the tenant ID back into subjects only for exported platform telemetry or a documented shared-account fallback. + For tenant isolation authorization see [security.md](security.md) Pattern 5 (AI Agent Sandbox Isolation). For JetStream stream setup see [jetstream.md](jetstream.md) Pattern 3. --- @@ -409,6 +416,6 @@ For tenant isolation authorization see [security.md](security.md) Pattern 5 (AI |----------|---|---|---|---|---| | Microservices | 4 | 3-10 | 50-100 | 10k-100k/sec | 30d-7y | | IoT | 4 | 1 (many dimensions) | 20-50 | 1M+/sec | 1-7 days | -| Multi-Tenant SaaS | 5 | 3-8 | 50-200 | 100k-1M/sec | 30-90d | +| Multi-Tenant SaaS | 4 | 3-8 | 50-200 | 100k-1M/sec | 30-90d | | Event Sourcing | 4 | 5-20 | 100+ | 10k-100k/sec | forever | -| Agentic AI | 5 | 2-3 | 100-1000+ | 10k-100k/sec | 30-365d | +| Agentic AI | 4 | 2-3 | 100-1000+ | 10k-100k/sec | 30-365d |