Includes: - Backend services: ingestion (:8001), weather API (:8002), gateway (:8003), billing (:8004) with BTCPay integration - Shared asyncpg pool, TimescaleDB hypertable, Redis, Mosquitto MQTT - React frontend: Dashboard (MapLibre) and Messaging (chat UI) - Bridge daemon for Pi + Meshtastic (Serial/TCP T-Deck support) - Production Docker Compose, Nginx reverse proxy, ops scripts - DEPLOY.md with step-by-step deployment guide
KosmoConnect Gateway Service
The Gateway Service handles all web-to-mesh and mesh-to-web messaging. It is the monetization boundary of the network.
What It Does
- Subscription Enforcement: Validates that the user has an active subscription and that their plan allows messaging the target node
- Quota Management: Tracks monthly message usage and rejects requests when limits are exceeded
- Outbound Queue: Accepts web messages, stores them in PostgreSQL, and publishes them to MQTT for bridge delivery
- Inbound Consumer: Listens to
kosmo/mesh/inboundand stores replies, automatically threading them into conversations - Delivery Tracking: Message status progresses
pending -> queued -> transmitted -> delivered(future: bridge ACKs will update totransmitted)
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/messages |
Send a message to a mesh node |
| GET | /api/v1/messages/conversations |
List all conversations for the user |
| GET | /api/v1/messages/conversations/{node_id} |
Get full message history with a node |
| GET | /api/v1/messages/{message_id} |
Check delivery status of a message |
Authentication (v0.1)
For rapid development, the gateway currently uses a simple X-User-ID header to identify the caller. In production this will be replaced with JWT/OAuth2.
Billing
Subscription management is handled by the Billing Service, which integrates with the Church of Kosmo's BTCPay Server at pay.cqre.net. The Gateway does not process payments itself; it only reads subscription state from the shared PostgreSQL database.
Subscription Scopes
| Plan | Scope | Quota (example) |
|---|---|---|
wanderer |
Any node on the mesh | 50/month |
guardian |
Only whitelisted nodes | 500/month |
sanctuary |
Any node + API/webhooks | Unlimited |
free |
Receive only | 0 outbound |
Running Locally
Make sure the backend infrastructure (Postgres, MQTT) is running:
cd backend
docker-compose up -d
Seed test users (only needed once):
docker-compose exec -T timescaledb psql -U kosmo -d kosmoconnect < migrations/002_seed_test_users.sql
Start the gateway:
./run-dev.sh gateway
Testing with cURL
# Send a message (test wanderer user)
curl -X POST http://localhost:8003/api/v1/messages \
-H "Content-Type: application/json" \
-H "X-User-ID: 11111111-1111-1111-1111-111111111111" \
-d '{"target_node_id": "!a1b2c3d4", "text": "Hello mesh"}'
# List conversations
curl http://localhost:8003/api/v1/messages/conversations \
-H "X-User-ID: 11111111-1111-1111-1111-111111111111"
# Check message status
curl http://localhost:8003/api/v1/messages/{message_id} \
-H "X-User-ID: 11111111-1111-1111-1111-111111111111"
Architecture
Web Client
|
| POST /api/v1/messages (X-User-ID)
v
Gateway Service (:8003)
|- Checks subscription + quota in PostgreSQL
|- Writes message to mesh_messages (status=pending)
|- Background worker publishes pending rows to MQTT
|
v
MQTT Broker (kosmo/mesh/outbound/{node_id})
|
v
Bridge Daemon (Pi) -> Meshtastic Mesh -> Target Node
Reply path:
Target Node -> Mesh -> Bridge Daemon -> MQTT (kosmo/mesh/inbound)
|
v
Gateway Service consumes MQTT and writes reply to mesh_messages
|
v
Web Client reads via GET /api/v1/messages/conversations