Implementation and use
ATLAS sells a snapshot. Emberline sells the desk: the watch, the fail-closed brief, the archive, and the commercial envelope around Hub SKUs.
Value beyond ATLAS
If you only need one invoke, buy atlas.watchbox.check@v1 / atlas.fire.weather@v1 and stop. Emberline is for a named box over time.
| Layer | What you get |
|---|---|
| Watch ops | Named bbox, 15/30/60 cadence, quiet hours, on_match vs always_brief. |
| Fail-closed brief | Empty LIVE stays empty. SIM never appears. Badges: not a perimeter, forecast, or evacuation order. |
| Archive | Citeable JSON, run-to-run delta, cite pack (PDF + SHA256), raw Hub payloads. |
| Receipt check | Ed25519 material verified when present (emberline_verified). |
| Delivery | HTTPS webhooks (HMAC t=,v1=), Slack, desk PWA push. Email is not a channel. SMTP is desk-only later. |
| Envelope | Plan caps, prepaid emb_ desk keys, one Hub key for the org. |
always_brief on a tight cadence will burn a Team plan. on_match is the default that can be profitable.
Implementation
Local
cp .env.example .env make up # http://localhost:8080
Development compose may seed a demo owner. Production compose will not boot with that seed or the default JWT secret.
Production
export JWT_SECRET=… POSTGRES_PASSWORD=… HUB_API_KEY=… PAY_MINT_SECRET=… export PUBLIC_URL=https://emberlinedesk.com export CORS_ORIGINS=https://emberlinedesk.com docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d
Terminate TLS in front of nginx. Do not publish :5432 or :8000. HUB_MODE=live refuses invokes without a key.
Mint a prepaid key
POST /api/pay/mint
X-Emberline-Mint: $PAY_MINT_SECRET
{"plan":"solo","days":30,"payment_ref":"np_invoice_123"}
Show desk_key once. Duplicate payment_ref → 409. Buyer redeems at login or POST /api/auth/redeem.
Usage
- Sign in with password or desk key.
- Create a watch. Cap bbox at 40° × 30°. Prefer
on_match. - Optional quiet hours
22-06. Runs continue; alerts pause. - Optional Slack / HTTPS hooks — https and public DNS only. Copy the HMAC secret immediately.
- Read briefs from Archive. A quiet run is not a safety guarantee.
HTTPS alert header: X-Emberline-Signature: t=<unix>,v1=<hex> over {ts}.{body}.
API surface
Cookie emberline_session or Authorization: Bearer. Production hides OpenAPI.
| Path | Purpose |
|---|---|
| POST /api/auth/login | /redeem | /logout | Session |
| GET/POST /api/watches | List / create |
| POST /api/watches/{id}/run | 402 if monthly cap hit |
| GET /api/briefs/{id} | Citeable brief (auth) |
| GET /api/public/briefs/{token} | Unlisted share; token ≠ id |
| GET /api/billing/usage | Meter, not a charge |
| GET /api/push/status | VAPID public key + whether this session subscribed |
| POST /api/pay/mint | Operator mint |
Operations
- Scheduler every 5 minutes; process lock + Postgres advisory lock 87421001.
- Backup volume
emberline_pg— the archive is the product. - Email is not a delivery channel. SMTP is desk-only (named-seat mail later). Alerts: app UI, PWA push, Slack, HTTPS webhooks.
- Never invent a perimeter during an outage. Publish
no_live_evidenceor nothing.
Markdown sources live in the repository under docs/enterprise/.