Add frontend spec

This commit is contained in:
Jon Staab
2026-03-26 13:49:46 -07:00
parent 9f737a25cd
commit a2239cf20e
17 changed files with 609 additions and 4 deletions
+29
View File
@@ -0,0 +1,29 @@
# Account
The account page lets an authenticated tenant manage billing settings and review invoice history.
```pug
page(path="/account", auth="required", shell="app")
header
title My Account
section(id="status")
heading Account Status
badge tenant
section(id="billing")
heading Recurring Billing
description Enable automatic payments by providing your Nostr Wallet Connect URL.
input(name="nwc_url", placeholder="nostr+walletconnect://...")
button Save
error_message(on="save_failure")
section(id="invoices")
heading Invoice History
loading_state(message="Loading invoices...")
list(empty="No invoices yet")
item
status
created_at
bolt11
```
+25
View File
@@ -0,0 +1,25 @@
# Admin Relay Detail
The admin relay detail page exposes relay state and controls with admin-level editing and deactivation.
```pug
page(path="/admin/relays/:id", auth="required", role="admin", shell="app")
back_link(href="/admin/relays", label="Relays")
loading_state(message="Loading relay...")
error_state(message="Failed to load relay.")
relay_detail_card(edit_href="/admin/relays/:id/edit", show_tenant=true, enforce_plan_limits=false, show_plan_actions=false)
actions
button(action="admin_deactivate_relay") Deactivate
toggles
toggle(name="policy_public_join") Public join
toggle(name="policy_strip_signatures") Strip signatures
toggle(name="groups_enabled") Groups
toggle(name="management_enabled") Management API
toggle(name="blossom_enabled") Media storage
toggle(name="livekit_enabled") LiveKit support
toggle(name="push_enabled") Push notifications
error_message(on="mutation_failure")
```
+21
View File
@@ -0,0 +1,21 @@
# Admin Relay Edit
The admin relay edit page updates relay metadata and returns to the admin relay detail view.
```pug
page(path="/admin/relays/:id/edit", auth="required", role="admin", shell="app")
back_link(href="/admin/relays/:id", label="Back")
header
title Edit Relay (Admin)
loading_state(message="Loading relay...")
error_state(message="Failed to load relay.")
form(action="admin_update_relay")
field(name="name", label="Relay Name", required=true)
field(name="subdomain", label="Subdomain", required=true)
field(name="icon", label="Icon URL", type="url")
field(name="description", label="Description", type="textarea")
submit_button(default="Save Changes", loading="Saving...")
error_message(on="submit_failure")
```
+22
View File
@@ -0,0 +1,22 @@
# Admin Relay List
The admin relay list page shows all relays with search for operators.
```pug
page(path="/admin/relays", auth="required", role="admin", shell="app")
header
title Relays
controls
input(type="search", name="query", placeholder="Search relays...")
loading_state(message="Loading relays...")
error_state(message="Failed to load relays.")
list(empty="No relays found")
item(link="/admin/relays/:id")
title relay.info_name || relay.subdomain
subtitle {relay.subdomain}.spaces.coracle.social
tenant relay.tenant
status relay.status
```
@@ -0,0 +1,25 @@
# Admin Tenant Detail
The admin tenant detail page shows tenant status and all relays for a selected tenant.
```pug
page(path="/admin/tenants/:id", auth="required", role="admin", shell="app")
back_link(href="/admin/tenants", label="Tenants")
header
title Tenant :id
loading_state(message="Loading tenant...")
error_state(message="Failed to load tenant.")
section(id="status")
heading Status
text Current: tenant
section(id="relays")
heading Relays
list(empty="No relays")
item(link="/admin/relays/:id")
title relay.info_name || relay.subdomain
subtitle {relay.subdomain}.spaces.coracle.social
status relay.status
```
+23
View File
@@ -0,0 +1,23 @@
# Admin Tenant List
The admin tenant list page shows all tenants with profile-enriched search results.
```pug
page(path="/admin/tenants", auth="required", role="admin", shell="app")
header
title Tenants
controls
input(type="search", name="query", placeholder="Search tenants...")
loading_state(message="Loading tenants...")
error_state(message="Failed to load tenants.")
list(empty="No tenants found")
item(link="/admin/tenants/:pubkey")
avatar(profile.picture)
title profile.name || shortened_pubkey
subtitle profile.about || "No profile bio"
meta tenant.pubkey
badge tenant
```
+86
View File
@@ -0,0 +1,86 @@
# Home
The home page is a marketing page with CTAs to create a relay or log in (if the user isn't logged in). If the user is logged in, "Sign in" actions are replaced with "Dashboard" and route to `/relays`.
```pug
page(path="/")
nav(sticky=true)
brand(name="Caravel", logo="/caravel.png")
if(authenticated)
link(href="/relays") Dashboard
else
link(href="/login") Sign in
section(id="hero")
badge Nostr-native relay hosting
hero
title Your community, your relay.
description Spin up private, managed infrastructure for your community in minutes. Full control over membership, access, and policies — no DevOps required.
actions
button(variant="primary", href="/relays/new") Get started free
if(authenticated)
button(variant="neutral", href="/relays") Dashboard
else
button(variant="neutral", href="/login") Sign in
section(id="features")
heading
title Everything you need
description Caravel takes care of the infrastructure so you can focus on building your community.
grid(columns=3)
card(icon="hosting")
title Managed hosting
description We handle uptime, backups, and updates. Your relay stays online so your community never misses a beat.
card(icon="membership")
title Membership control
description Approve members with Nostr pubkeys. Keep your space invite-only or open — you decide.
card(icon="shield")
title Access policies
description Fine-grained write and read permissions. Moderate content without touching any server config.
card(icon="storage")
title Blossom storage
description Attach media files to your relay with integrated Blossom server support on paid plans.
card(icon="video")
title LiveKit video
description Built-in video room support via LiveKit. Host voice and video calls directly within your community.
card(icon="lightning")
title Pay with sats
description Lightning-native billing. No credit cards, no bank accounts — just sats, straight from your wallet.
section(id="connect")
heading
title Connect with your community
description Once your relay is live, these Nostr-native platforms let your members connect, chat, and collaborate — all powered by your relay.
grid(columns=2)
product(name="Flotilla", href="https://flotilla.social", domain="flotilla.social")
description A community platform built on Nostr. Flotilla gives your members channels, threads, and a rich social experience — all connected to your relay.
bullets
item Nostr-native channels & threads
item Works directly with your relay
item Open source & self-sovereign
product(name="Chachi", href="https://chachi.chat", domain="chachi.chat")
description A group chat app built on top of Nostr. Chachi makes it easy for your community to have real-time conversations, all flowing through your own relay.
bullets
item Real-time group messaging
item Bring your own relay
item No accounts — just your Nostr key
section(id="pricing")
heading
title Simple pricing
description Pay in sats. Upgrade or cancel any time.
pricing_table(cta_href="/relays/new")
section(id="cta")
heading
title Ready to launch your relay?
description Join communities already running on Caravel. Set up in minutes, pay in sats.
button(variant="primary", href="/relays/new") Create your relay
footer
brand(name="Caravel", logo="/caravel.png")
copyright © {currentYear} Caravel. Built on Nostr.
links
link(href="https://flotilla.social") Flotilla
link(href="https://chachi.chat") Chachi
```
+67
View File
@@ -0,0 +1,67 @@
# Login
The login page authenticates users with Nostr via extension, remote signer (NIP-46), or key material, then redirects to `/relays`.
```pug
page(path="/login")
hero
badge Secure Nostr Login
title Welcome back
description Connect your Nostr account to manage relay hosting, billing, and access in one place.
bullets
item Own your identity with cryptographic sign-in.
item No passwords or email required.
item Get fast access to your relays.
auth_card
section(id="method_select")
title Log in / Sign up
description Use any Nostr signer method. New users are automatically onboarded.
tabs
tab(id="nip07") Extension
tab(id="nip46") Signer
tab(id="key") Key
when(tab="nip07")
button Continue with extension
when(tab="nip46")
button Continue with signer
when(tab="key")
button Continue with key
screen(id="nip46")
back_button Back
title Log in with signer
tabs
tab(id="qr") Use QR Code
tab(id="paste") Paste Link
when(tab="qr")
qr_code
copyable_input(name="nostrconnect_uri")
when(tab="paste")
input(name="bunker_url", placeholder="bunker://...")
button Scan QR code
button Connect to Signer
screen(id="key")
back_button Back
title Log in with key
tabs
tab(id="plaintext") Plaintext
tab(id="encrypted") Encrypted
when(tab="plaintext")
input(name="nsec", placeholder="nsec1...")
when(tab="encrypted")
input(name="ncryptsec", placeholder="ncryptsec1...")
input(type="password", name="password", placeholder="Password")
button Log in
error_message
help_text Having trouble? Make sure your signer is unlocked and connected.
modal(id="scanner")
title Scan QR Code
camera_preview
```
+27
View File
@@ -0,0 +1,27 @@
# Relay Detail
The relay detail page shows relay status and settings for an authenticated tenant, with inline toggles and plan changes.
```pug
page(path="/relays/:id", auth="required", shell="app")
back_link(href="/relays", label="Relays")
loading_state(message="Loading relay...")
error_state(message="Failed to load relay.")
relay_detail_card(edit_href="/relays/:id/edit")
actions
button(action="deactivate_relay") Deactivate
toggles
toggle(name="policy_public_join") Public join
toggle(name="policy_strip_signatures") Strip signatures
toggle(name="groups_enabled") Groups
toggle(name="management_enabled") Management API
toggle(name="blossom_enabled") Media storage
toggle(name="livekit_enabled") LiveKit support
toggle(name="push_enabled") Push notifications
plan_selector(action="update_plan")
member_count(source="relay_url")
error_message(on="mutation_failure")
```
+21
View File
@@ -0,0 +1,21 @@
# Relay Edit
The relay edit page lets an authenticated tenant update relay metadata and returns to relay detail on success.
```pug
page(path="/relays/:id/edit", auth="required", shell="app")
back_link(href="/relays/:id", label="Back")
header
title Edit Relay
loading_state(message="Loading relay...")
error_state(message="Failed to load relay.")
form(action="update_tenant_relay")
field(name="name", label="Relay Name", required=true)
field(name="subdomain", label="Subdomain", required=true)
field(name="icon", label="Icon URL", type="url")
field(name="description", label="Description", type="textarea")
submit_button(default="Save Changes", loading="Saving...")
error_message(on="submit_failure")
```
+29
View File
@@ -0,0 +1,29 @@
# Relay List
The relay list page shows an authenticated tenant's relays with search and status filtering.
```pug
page(path="/relays", auth="required", shell="app")
header
title My Relays
button(href="/relays/new") Add Relay
controls
input(type="search", name="query", placeholder="Search by name or subdomain")
select(name="status")
option(value="all") All statuses
option(value="active") Active
option(value="pending") Pending
option(value="deactivated") Deactivated
option(value="provisioning_failed") Provisioning failed
option(value="suspended") Suspended
loading_state(message="Loading relays...")
error_state(message="Failed to load relays.")
list(empty="No relays found")
item(link="/relays/:id")
title relay.info_name || relay.subdomain
subtitle https://{relay.subdomain}.spaces.coracle.social
status relay.status
```
+32
View File
@@ -0,0 +1,32 @@
# Relay New
The new relay page lets an authenticated tenant configure and create a relay, then navigates to its detail page.
```pug
page(path="/relays/new", auth="required", shell="app")
header
title New Relay
form(action="create_tenant_relay")
field(name="name", label="Relay Name", required=true, placeholder="My Community")
field(name="subdomain", label="Subdomain", required=true, suffix=".spaces.coracle.social", placeholder="my-community")
field(name="icon", label="Icon URL", type="url", placeholder="https://example.com/icon.png")
field(name="description", label="Description", type="textarea", placeholder="A community for...")
field(name="plan", label="Plan")
option(value="free")
title Free
price Free
members Up to 10 members
option(value="basic")
title Basic
price 10,000 sats/mo
members Up to 100 members
option(value="growth")
title Growth
price 50,000 sats/mo
members Unlimited members
tooltip_error(field="subdomain")
submit_button(default="Create Relay", loading="Creating...")
```