288 lines
12 KiB
Markdown
288 lines
12 KiB
Markdown
# Device Plane Implementation Baseline
|
|
|
|
> Superseded topology notice — 2026-08-10
|
|
>
|
|
> The historical Foundry-Page product boundary, Mini ingress, VPS-initiated
|
|
> Tailscale/SSH backhaul and `device.nodedc.ru` raw-TCP assumptions below are
|
|
> retained only as implementation history. They must not be used for a new
|
|
> plan/apply. The accepted successor is
|
|
> `docs/ADR_0001_CORE_INITIATED_EDGE_CHANNEL.md`: Device Core is a standalone
|
|
> Hub application, Synology/Core initiates a mutually authenticated full-duplex
|
|
> channel to the VPS, and `device.nodedc.ru` remains the HTTPS UI surface.
|
|
|
|
Status: PostgreSQL, Control Core and Gateway foundation are running healthy on
|
|
Synology. The accepted foundation has public ingress and discovery ingest
|
|
disabled. The next additive transition enables only an authenticated,
|
|
quarantine-only ARUSNAVI B2 discovery path on raw TCP 9921. Command transport
|
|
remains disabled.
|
|
|
|
## Product boundary
|
|
|
|
The Device Manager user interface is a canonical Foundry Page Library
|
|
template. Foundry owns page instances, layout, presentation and an opaque
|
|
`device-plane-control` binding. It does not own device records, credentials,
|
|
raw protocol or command delivery.
|
|
|
|
The independent NDC Device Plane owns physical-device state and direct
|
|
connections:
|
|
|
|
```text
|
|
Foundry Device Manager Page
|
|
|
|
|
| device-plane-control (typed server boundary)
|
|
v
|
|
Device Control Core <-> Device PostgreSQL
|
|
|
|
|
v
|
|
Device Gateway <-> physical devices
|
|
```
|
|
|
|
The isolated ingress placement replaces the direct physical-device arrow when
|
|
the raw route must not terminate on the multi-service Synology:
|
|
|
|
```text
|
|
ARUSNAVI B2 device
|
|
|
|
|
| raw TCP 9921 (future, separately approved)
|
|
v
|
|
Device Edge Relay on dedicated mini
|
|
|
|
|
| outbound restricted SSH local-forward; opaque byte stream only
|
|
v
|
|
Synology loopback 127.0.0.1:9921 -> Device Gateway -> Device Control Core
|
|
```
|
|
|
|
The Edge Relay owns neither protocol acknowledgement nor device identity. It
|
|
does not receive the Gateway/Core token, PostgreSQL credentials, Foundry
|
|
bindings or any command capability. The Synology Gateway remains the sole B2
|
|
codec and acknowledgement owner.
|
|
|
|
Engine L2 may consume safe decoded observations and build workflows/Data
|
|
Products. It does not own TCP sessions, secrets or the command transport.
|
|
|
|
## Preserved production path
|
|
|
|
The existing Gelios -> Engine L2 -> External Data Plane -> Foundry Map path is
|
|
outside this implementation slice. Its credentials, workflows, Data Products,
|
|
bindings and map presentation must not be changed or restarted by a Device
|
|
Plane artifact.
|
|
|
|
The first B2 pilot adds an NDC server route in parallel and keeps the existing
|
|
Gelios route unchanged.
|
|
|
|
## Source and runtime placement
|
|
|
|
Source:
|
|
|
|
```text
|
|
platform/device-plane/
|
|
packages/device-protocol-contract/
|
|
packages/arusnavi-b2-adapter/
|
|
services/device-control-core/
|
|
services/device-gateway/
|
|
services/device-edge-relay/
|
|
docker-compose.device-plane.yml
|
|
docker-compose.device-edge.yml
|
|
```
|
|
|
|
Planned Synology runtime:
|
|
|
|
```text
|
|
/volume1/docker/nodedc-device-plane
|
|
```
|
|
|
|
Planned Compose project and services:
|
|
|
|
```text
|
|
nodedc-device-plane
|
|
device-control-core
|
|
device-gateway
|
|
device-postgres
|
|
```
|
|
|
|
`device-postgres` is a private persistent prerequisite. Application overlays
|
|
must never force-recreate it or its volume.
|
|
|
|
The canonical runner selects only `device-control-core` and `device-gateway`
|
|
with `--no-deps`. Its health acceptance is scoped to the selected services and
|
|
requires the fail-closed fields to remain disabled. A failed first activation
|
|
removes only candidate stateless services and never requests volume removal.
|
|
Rollback now records an explicit pre-apply service inventory in the backup;
|
|
the existence of the shared Compose file does not imply that Core or Gateway
|
|
existed before apply.
|
|
|
|
The exact foundation recovery validates the failed archive, journal, backup,
|
|
partial live source and observed healthy image/container generations. It then
|
|
publishes the matching source and performs read-only runtime acceptance. It
|
|
does not build, restart, recreate or remove any service.
|
|
|
|
## Network boundary
|
|
|
|
The accepted Synology foundation publishes no device port. Device Gateway's
|
|
raw B2 listener is reachable only through `127.0.0.1:9921`; its health
|
|
endpoints are loopback-only. The only planned external raw-TCP termination is
|
|
the dedicated Mini Edge Relay described below.
|
|
|
|
`device.nodedc.ru` is a DNS name, not an HTTP/TCP mode. The same name may later
|
|
serve an HTTPS Control API on 443 and the B2 raw TCP protocol on 9921.
|
|
|
|
DSM HTTP/HTTPS Reverse Proxy is not a raw TCP ingress and must not be configured
|
|
as `443 -> 9921`.
|
|
|
|
The artifact never changes DSM firewall, DSM Router Configuration, DNS or a
|
|
physical router.
|
|
|
|
### Dedicated mini Device Edge
|
|
|
|
The Debian mini is the isolated raw-TCP edge. Its accepted predecessor keeps the
|
|
relay disabled and publishes health only on `127.0.0.1:18221`. The reviewed
|
|
target removes even that host publication: health remains container-internal,
|
|
the relay stays on the `internal: true` private bridge for backhaul, and a
|
|
second IPvlan L2 attachment gives only the relay a LAN-routable address for
|
|
`9921/TCP`. The relay has bounded global/per-address sessions and connection
|
|
rate, a bounded source-rate table and a per-direction byte budget. It emits no
|
|
bytes of its own and does not inspect device payloads.
|
|
|
|
The admission-gate transition is deliberately fail-closed at the relay: an
|
|
ingress instance accepts only a syntactically public IPv4 source, limits its
|
|
in-memory source table to 2,048 addresses and closes either direction after
|
|
262,144 bytes. Private, loopback, link-local, carrier-grade NAT, multicast,
|
|
reserved and documentation addresses are rejected before an upstream connection
|
|
is made. This is a connection-admission and resource-boundary control, not a
|
|
claim that Docker IPvlan traffic is filtered by a host firewall. A raw B2
|
|
protocol has no TLS client identity and cellular devices do not offer a stable
|
|
source-IP allowlist, so a router/NAT mapping remains prohibited until its
|
|
separate exposure and abuse controls are reviewed.
|
|
|
|
IPvlan deliberately reuses the Mini's one physical parent `enp1s0f0`; a second
|
|
Ethernet adapter is not required. The host keeps `192.168.68.54/22` and the
|
|
Amnezia `0.0.0.0/1` plus `128.0.0.0/1` routes. The relay has its own fixed LAN
|
|
IPv4 and default route through `192.168.68.1`, while its private connected route
|
|
continues to reach `device-edge-backhaul:19921`. No Docker host `ports:` entry,
|
|
host-network mode, privileged container or VPN teardown is allowed.
|
|
|
|
Enabling public ingress is a separate reviewed operation and requires all of
|
|
the following evidence:
|
|
|
|
1. A distinct, no-shell Synology SSH account and key whose sole permitted open
|
|
target is `127.0.0.1:9921`; host-key pinning and a persistent, monitored
|
|
tunnel are required.
|
|
2. A private backhaul sidecar/network; the raw listener may forward only to
|
|
that tunnel. The Core token and all Core/Database secrets remain on
|
|
Synology.
|
|
3. Router evidence proving the fixed relay IPv4 is outside DHCP. The artifact
|
|
cannot choose an address and never changes router, firewall or DHCP state.
|
|
A manual router/NAT rule is a later independent approval, after the relay's
|
|
admission gate and external-exposure runbook have been accepted.
|
|
4. The host full-tunnel VPN remains active. Before production activation, the
|
|
exact single-NIC IPvlan design must pass duplicate-address detection,
|
|
gateway reachability, external return-path and private-backhaul checks.
|
|
5. One pre-authorized B2 pilot route, quarantine-only Gateway/Core ingest and
|
|
disabled command transport.
|
|
|
|
## Identity and onboarding
|
|
|
|
An IMEI is a claimed protocol identifier, not proof of tenant ownership.
|
|
|
|
- An unknown connection produces a quarantine-only discovery.
|
|
- A discovery never receives commands.
|
|
- Pilot claim requires an explicit platform-admin action.
|
|
- Production assignment requires authoritative pre-enrollment or an audited
|
|
inventory import.
|
|
- First-claim-wins by IMEI is forbidden.
|
|
|
|
The ARUSNAVI Web account login/password is used only by the human operator to
|
|
configure the additional device route. It is not a Device Plane credential.
|
|
|
|
## Protocol evidence
|
|
|
|
The official B2 material proves:
|
|
|
|
- four simultaneous monitoring server routes;
|
|
- `INTERNAL`, `EXTERNAL`, `USER_AG` and EGTS variants;
|
|
- INTERNAL server-side identification by modem IMEI;
|
|
- server route fields for DNS/IP, TCP port, protocol and optional ID;
|
|
- SMS/TCP command families and a six-digit device access password.
|
|
|
|
The official ARUSNAVI INTERNAL protocol sheet now provides the first read-path
|
|
framing contract:
|
|
|
|
- HEADER2 for GPRS is `FF 23` followed by an eight-byte little-endian IMEI;
|
|
- the server confirms HEADER2 with a bounded `SERVER_COM` carrying Unix time;
|
|
- a PACKAGE begins with `5B`, carries a package number in `01..FB`, contains
|
|
one or more length-framed PACKET records and ends with `5D`;
|
|
- every PACKET checksum is verified before acknowledgement;
|
|
- every valid PACKAGE is acknowledged by package number;
|
|
- without acknowledgement the tracker repeats the transmission.
|
|
|
|
The pilot codec implements only that verified read/acknowledgement subset. It
|
|
does not decode telemetry tags, export command builders or accept arbitrary
|
|
server commands. An IMEI parsed from a valid HEADER2 remains a claimed
|
|
identifier and never proves tenant ownership.
|
|
|
|
## Command boundary
|
|
|
|
Outbound command transport is disabled in this baseline. No command builder is
|
|
exported.
|
|
|
|
Later lifecycle:
|
|
|
|
```text
|
|
draft -> planned -> awaiting_confirmation -> queued -> dispatched
|
|
-> acknowledged | failed | expired | unknown
|
|
```
|
|
|
|
`send` is not success. An `unknown` result forbids automatic retry.
|
|
|
|
Erase, factory reset, firmware/custom firmware, physical outputs and arbitrary
|
|
raw TCP remain forbidden until separate reviewed acceptance slices.
|
|
|
|
## Implemented local foundation
|
|
|
|
- Provider-neutral discovery, contour and opaque Foundry-binding contracts.
|
|
- B2 model profile with four parallel routes and INTERNAL/IMEI evidence.
|
|
- PostgreSQL migration for model profiles, contours, quarantine discoveries,
|
|
claimed devices, Foundry bindings and append-only audit events.
|
|
- Core health endpoint and an authenticated quarantine-ingest boundary that is
|
|
disabled unless explicitly enabled with file-backed secrets.
|
|
- Gateway discovery-only HEADER2/PACKAGE state machine with bounded buffers,
|
|
handshake timeout, concurrent/per-source session limits and per-source
|
|
connection rate limits.
|
|
- Authenticated Gateway-to-Core discovery ingest. Core HMAC-hashes the full IMEI
|
|
and persists only its digest, masked view and verified framing evidence.
|
|
- Only HEADER2 and valid PACKAGE acknowledgements are emitted; no command
|
|
builder or command transport is present.
|
|
- Recursive rejection of secret-like fields, raw payloads and command-shaped
|
|
input in presentation contracts.
|
|
- Automated contract, adapter, migration, Core and Gateway tests.
|
|
- Additive `component=device-plane` runner registry with exact roots, builds,
|
|
services, allowlist/denylist, runner-owned secrets, health contracts and
|
|
automatic source/runtime rollback.
|
|
- Deterministic data-only artifact builder and positive/negative regression
|
|
tests.
|
|
- Compose foundation with a private internal network, preserved PostgreSQL
|
|
volume, file-backed database password and loopback-only health publishing.
|
|
- Exact one-time PostgreSQL bootstrap descriptor, deterministic builder and
|
|
absence preflight: an existing database container or volume fails closed,
|
|
and rollback never removes the volume.
|
|
|
|
## Next activation slice
|
|
|
|
1. The Deco DHCP range has been recorded as `192.168.68.50` through
|
|
`192.168.71.250`; the fixed Relay IPv4 is `192.168.71.253`, outside that
|
|
pool and independently DAD-tested. It is pinned in Compose, descriptor,
|
|
builder and the separate Edge runner.
|
|
2. Build the deterministic `component=device-edge` artifact, promote the
|
|
root-owned Edge runner and review its `plan`. The Synology runner and inbox
|
|
are not used for this host.
|
|
3. Apply the admission-gate update only to `device-edge-relay`; prove exact
|
|
IPvlan runtime, no host ports, `public-ipv4-only` admission, byte/source
|
|
limits, internal health, private backhaul reachability, unchanged
|
|
backhaul/tailnet identities and preserved Amnezia routes. Automatic rollback
|
|
restores the reviewed IPvlan predecessor and leaves router state unchanged.
|
|
4. Independently review and add the single router/NAT rule for TCP `9921` only,
|
|
then verify that Synology still exposes no public device port.
|
|
5. Add the NDC route to one approved B2 free server slot while preserving
|
|
Gelios, then prove HEADER/discovery/PACKAGE acknowledgement. Claim and tenant
|
|
assignment remain a later explicit platform-admin operation.
|