diff --git a/README.md b/README.md new file mode 100644 index 0000000..0271dc6 --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# Nostr Community Relay Hosting Platform + +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 +- shadcn/ui + +**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.) | + +### `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) | +| `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. + +### 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. +- A **7-day grace period** applies before access is restricted for non-payment. + +### Environment Variables +| Variable | Description | +|---|---| +| `HOSTING_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 | + +--- + +## 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 `.spaces.coracle.social`) + - 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 `HOSTING_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, description, and plan + +### Relay Edit Form (`/relays/{id}/edit`) +- Edit relay name, subdomain, description, and plan