Thing Access Model¶
This document describes how things are enrolled, provisioned, and made accessible to different accounts on the FlexGalaxy.AI platform. It is the conceptual model behind the repository-visibility ADRs — see ADR-0001, ADR-0002, and ADR-0003.
Core concepts¶
- Thing
A device, product, or piece of equipment registered on the platform. Things go through a lifecycle:
ENROLLED → PROVISIONED → ACTIVE.- Registrar
A manufacturing context owned by an account. Things are enrolled into a registrar. An account can have multiple registrars (e.g., different factory lines or product categories).
- Access Code
A per-thing credential generated at provisioning. Used by other accounts to gain access to the thing. Reusable (multiple accounts can use the same code) until explicitly retired by the registrar owner.
- Thing Access
A grant that allows an account to see and interact with a specific thing. Each access grant records which access code was used. Access is valid only while the access code matches the thing’s current active code.
Enrollment vs Access¶
ThingMake (manufacturer console) shows enrolled things — things the account’s registrar enrolled. The registrar owner has inherent access to all things in their registrar without needing an access code.
ThingHub (device management) shows accessible things — things the account has been granted access to, regardless of how. This includes:
Things in the account’s own registrar (inherent access)
Things accessed via access code
Things auto-granted access (a platform-driven grant with a null access code)
Lifecycle¶
Enrollment¶
Manufacturer creates a registrar (if they don’t have one)
Manufacturer enrolls a thing into the registrar
Thing is created with
status=ENROLLED, nothing_id, noaccess_codeThe registrar owner has inherent access (no ThingAccess record needed inline — the registrar/repository system inserts one; see ADR-0001)
Provisioning¶
Manufacturer provisions the thing
thing_idis assigned (NanoID 16 characters)access_codeis auto-generatedstatuschanges toACTIVEThe thing is now ready to be shared with others
Auto-granted access¶
The platform can create a ThingAccess record automatically using the thing’s current
access code (or a null access code for platform-driven grants). This lets a platform-approved
account view a thing without the manufacturer manually sharing a code. Auto-granted access
carries the same revocation semantics as any other grant: retiring the current access
code invalidates it.
Access validation¶
On every access check, the platform validates:
A
ThingAccessrecord exists for(thing_id, account_id)The
access_codein the record matches the thing’s current active code (a nullaccess_codecounts as an auto-granted match)If the code has been retired (no longer matches), access is denied
This means retiring an access code instantly revokes all access grants that were made with that code.
Access code management¶
Action |
Effect |
|---|---|
Provision thing |
First access code auto-generated |
Share code |
Others enter the code to gain access (reusable, multiple accounts) |
Retire + regenerate |
Current code retired, new code generated. All existing access grants tied to the old code become invalid. New code can be shared with new parties. |
Auto-grant |
Access created using current code (or null); same revocation semantics |
Registrar access¶
Registrar owners have inherent access to all things in their registrar. This access does NOT go through the access code model.
Other accounts CANNOT access a registrar. They can only access individual things within it (via access code or auto-grant).
Registrar information (name, owner, etc.) is hidden from non-owner accounts in ThingHub.
Data model¶
Thing entity¶
things (
id UUID PRIMARY KEY,
thing_id VARCHAR(16), -- assigned at provisioning (NanoID)
type VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL, -- ENROLLED, ACTIVE, SUSPENDED, DEREGISTERED
registrar_id UUID NOT NULL, -- FK to registrars
access_code VARCHAR(20), -- current active code (null before provisioning)
model_id VARCHAR(100),
registered_at TIMESTAMP,
updated_at TIMESTAMP
)
ThingAccess entity¶
thing_accesses (
id UUID PRIMARY KEY,
thing_id UUID NOT NULL, -- FK to things.id (internal ID)
account_id VARCHAR(100) NOT NULL,
access_code VARCHAR(20) NOT NULL, -- the code used to gain access
granted_at TIMESTAMP NOT NULL,
UNIQUE(thing_id, account_id, access_code)
)
Access check: SELECT 1 FROM thing_accesses ta JOIN things t ON ta.thing_id = t.id WHERE ta.thing_id = ? AND ta.account_id = ? AND ta.access_code = t.access_code
Registrar entity¶
registrars (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
account_id VARCHAR(100) NOT NULL, -- owner account
status VARCHAR(20) NOT NULL,
created_at TIMESTAMP,
updated_at TIMESTAMP
)
API endpoints¶
ThingHub (accessible things)¶
GET /api/v1/accesses -- list accessible things
POST /api/v1/things/access -- grant access by access code
body: { "access_code": "..." }
ThingMake (enrolled things)¶
GET /api/v1/registrars -- list own registrars
POST /api/v1/registrars -- create a registrar
GET /api/v1/registrars/{id}/things -- list enrolled things
POST /api/v1/things -- enroll a thing
POST /api/v1/things/{id}/provision -- provision (assigns thing_id + access_code)
POST /api/v1/things/{id}/regenerate-code -- retire current code, generate new one
Access code flows¶
-- Share: manufacturer gives code to partner
POST /api/v1/things/access
{ "access_code": "B002-X002-Y002" }
→ 201: { "thing_id": "BROIT-CLN-002", "access_code": "B002-X002-Y002", ... }
-- Retire + regenerate: manufacturer rotates code
POST /api/v1/things/{id}/regenerate-code
→ 200: { "access_code": "NEW-CODE-HERE", ... }
-- All previous access grants using old code are now invalid
Examples¶
A manufacturer (RUBY-Dalian) enrolls a cleaning robot:
1. POST /registrars → creates "RUBY Dalian Manufacturing"
2. POST /things → enrolls robot (status=ENROLLED)
3. POST /things/{id}/provision → thing_id=BROIT-CLN-002, access_code=B002-X002-Y002
4. RUBY sees the robot in ThingMake (enrolled) and ThingHub (accessible)
A distributor (GREEN) gets access via code, then loses it on rotation:
1. RUBY shares access code B002-X002-Y002 with GREEN
2. GREEN enters code in ThingHub → ThingAccess created
3. GREEN sees BROIT-CLN-002 in ThingHub
4. RUBY retires code → GREEN loses access
5. RUBY generates new code, shares with BLUE → only BLUE has access
Access is additive and managed entirely through grants: there is no owner-transfer or
claim concept. Revoking is deleting the ThingAccess row (or rotating the code).