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

202 lines
7.0 KiB
Markdown

# Caravel
A multi-tenant platform for hosting Nostr community relays, built on top of [zooid](./ref/zooid) — a multi-tenant relay implementation configured via TOML and an HTTP API.
---
## Overview
The platform has three main components:
1. **Backend** — Manages the zooid instance via its HTTP API, along with tenants (users), virtual relays, invoices, and billing.
2. **Tenant Dashboard** — A web app where anyone can sign up, pay for a relay via Lightning, and manage their relay's membership, metadata, access, and policies.
3. **Super Admin Dashboard** — A restricted interface for the infrastructure owner to manage tenants and their relays.
A proof of concept exists in [`ref/metamanager`](./ref/metamanager) (backend) and [`ref/website`](./ref/website) (frontend). Zooid is included for reference in ./ref/zooid.
---
## Tech Stack
**Frontend**
- Bun
- TypeScript
- SolidJS
- Preline UI
- https://applesauce.build/
- tanstack tools where relevant
**Backend**
- Rust
- Sqlite
---
## Database Schema
### `tenants`
Users of the platform. Identified by their Nostr public key.
| Field | Description |
|---|---|
| `pubkey` | Primary key — Nostr public key |
| `status` | Account status (active, suspended, etc.) |
| `tenant_nwc_url` | Tenant-provided NWC URL for recurring billing |
### `relays`
Virtual relays linked to a tenant.
| Field | Description |
|---|---|
| `id` | Primary key |
| `tenant` | Foreign key → tenants |
| `name` | Human-readable relay name |
| `subdomain` | Subdomain slug (e.g. `my-relay``my-relay.spaces.coracle.social`) |
| `schema` | zooid DB schema name (subdomain with dashes replaced by underscores; stored for reference only) |
| `icon` | Relay icon URL |
| `description` | Relay description |
| `plan` | Pricing tier: `free`, `basic`, or `growth` |
| `status` | Relay status (pending, active, suspended, etc.) |
### `invoices`
Invoices generated for tenants, potentially covering multiple relays in a single payment.
| Field | Description |
|---|---|
| `id` | Primary key |
| `tenant` | Foreign key → tenants |
| `amount` | Total invoice amount (sats) |
| `status` | Payment status (pending, paid, expired, etc.) |
| `created_at` | Timestamp |
| `invoice` | Lightning invoice string |
### `invoice_items`
Line items linking an invoice to a specific relay charge.
| Field | Description |
|---|---|
| `id` | Primary key |
| `invoice` | Foreign key → invoices |
| `relay` | Foreign key → relays |
| `amount` | Amount for this relay (sats) |
| `period_start` | Start of billing period |
| `period_end` | End of billing period |
---
## Pricing Tiers
| Tier | Price | Members | Blossom | LiveKit |
|---|---|---|---|---|
| **Free** | 0 sats/mo | Up to 10 | No | No |
| **Basic** | 10,000 sats/mo | Up to 100 | Yes | Yes |
| **Growth** | 50,000 sats/mo | Unlimited | Yes | Yes |
---
## Backend
> Do not modify zooid directly. All relay management goes through its HTTP API (`zooid/api.go`).
### Authentication
- All endpoints are authenticated using NIP 98
### Responsibilities
- Manage zooid virtual relays via the HTTP API
- Tenant and relay CRUD
- Lightning invoice generation and collection
- Billing: recurring charges, grace periods, NIP-17 DM notifications
- Async job runner for billing checks, invoice collection, and relay provisioning
### Relay Provisioning
When a relay is created, an async worker is spawned that sends the appropriate API request to zooid to set up the virtual relay. Status updates to `active` on success and `provisioning_failed` on error.
### Billing Logic
- Billing is monthly. Invoices batch all of a tenant's relay charges into a single payment.
- Tenants can enable **recurring billing** by providing their own NWC URL on the account page. The platform uses this to pull payments automatically.
- If recurring billing is off, invoices are sent via **NIP-17 DMs** (from the platform's Nostr key) when a subscription is due. If recurring billing is on, still send notifications when a payment is made.
- A **7-day grace period** applies before access is restricted for non-payment.
### Environment Variables
| Variable | Description |
|---|---|
| `PLATFORM_ADMIN_PUBKEYS` | Comma-separated Nostr pubkeys with super admin access |
| `PLATFORM_SECRET` | Nostr private key used by the platform to send NIP-17 DMs |
| `NWC_URL` | Nostr Wallet Connect URL used by the platform to generate Lightning invoices |
| `NOSTR_INDEXER_RELAYS` | Relays used to fetch kind `10050` DM relay lists |
| `PLATFORM_NAME` | Platform display name (published as kind `0`) |
| `PLATFORM_DESCRIPTION` | Platform description (published as kind `0`) |
| `PLATFORM_PICTURE` | Platform picture URL (published as kind `0`) |
| `PLATFORM_MESSAGING_RELAYS` | Relays published in kind `10050` for DMs |
---
## Frontend
### Marketing Page (`/`)
- Describes the value proposition, features, and brand
- Prominent **"Get Started"** button linking to the new relay form
- A "Log In" button, replaced by a "Dashboard" button when the user is logged in
### Login Page (`/login`)
- Uses nonboard to log the user in
### Tenant dashboard
- All requests are authenticated using NIP 98 against the tenant pubkey
#### Relays Page (`/relays`)
- **My Relays** — searchable, filterable list of the user's relays
- **Add Relay** button (top right)
- Link to account page
#### Relay Detail Page (`/relays/{id}`)
- Shows relay information (name, url, description, plan)
- Actions: edit relay, deactivate
### New Relay Form (`/relays/new`)
- Requires Nostr login (via the `nonboard` plugin — see [`ref/website`](./ref/website)); the NIP-98 auth token is used to identify the tenant
- Fields:
- Relay name
- Subdomain (auto-generated from name, editable; displayed as `<subdomain>.spaces.coracle.social`)
- Icon URL
- Description
- Plan selection — shown as a comparison table (see Pricing Tiers)
- On submit (if plan is not free): generates a Lightning invoice
- User can scan QR code, click to open in wallet, or copy invoice string
- **"I've paid the invoice"** button — checks invoice status and reports to user
- On confirmed payment: redirect to tenant dashboard
### Account Page (`/account`)
- Account status
- Complete invoice history
- Toggle for recurring billing via Nostr Wallet Connect (tenant provides their own NWC URL)
### Super Admin Dashboard (`/admin`)
- Authenticated via NIP-98 against `PLATFORM_ADMIN_PUBKEYS`
- No link to this page from any other page
#### Tenants Page (`/admin/tenants`)
- Searchable, filterable list of all tenants
#### Tenant Detail Page (`/admin/tenants/{id}`)
- All their relays
- Account status
- Actions: deactivate tenant and all their relays
#### Relays Page (`/admin/relays`)
- Searchable, filterable list of all relays
- Link to owning tenant
- Actions: update or deactivate any relay
#### Relay Detail Page (`/admin/relays/{id}`)
- Show relay information
- Actions: edit or deactivate relay
#### Relay Edit Form (`/admin/relays/{id}/edit`)
- Edit relay name, subdomain, icon, description, and plan
### Relay Edit Form (`/relays/{id}/edit`)
- Edit relay name, subdomain, icon, description, and plan