Subject Naming

Table of Contents

Subject Hierarchy Design

Subject naming is the API of your messaging system. A well-designed hierarchy enables efficient routing, filtering, and access control while remaining intuitive for developers.


Design Principles

PrincipleRationale
HierarchicalEnable wildcard subscriptions at any level
PredictableDevelopers can construct subjects without lookup
Environment-awareSeparate production from staging/development
FilterableSubscribe to one vehicle, group, or entire fleet
ExtensibleAdd new message types without restructuring

Core Subject Pattern

All fleet subjects follow this pattern:

fleet.<env>.veh.<vid>.<category>.<type>
SegmentDescriptionExamples
fleetRoot namespaceAlways “fleet”
<env>Environmentprod, staging, dev
vehResource typeVehicles (future: gcs for ground control)
<vid>Vehicle IDVID-001, drone-alpha-7
<category>Message categorystate, evt, cmd, cmdack
<type>Specific typeposition, battery, takeoff

Message Categories

State: fleet.<env>.veh.<vid>.state.*

Current vehicle state, published continuously:

SubjectDescriptionRate
state.positionLat/lon/alt, velocity10 Hz
state.attitudeRoll/pitch/yaw10 Hz
state.batteryVoltage, current, remaining1 Hz
state.modeFlight mode (AUTO, MANUAL, RTL)On change
state.healthSystem health summary1 Hz

Example publish:

subject := fmt.Sprintf("fleet.prod.veh.%s.state.position", vehicleID)
nc.Publish(subject, positionJSON)

Events: fleet.<env>.veh.<vid>.evt.*

Discrete occurrences, published when they happen:

SubjectDescription
evt.armedVehicle armed
evt.disarmedVehicle disarmed
evt.takeoffTakeoff initiated
evt.landedLanding complete
evt.waypointWaypoint reached
evt.failsafeFailsafe triggered
evt.geofenceGeofence breach
evt.battery.lowLow battery warning

Events are state transitions, not continuous data. They’re durable—stored in JetStream for audit trails.

Commands: fleet.<env>.veh.<vid>.cmd.*

Instructions sent to vehicles:

SubjectDescription
cmd.armArm motors
cmd.disarmDisarm motors
cmd.takeoffInitiate takeoff
cmd.landInitiate landing
cmd.rtlReturn to launch
cmd.gotoNavigate to position
cmd.mission.uploadUpload mission
cmd.mission.startStart mission
cmd.param.setSet parameter

Commands flow downstream from fleet management to vehicles.

Command Acknowledgments: fleet.<env>.veh.<vid>.cmdack.*

Responses to commands:

SubjectDescription
cmdack.armArm command result
cmdack.takeoffTakeoff command result
cmdack.gotoGoto command result

Ack payload includes:

{
  "cmd_id": "cmd-123456",
  "status": "accepted|rejected|completed|failed",
  "error": "optional error message",
  "timestamp": "2024-01-15T10:30:00Z"
}

Wildcard Subscriptions

NATS wildcards enable flexible subscriptions:

WildcardMeaningExample
*Single tokenfleet.prod.veh.*.state.position
>One or more tokensfleet.prod.veh.VID-001.>

Common Subscription Patterns

PatternUse Case
fleet.prod.veh.*.state.positionAll vehicle positions
fleet.prod.veh.VID-001.>Everything from one vehicle
fleet.prod.veh.*.evt.>All events from all vehicles
fleet.prod.veh.*.state.batteryAll battery states
fleet.*.veh.VID-001.>One vehicle across all environments

KV Stores: Digital Twin Shadow

JetStream KV stores maintain desired and reported state:

Subject Pattern (KV)

fleet/<env>/veh/<vid>/desired
fleet/<env>/veh/<vid>/reported

Note: KV uses / separator (bucket path), while pub/sub uses . separator.

Desired State

What the fleet management system wants the vehicle to do:

{
  "mode": "AUTO",
  "mission_id": "mission-456",
  "geofence_enabled": true,
  "max_altitude": 120,
  "home_position": {
    "lat": 37.7749,
    "lon": -122.4194
  }
}

Reported State

What the vehicle actually reports:

{
  "mode": "AUTO",
  "mission_id": "mission-456",
  "mission_progress": 0.45,
  "geofence_enabled": true,
  "armed": true,
  "in_flight": true,
  "battery_remaining": 0.72
}

Shadow Reconciliation

The Vehicle Gateway continuously:

  1. Reads desired state from KV
  2. Compares with actual vehicle state
  3. Issues commands to align reality with desired
  4. Updates reported state

This enables declarative fleet management—set the desired state, let vehicles converge.


Access Control

NATS authorization maps users to allowed subjects:

# Vehicle can publish its own state/events
publish: fleet.prod.veh.VID-001.state.>
publish: fleet.prod.veh.VID-001.evt.>
publish: fleet.prod.veh.VID-001.cmdack.>

# Vehicle can subscribe to commands for itself
subscribe: fleet.prod.veh.VID-001.cmd.>

# Vehicle can read/write its own shadow
kv: fleet/prod/veh/VID-001/*
# Fleet operator can subscribe to all state/events
subscribe: fleet.prod.veh.*.state.>
subscribe: fleet.prod.veh.*.evt.>
subscribe: fleet.prod.veh.*.cmdack.>

# Fleet operator can publish commands
publish: fleet.prod.veh.*.cmd.>

# Fleet operator can manage shadows
kv: fleet/prod/veh/*/desired

This ensures vehicles can’t impersonate other vehicles or publish unauthorized commands.

For detailed coverage of the authorization model, including third-party grants and credential management, see Authorization & Grants.


Subject Design Tradeoffs

Why not flat subjects?

Flat subjects like vehicle-001-position don’t support:

  • Wildcard subscriptions
  • Hierarchical access control
  • Logical grouping

Why not deeper hierarchy?

Subjects like fleet.prod.region.us-west.site.warehouse-a.veh.VID-001.state.position:

  • Harder to construct programmatically
  • Wildcards become complex
  • Changes ripple through the system

The four-level hierarchy balances flexibility with simplicity.


Message Format

All messages use JSON with consistent structure:

{
  "vid": "VID-001",
  "timestamp": "2024-01-15T10:30:00.123Z",
  "seq": 12345,
  "data": {
    // message-specific payload
  }
}
FieldDescription
vidVehicle ID (redundant with subject, but useful for consumers)
timestampISO 8601 with millisecond precision
seqMonotonic sequence number for ordering
dataMessage-specific payload

Summary

CategorySubject PatternDirection
Statefleet.<env>.veh.<vid>.state.<type>Vehicle → Hub
Eventsfleet.<env>.veh.<vid>.evt.<type>Vehicle → Hub
Commandsfleet.<env>.veh.<vid>.cmd.<type>Hub → Vehicle
Acksfleet.<env>.veh.<vid>.cmdack.<type>Vehicle → Hub
Desiredfleet/<env>/veh/<vid>/desired (KV)Hub → Vehicle
Reportedfleet/<env>/veh/<vid>/reported (KV)Vehicle → Hub

Next

Stream Configuration →