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 |