New optional 1:1 extension to services: providers can declare how IoT
devices connect to their hub (hub_url, protocols, provisioning endpoint,
device classes, firmware compatibility) via PATCH /services/{id}.
- New entity IotProfileEntity + Liquibase changeset 009 (GIN indexes for
jsonb device_classes and protocols arrays)
- IotProtocol / CredentialFormat enums; IotProfileRequest / IotProfileResponse DTOs
- JsonStringListConverter for jsonb List<String> persistence
- GET /services/{id}/replacements extended with iotProfile per candidate
and new filter params: iotReady=true, deviceClass=..., protocol=...
- 6 new BDD scenarios (IotProfileCucumberTest) covering profile creation,
candidate enrichment, iotReady / deviceClass filtering, partial update,
and missing-field 422 validation
- All 57 tests green (6 new + 27 existing transition + 24 unit)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.1 KiB
ADR-015: IoT Device Transition — Pull-Only Anonymity Model
Status: Accepted Date: 2026-05-06
Context
When a cloud service declares sunset and releases its device lock, IoT device owners need to discover compatible replacement services. APIX facilitates this discovery. The design question is how APIX interacts with device owners during this process without compromising their anonymity.
Device owner anonymity is a hard requirement: APIX must not store any artefact that links a query to a specific device or owner, including under legal compulsion.
Alternatives
| Alt | Description | Pros | Cons |
|---|---|---|---|
| A — Pull-only polling | Devices poll GET /services/{id} and GET /services/{id}/replacements periodically. No registration. |
Zero identity exposure; no per-device APIX state; no single point of notification failure | Device must be online and polling; no guaranteed delivery; detection latency depends on poll interval |
| B — Anonymous token registration | Device generates a one-time token and posts it to APIX for push callbacks on status change | Lower detection latency; no active polling required | Token + callback URL creates a device linkage; legally compellable even if hashed; APIX becomes notification infrastructure |
| C — Email / contact registration | Device owner registers email with APIX for sunset alerts | Familiar UX for human operators | Directly identifies owner; incompatible with anonymity requirement |
| D — Third-party privacy relay | Device owner registers with a privacy relay (e.g. anonymising alias service) which forwards APIX push events | Plausible deniability for owner identity | External dependency; relay is a single point of failure; APIX still stores a callback endpoint linkable to the relay account |
Decision
Alternative A — Pull-only polling.
Reason
Only pull-only provides a genuine anonymity guarantee. Alternatives B, C, and D all require APIX to store an artefact (token, address, or endpoint) that is linkable to a device or owner under legal compulsion, regardless of hashing or relay indirection. APIX's anonymity guarantee is only credible if there is no stored linkage at all.
Device owners requiring active push notification must implement it themselves using their own tooling pointed at the APIX poll endpoints. The poll API is designed to be cache-friendly and bandwidth-minimal.
Consequences
GET /services/{id}must returnlocked,sunset_date, andservice_stagewithout authentication.GET /services/{id}/replacementsmust be publicly accessible without authentication.- Both endpoints are included in the Caddy cache configuration (same cache policy as the default production service query).
- IP addresses from polling requests must not be persisted beyond standard access log rotation (no analytics pipeline on these endpoints).
- BSF terms of registration require template owners to release the device lock within 90 days of sunset declaration, making the polling window predictable for device owners.
- APIX must never log request parameters or headers that could identify a polling device.