Skip to content

Architecture

System Overview

┌──────────────┐     HTTPS      ┌──────────────┐     PostgreSQL     ┌─────────┐
│  portal-web  │ ──────────────▶│   backend    │ ──────────────────▶│   RDS   │
│  (React SPA) │                │  (Go / Chi)  │                    └─────────┘
└──────────────┘                └──────┬───────┘
                                       │ MQTT (X.509 mTLS)
                                ┌──────┴───────┐
                                │  AWS IoT Core │
                                └──────┬───────┘
                                       │ MQTT (X.509 mTLS)
                                ┌──────┴───────┐
                                │   e-ink      │
                                │   devices    │
                                └──────────────┘

Components

Backend (Go)

Modular monolith with three domains:

Module Responsibility
auth JWT authentication, OAuth (Google/Apple), session management
billing Stripe subscriptions, checkout, invoices
iot MQTT client, device registry, heartbeat processing, command delivery, device binding

AWS IoT Core

Devices connect via X.509 certificate mutual TLS. The backend connects as a privileged MQTT client (inklet-backend) that can subscribe to all device topics and publish commands.

Topic Structure

Topic Direction Purpose
inklet/dev/{thing}/up/heartbeat Device → Backend Periodic heartbeat
inklet/dev/{thing}/up/state Device → Backend Device state report
inklet/dev/{thing}/up/request_claim Device → Backend Request a claim code
inklet/dev/{thing}/down/cmd Backend → Device Commands (text, claim_code, bound, unbound)

Database Schema

users
├── sessions (JWT refresh tokens)
├── oauth_accounts (Google, Apple)
├── subscriptions (Stripe)
└── devices (bound via owner_id)
    └── device_commands (delivery log)

Key tables:

Table Primary Key Notes
users UUID v4 Email + username unique
devices UUID v7 hw_id unique, thing_name unique
device_commands UUID v7 Tracks command delivery status

Device Lifecycle

Factory → NFC tag with signed hw_id
Power on → Fleet Provisioning (claim cert → device cert)
Heartbeat loop → Backend registers device in DB
User binds device (NFC or claim code)
Backend sends commands → Device renders to display