33bdfa1d05 ci: containerize + arcd GHCR semver build (DOKS deploy) (#1)
Containerize apps/web (@hanzo/waitlist-demo, Next.js 16). Enable Next
standalone output (output: standalone + outputFileTracingRoot for the
pnpm monorepo so the @hanzo/waitlist widget is bundled). Add multi-stage
Dockerfile (pnpm+turbo build -> minimal node:22-slim standalone server,
no nginx/caddy, port 3000) and .github/workflows/build.yml that
builds+pushes ghcr.io/hanzoai/waitlist on v* tags via the canonical
hanzoai/.github docker-build reusable workflow on the self-hosted arcd
fleet. Semver-only tags.

Co-authored-by: hanzo-dev <z@hanzo.ai>
2026-06-19 16:22:47 -07:00
2026-01-21 00:16:29 +08:00
2026-01-21 00:16:29 +08:00
2026-01-21 00:16:29 +08:00

Hanzo Waitlist

中文

Monochromatic, brand-neutral viral waitlist. No logos, no brand colors, no embedded identity — each consumer brings its own. Backed by Hanzo Base; no Redis, no third-party SaaS.

import { Waitlist } from '@hanzo/waitlist'
import '@hanzo/waitlist/styles.css'

<Waitlist waitlist="my-product" baseUrl="https://api.example.com" />

What's in this repo

Path What
packages/widget/ @hanzo/waitlist — React + framework-free client + custom element
apps/web/ Demo site (Next.js) — brand-swappable preview
docs/ architecture, api, widget

The server lives in a different repo: ~/work/hanzo/base under plugins/waitlist/. Register it on any Base process:

import "github.com/hanzoai/base/plugins/waitlist"

waitlist.MustRegister(app, waitlist.Config{
    Enabled:         true,
    TurnstileSecret: os.Getenv("TURNSTILE_SECRET_KEY"),
    AdminSecret:     os.Getenv("WAITLIST_ADMIN_SECRET"),
})

Two collections (waitlists, waitlist_entries) are created on first boot. Three endpoints are mounted under /v1/waitlist.

Quick start (dev)

pnpm install
pnpm --filter @hanzo/waitlist build

# Terminal 1: backend (mock reference impl, in-memory)
pnpm --filter @hanzo/waitlist-mock-api dev   # listens on :8090

# Terminal 2: demo
NEXT_PUBLIC_BASE_URL=http://localhost:8090 \
  pnpm --filter @hanzo/waitlist-demo dev     # http://localhost:3000

For production you swap mock-api for a real Hanzo Base instance with plugins/waitlist registered. The mock implements the exact same /v1/waitlist/{join,status,export} contract — it's both the demo backend and the executable spec.

Theming

Zero brand colors in the widget. Bring your own selector + variables:

.your-brand {
  --hw-accent: <your accent color>;
  --hw-accent-fg: <text on accent>;
  --hw-radius: <corner radius>;
}

Logos, headlines, and any embedded identity are the host's responsibility. The widget itself ships fully neutral.

Full variable list: docs/widget.md.

API

Endpoint Purpose
POST /v1/waitlist/join Register an entry, credit referrer atomically
GET /v1/waitlist/status Look up rank + share URL
GET /v1/waitlist/export Admin CSV (superuser or shared-secret gated)

Wire format: docs/api.md.

License

MIT.

S
Description
Mirror of github.com/hanzoai/waitlist
Readme MIT
445 KiB
Languages
TypeScript 53.4%
JavaScript 24.7%
CSS 20.8%
Dockerfile 1.1%