Skip to content

Architecture

Raiznet is organized in three layers. This page distinguishes what runs today from what is in design — see the Roadmap for the full picture.

Edge layer — ESP32 sensors

All devices run the same base firmware. The mode is determined by configuration, not hardware:

ModePowerBehavior
sensor_mainsWall powerAlways on, keeps Wi-Fi active; future ESP-NOW relay for neighbors
sensor_batteryBatterySleeps most of the time, wakes on schedule
gatewayWall powerRelay only — bridges ESP-NOW devices to Wi-Fi (planned)

Every device has the same identity model: an Ed25519 keypair born at provisioning (hardware TRNG), stored in flash, used to sign every telemetry packet. The reference firmware also generates the owner identity from a BIP-39 mnemonic in its captive portal — see Device Lifecycle.

Mesh layer — server nodes

Each server is a peer. There is no "main server". What a node does today:

  • Receives signed telemetry over HTTP (POST /v1/telemetry) and validates every signature
  • Applies the per-field privacy policy at ingestion
  • Stores readings in two local SQLite databases (public / private)
  • Exposes the HTTP API on two ports: one public, one local

In design (ADR-004): nodes will persist public data as a signed append-only event log and replicate it peer-to-peer with other nodes in the same network — first between configured peers over HTTP, then via a dial-by-pubkey transport with community-runnable relays. Replication is not implemented yet — today, nodes are independent.

A server can run anywhere Node.js runs: VPS, Raspberry Pi, Mini PC, Android via Termux. A Rust reimplementation of the node (raiznetd) is underway to target very small ARM boards with a static binary — see the Roadmap.

Dual endpoints on one process

A single server process exposes two HTTP interfaces:

EndpointDefault portBindDevices routes hitAuth
Public:30000.0.0.0raiznet_public.dbNone (public data only)
Local:3001127.0.0.1raiznet_private.dbNone yet — planned: owner challenge-response

WARNING

Until owner authentication ships, the local endpoint's only protection is its loopback bind. Reach it remotely via Tailscale/VPN — never expose it directly.

Two databases

DatabaseFed byContainsServed by
raiznet_public.dbPublic ingest (replication planned)Devices and readings publishable to networksPublic endpoint
raiznet_private.dbLocal ingest onlylocal_only devices + fields kept off the public sideLocal endpoint only

Security by isolation: a query on the public endpoint cannot return private data because the private database connection is simply not available to it. Isolation is enforced at the database level, not the API layer.

Client layer

ClientDescriptionStatus
CLIOperations and debugging toolIn repo
Web dashboardVisualization UIIn repo
Public gatewayA node exposed on the internet — just another peer, no privileged dataPlanned
Desktop app (Tauri)Bundles a full node + UI, works offlineFuture phase
Mobile appReact Native or CapacitorFuture phase