Reference Implementation

NATS/JetStream Naming Conventions

Concrete naming rules for JetStream streams, subjects, and NATS accounts

Audience: Implementation engineers, operators. Use: Reference for JetStream-specific naming when deploying BSFG with NATS. For abstract naming rules (subjects, predicates, schemas, artifacts, zones), see Naming Conventions.


Stream Naming

BSFG facts are organized into JetStream streams by category and subject prefix.

Format

stream_name := facts.<category>[.<prefix>]

Standard Categories

Category Purpose Subjects Retention Example Stream
operational Production data (orders, batches, steps) facts.operational.* 7–10 years facts.operational.batch.*
audit System access and change logs facts.audit.* 3–7 years facts.audit.user.*
documents Document and file references facts.documents.* 5–10 years facts.documents.compliance.*
telemetry Sensor readings and metrics facts.telemetry.* 1–3 years facts.telemetry.temperature.*

Subject-Based Partitioning

Streams can use subject prefixes to partition by subject kind:

facts.operational.batch.*          (all batch facts)
facts.operational.order.*          (all order facts)
facts.operational.device.*         (all device facts)
facts.audit.system.*               (system-level audit)
facts.audit.user.*                 (user-level audit)

Partitioning enables:

JetStream Stream Configuration

streams:
  - name: facts_operational
    subjects:
      - facts.operational.>
    max_age: 10y        # 10-year retention for operational data
    storage: file       # persistent storage
    replicas: 3         # HA: replicate to 3 nodes
    discard: old        # evict oldest when full (for non-safety-critical)

  - name: facts_audit
    subjects:
      - facts.audit.>
    max_age: 7y
    storage: file
    replicas: 3
    discard: old

  - name: facts_telemetry
    subjects:
      - facts.telemetry.>
    max_age: 3y
    storage: file
    replicas: 1         # lower HA requirement for ephemeral telemetry
    discard: old

Account Naming

Each BSFG zone has zone-scoped NATS accounts for access control.

Format

account_name := <zone>_account

Examples

enterprise_account     (Enterprise IT zone)
plant_a_account        (Plant A OT zone)
plant_b_account        (Plant B OT zone)
idmz_account           (Industrial DMZ, optional)

Account Model

Each zone has at least two accounts:

zone: enterprise-bsfg
accounts:
  enterprise_account:      # Application-facing account
    purpose: emit/consume facts
    permissions:
      - publish: facts.operational.>
      - subscribe: facts.operational.>
      - publish: facts.audit.>
      - subscribe: facts.audit.>

  system_account:          # BSFG node system account
    purpose: internal JetStream operations
    permissions:
      - publish: $JS.>
      - subscribe: $JS.>

The enterprise_account is used by producers and consumers (applications). The system_account is used by the BSFG node itself for internal stream/consumer management.


Subject-Level Authorization

NATS enforces authorization at the subject level using ACLs (Access Control Lists).

Subject Hierarchies

Topics use dot-separated hierarchies:

facts.operational.batch.PlantA.B1042
facts.operational.order.ENT-12345
facts.audit.user.john_doe
facts.telemetry.temperature.sensor_7

Authorization Rules

# Enterprise zone permissions
enterprise_account:
  permissions:
    publish:
      allow:
        - 'facts.operational.>'        # produce facts
        - 'facts.audit.>'
        - 'facts.documents.>'
    subscribe:
      allow:
        - 'facts.operational.>'        # consume facts
        - 'facts.audit.>'
        - 'facts.documents.>'

# Plant zone permissions (restricted)
plant_a_account:
  permissions:
    publish:
      allow:
        - 'facts.operational.batch.PlantA.>'    # only PlantA batches
        - 'facts.audit.plant_a.>'
    subscribe:
      allow:
        - 'facts.operational.batch.PlantA.>'
        - 'facts.audit.plant_a.>'

JetStream System Subject Rules

JetStream uses reserved subjects for cluster and consumer operations:

$JS.API.*              # API calls (create stream, consumer, etc.)
$JS.EVENT.*            # Events (stream created, message acknowledged)
$JS.DEBUG.*            # Debug information
$KV.*                  # Key-value store (if used)
$OBJ.*                 # Object store (if used)

The system_account must have permission to $JS.>:

system_account:
  permissions:
    subscribe:
      allow: ['$JS.>']
    publish:
      allow: ['$JS.>']

Message ID (Deduplication) Naming

Within each stream, producers provide a message ID for idempotent deduplication:

// High-entropy stable ID derived from business key
const message_id = sha256(order_id + event_type + timestamp);

// Publish with message ID header
await stream.publish(subject, payload, {
  msgID: message_id
});

JetStream stores message IDs in a deduplication window (default: stream's MaxAge). Any message with the same ID within the window is deduplicated.


Zone Identity and Certificates

Zone identities appear in mTLS certificate Common Names:

Zone Identity: enterprise-bsfg
  └─ Certificate CN: enterprise-bsfg
  └─ Private Key: /etc/bsfg/certs/enterprise-bsfg.key
  └─ Certificate: /etc/bsfg/certs/enterprise-bsfg.crt
  └─ CA Bundle: /etc/bsfg/certs/ca.crt

Zone Identity: plant-a-bsfg
  └─ Certificate CN: plant-a-bsfg
  └─ ...

Zone Identity Rules


Environment Variables and Secrets

Store NATS credentials and keys in environment variables or secrets manager:

# Zone identity for this BSFG node
export BSFG_ZONE="enterprise-bsfg"

# NATS server connection
export NATS_SERVERS="nats://enterprise-nats:4222"

# mTLS certificate paths
export BSFG_CERT="/etc/bsfg/certs/enterprise-bsfg.crt"
export BSFG_KEY="/etc/bsfg/certs/enterprise-bsfg.key"
export BSFG_CA="/etc/bsfg/certs/ca.crt"

# NATS account credentials (if using user accounts instead of mTLS)
export NATS_USER="$BSFG_ZONE-user"
export NATS_PASSWORD="<secure-password>"

Relationship to Abstract Naming

For the abstract naming rules that apply to all BSFG deployments, see Naming Conventions.

Abstract grammar (substrate-neutral):

NATS/JetStream specifics (this document):


Cross-Links