Identity
:::info Status
Implemented. Source: docs/device-management-module-architecture.md §1, §3, §5e, §6.0; fastapi-backend/core/device_claim.py, fastapi-backend/core/device_registry.py.
:::
Identity answers exactly one question: which physical unit is this? Nothing more. It is established once, at manufacture and claim, and never changes for the life of the unit.
| Concept | Lives in | Changed by | Never changed by |
|---|---|---|---|
| Identity | devices.device_uid, MQTT client id, topic path | manufacture / claim | rebinding, membership changes, approval |
This is the first of five concepts this system keeps strictly separate — see Terminology for the full table and Device Architecture for why.
The identity chain
Inventory precedes device. A serial that was never imported into
device_inventory cannot be claimed (unknown_serial) — the single control
that stops an unmanifested unit from entering the fleet. The factory never
holds a device_secret; manufacturing produces identifiers only, and the
manifest is checked (row count + checksum vs. the purchase order), not
trusted blindly.
hardware_revision is captured at import time — it's what binds which
firmware/config a unit can accept later, and can't be inferred after the
fact from the serial alone. MAC may be null for parts that can't read it at
manufacture time; it's then bound at first claim, which weakens the
cross-check below to serial-only for that unit (a per-batch decision, never
a silent fallback).
Claim-time cross-validation (§6.1a)
A hard acceptance criterion, not a soft mitigation — every field must agree with the inventory row or the claim is rejected outright:
Claim is also where the inventory transition IN_STOCK → ALLOCATED happens
— the step the rest of the lifecycle (verify/activate/approve) depends on as
a precondition without itself triggering it. This does not prove the
hardware is genuine — a clone holding a stolen serial/MAC pair would also
pass (closed properly only by a secure-element key, noted as an open
per-batch decision in the source doc) — but it does mean counterfeiting
requires stealing a specific sold unit's identity rather than inventing
plausible ones.
Identity vs. authentication
Identity (device_uid lookup) and authentication (device_secret verified
via bcrypt; a per-device broker credential for MQTT) are the first two of
five distinct questions this system asks on every request — see
Device Authorization for the full chain and why
passing an earlier one never implies the later ones.
/announce vs. /claim
POST /device-registry/announce | POST /device-registry/claim | |
|---|---|---|
| Auth | none (IP rate-limited) | user JWT |
| Who calls it | an unprovisioned unit, on its own | the installer/buyer |
| On a manifest match | creates/refreshes a PENDING row, links inventory — no credentials returned | opens ownership + assignment, releases broker credentials, stays PENDING |
| On no match | recorded in unmanifested_announcements, no device row | rejected (unknown_serial) |
/announce polls every 30 seconds until claimed — the only polling endpoint
in the system, because a pre-claim unit has no open session to push
anything to. Full endpoint list: Device Management module.
An unmatched announcement lands in unmanifested_announcements — a queue
for humans, never a device state: either an unimported manifest (fix: import
it) or a counterfeit (fix: investigate). Nothing is promoted automatically.