Reference Implementation

BSFG NATS Naming Profile

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 <a href="../concepts/naming-conventions.html">Naming Conventions</a>


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:

  • Different retention policies per subject kind
  • Better consumer performance (smaller subscription scope)
  • Clearer semantic organization

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

  • Zone names are stable: Once deployed, a zone name is never changed
  • Zone names are DNS-friendly: Lowercase, dash-separated (not underscore or dot)
  • Zone names appear in NATS accounts: Account naming derives from zone names (<zone>_account)
  • Zone names appear in certificate CN: Authentication relies on CN matching zone identity
  • Renaming zones requires infrastructure updates: Re-issue certificates, re-provision NATS accounts, update firewall 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):

  • Subjects: <entity_type>:<identifier> (e.g., batch:PlantA/B1042)
  • Predicates: <verb>_<object> (e.g., batch_started)
  • Schema IDs: <predicate>_v<#> (e.g., batch_started_v1)
  • Artifact paths: <bucket>/<entity>/<identifier> (e.g., batch-files/PlantA/B1042/recipe.pdf)
  • Zone names: <zone>-bsfg (e.g., enterprise-bsfg)

NATS/JetStream specifics (this document):

  • JetStream streams: facts.<category>[.<prefix>]
  • Subject hierarchies: facts.<category>.<subject_kind>.<entity>.*
  • NATS accounts: <zone>_account
  • Certificate CN: <zone>-bsfg