Jon Staab ed57ff7bb7 Add toast
2026-02-26 15:45:30 -08:00
2026-02-26 15:45:30 -08:00
2026-02-25 16:10:24 -08:00
2026-02-25 16:10:24 -08:00
2026-02-25 15:18:43 -08:00

Caravel

A multi-tenant platform for hosting Nostr community relays, built on top of 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 (backend) and ref/website (frontend). Zooid is included for reference in ./ref/zooid.


Tech Stack

Frontend

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-relaymy-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); 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
S
Description
Hosting manager and dashboard for zooid relays
Readme 2.8 MiB
Languages
TypeScript 54.3%
Rust 44.9%
Dockerfile 0.3%
Just 0.2%
CSS 0.2%
Other 0.1%