Files
caravel/backend/README.md
T
2026-02-25 15:18:43 -08:00

128 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backend
Rust backend for the Nostr relay hosting platform. This service manages tenants, relays, invoices, and billing, and provisions relays by calling the zooid HTTP API. It authenticates requests using NIP-98.
## Tech Stack
- Rust (Edition 2024)
- Axum (HTTP server)
- SQLx + SQLite (persistence)
- Nostr SDK (NIP-98 verification)
## Layout
```
backend/
migrations/ # SQL migrations
src/
auth.rs # NIP-98 verification helper
billing.rs # Billing loop + invoice generation
config.rs # Env-based configuration
db.rs # SQLite pool + migrations
main.rs # Axum server entrypoint
models.rs # Data models
notifications.rs # NIP-17 DM sender + relay discovery
platform.rs # Startup kind 0/10050 publishing
provisioning.rs # Zooid provisioning worker
repo.rs # Data access layer
```
## Configuration
Environment variables:
| Variable | Description | Default |
|---|---|---|
| `DATABASE_URL` | SQLite database URL | `sqlite://data/caravel.db` |
| `HOST` | Bind host | `127.0.0.1` |
| `PORT` | Bind port | `3000` |
| `ZOOID_API_URL` | Zooid API base URL | `http://127.0.0.1:8032` |
| `PLATFORM_SECRET` | Platform Nostr secret key for NIP-98 auth | _required_ |
| `RELAY_DOMAIN` | Relay base domain for subdomains | `spaces.coracle.social` |
| `NWC_URL` | Platform NWC URL for invoice generation | _required for billing_ |
| `NOSTR_INDEXER_RELAYS` | Comma-separated relays to fetch kind `10050` DM relays | _required for notifications_ |
| `PLATFORM_NAME` | Platform display name for kind `0` metadata | _optional_ |
| `PLATFORM_DESCRIPTION` | Platform description for kind `0` metadata | _optional_ |
| `PLATFORM_PICTURE` | Platform picture URL for kind `0` metadata | _optional_ |
| `PLATFORM_MESSAGING_RELAYS` | Comma-separated relays published in kind `10050` | _optional_ |
The database directory is created automatically if it doesnt exist.
## Database Schema
Created via `migrations/0001_init.sql`:
- `tenants`
- `relays`
- `invoices`
- `invoice_items`
## Running
```bash
cd backend
cargo run
```
Health check:
```
GET /healthz
```
## NIP-98 Authentication
NIP-98 verification is implemented in `auth.rs` using the Rust Nostr SDK. It verifies:
- Authorization header format
- Event signature and kind
- URL + HTTP method tags
- Timestamp validity
This is ready to be used by API routes.
## Billing Jobs
The backend runs an in-process billing loop that:
- Generates monthly invoices (using `NWC_URL`)
- Uses the tenants `tenant_nwc_url` for recurring pull payments (if set)
- Sends NIP-17 DMs with invoices when recurring is off
- Sends NIP-17 DMs on successful payment when recurring is on
NIP-17 relay discovery:
- Uses `NOSTR_INDEXER_RELAYS` to fetch kind `10050` for each tenant
- Cached for a short period
- If no relays are found, no DM is sent
On startup, the backend publishes:
- Kind `0` metadata (name/description)
- Kind `10050` relay list for DMs
These are published to the relays listed in `NOSTR_INDEXER_RELAYS`.
## API Routes
Tenant routes (all require NIP-98 auth; pubkey is inferred from the token):
- `GET /tenant` — fetch (or create) tenant
- `GET /tenant/relays` — list tenant relays
- `POST /tenant/relays` — create relay
- `GET /tenant/relays/:id` — get relay
- `PUT /tenant/relays/:id` — update relay
- `DELETE /tenant/relays/:id` — deactivate relay
- `GET /tenant/invoices` — list invoices
- `PUT /tenant/billing` — update tenant billing (NWC URL)
Admin routes (all require NIP-98 auth; pubkey must be in `PLATFORM_ADMIN_PUBKEYS`):
- `GET /admin/tenants` — list tenants
- `GET /admin/tenants/:pubkey` — tenant detail (includes relays)
- `PUT /admin/tenants/:pubkey` — update tenant status
- `GET /admin/relays` — list relays
- `GET /admin/relays/:id` — get relay
- `PUT /admin/relays/:id` — update relay
- `DELETE /admin/relays/:id` — deactivate relay