Skip to content
FLAVIO COPES
flaviocopes.com
Waiting Lists diagram showing subscribers joining a self-hosted list

Web App · version 1.0

Waiting Lists

A self-hosted waiting-list web app with an included command-line client. Run it from your terminal or let a coding agent create lists, connect forms, inspect subscribers, and export data through the private API.

AstroCloudflare WorkersD1HTMXAlpine.jsTypeScriptNode.js CLI

Join the Flavio Copes newsletter

Join the newsletter to access my complete download library, including books, courses, and software. I’ll also email you about new software, building products with AI, and my courses. You can unsubscribe anytime.

Your email is stored on a secure server in the EU. Every email has an unsubscribe link. Unsubscribing stops future emails; you can keep using the public download library.

Why I built this

A waiting list should be one of the smallest pieces of a product launch, but it often turns into a pile of forms, email tools, spreadsheets, consent questions, and glue code. I wanted one focused service that could collect an email safely, prove consent, and stay easy to operate.

Waiting Lists is the real, working result: a public collection endpoint, deliberate double opt-in, a private dashboard, export formats, delivery status, cleanup rules, and a private interface that AI agents can use without putting keys in a project repository.

From form to confirmed subscriber

The whole waiting-list lifecycle is already connected.

  1. Create a list in the dashboard or included CLI.
  2. Drop the generated form into any site.
  3. Confirm ownership through double opt-in.
  4. Review or export subscribers in the dashboard or terminal.

Features

Double opt-in

Keep new requests pending until the address owner reviews and confirms through a single-use 24-hour link.

Private dashboard

Create lists, inspect confirmed and pending subscribers, review delivery problems, and manage settings.

Drop-in forms

Post email and explicit consent from any approved website using generated HTML or JavaScript.

Included CLI and private API

Create, inspect, update, integrate, and export lists from a terminal or coding agent. The CLI source and its complete guide are in the download.

Useful exports

Download consent archives, universal email files, and Sendy, Kit, or Mailchimp-ready CSVs.

Privacy-minded lifecycle

Minimize collected data, avoid storing IP addresses, support signed removal links, and clean up expired records.

Use cases

Product launches

Give each upcoming product its own endpoint, consent wording, origin rules, and export.

Client projects

Run one private service for several sites while keeping every list separately manageable.

Agent-built sites

Let a coding agent create the list and connect the form through a documented command-line contract.

Self-hosted lead capture

Own the source, deployment, subscriber database, retention policy, and email delivery path.

Email-provider staging

Collect and confirm interest before moving approved addresses into the newsletter system you prefer.

SaaS starting point

Add accounts, organizations, billing, or hosted onboarding to turn the single-owner tool into a service.

Tech stack

Application

Astro

Renders the public site, private dashboard, confirmation flow, and server endpoints.

Runtime

Cloudflare Workers

Runs HTTP requests, the Queue consumer, scheduled cleanup, and static asset delivery.

Persistence

D1

Stores lists, consent records, subscriber state, sessions, API keys, settings, and delivery events.

Transactional email

Email Service

Sends confirmation and removal links from a restricted sender binding.

Interaction

HTMX and Alpine.js

Add focused form and dashboard behavior without a separate client application.

Verification

Vitest

Covers authentication, tokens, API behavior, validation, exports, Turnstile, and email events.

Command line

Node.js CLI

Uses the private API to create, inspect, update, integrate, and export lists without putting credentials in a project repository.

CLI

The ZIP contains the CLI source, package scripts, the authenticated API it calls, and a dedicated CLI.md guide. It runs directly from the downloaded repository. Nothing depends on a separately published CLI package.

npm run waitinglists -- init

Create a list and link it to the current project.

npm run waitinglists -- lists

List waiting lists and confirmed subscriber counts.

npm run waitinglists -- integration

Print the exact endpoint and form markup for a linked list.

npm run waitinglists -- export

Save a private CSV export with restricted file permissions.

Screenshots and demos

Waiting Lists dashboard showing confirmed subscribers and active waiting lists
Waiting Lists dashboard showing confirmed subscribers and active waiting lists. Open the full-size image.
Agent-ready form setup guide with the endpoint contract and implementation brief
Agent-ready form setup guide with the endpoint contract and implementation brief. Open the full-size image.
Waiting-list settings for the list name, endpoint slug, and allowed website origins
Waiting-list settings for the list name, endpoint slug, and allowed website origins. Open the full-size image.
Waiting Lists agent access screen for creating API keys and configuring the included CLI
Waiting Lists agent access screen for creating API keys and configuring the included CLI. Open the full-size image.

Usage manual

Run it and make it yours.

The setup and usage guide from the ZIP. Read it before downloading so you know what the software needs.

Waiting Lists is a self-hosted, email-only waiting-list service with double opt-in, a private dashboard, an agent-ready API and CLI, CSV exports, and privacy-minded retention controls.

Current release: 1.0 (1.0.0 in package metadata). See CHANGELOG.md for release notes.

This download package was created from commit 71bc1c9e86ba04f5fe73d372d8f2f23bc56ed79d dated 2026-07-31. Live credentials, account identifiers, analytics, deployment history, dependencies, and build output are intentionally excluded.

What is included

  • Complete Astro and TypeScript source in code/
  • Cloudflare Worker, D1 migrations, Queue consumer, Cron cleanup, rate limits, Turnstile, and Email Service integration
  • Admin authentication, waiting-list management, delivery status, and CSV exports
  • Public HTML/JSON subscription endpoint with per-list origin controls
  • Private JSON API and complete command-line client for terminal use, AI agents, and automation
  • Dedicated CLI.md guide with setup, command reference, common workflows, and credential handling
  • Automated tests for authentication, API keys, consent tokens, CSV, email events, country data, Turnstile, and validation
  • Human setup instructions here and dedicated instructions for AI coding agents in AGENTS.md

Human quick start

1. Prerequisites

Install Node.js 22 or newer. Create a Cloudflare account if you want to use the included deployment path.

2. Install and verify

cd code
npm ci
npm run check
npm test

3. Create local settings

cp .dev.vars.example .dev.vars

Replace every placeholder in .dev.vars. Generate separate random values for SESSION_SECRET and SUBSCRIBER_TOKEN_SECRET. Generate ADMIN_PASSWORD_HASH from a strong password:

printf %s 'your-high-entropy-password' | openssl dgst -sha256

4. Prepare the local database

npm run db:migrate:local
npm run dev

Open the local URL shown by Astro, then visit /login and sign in with the administrator credentials from .dev.vars.

5. Create and connect a list

Create a waiting list in the dashboard. Add the exact browser origins that may submit to it. The list page generates ready-to-copy HTML, JavaScript, and an AI-agent integration brief.

6. Use the included CLI

Create an API key at /admin/agent, then follow CLI.md to configure the command-line client without putting the key in shell history.

npm run waitinglists -- help
npm run waitinglists -- init --name "My product" --origin "https://example.com"

The CLI can create, list, inspect, update, integrate, and export waiting lists. It runs from code/cli/waitinglists.mjs and uses the private API included in this package.

Before deploying, continue with CONFIGURATION.md, SECURITY.md, and DEPLOYMENT.md.

Project map

  • code/src/pages/ — public, admin, and API routes
  • code/src/lib/ — auth, database, consent, email, API keys, validation, and exports
  • code/src/worker.ts — Worker entry, Queue consumer, and scheduled cleanup
  • code/migrations/ — D1 schema history
  • code/cli/ — complete command-line client for people, coding agents, and automation
  • code/wrangler.jsonc — portable Cloudflare configuration with placeholders

Change the stack

The included Astro and Cloudflare implementation is a working reference, not a lock-in contract. The behavior, data model, edge cases, and tests are the blueprint. You can ask an AI coding agent to move the UI, database, email provider, framework, or deployment platform while preserving the product contract described in these documents.

Read AGENTS.md first when handing the package to an AI coding agent.

CLI reference

Commands for terminals, scripts, and coding agents.

The command-line workflows and options included with the software.

The download includes a working Waiting Lists CLI in code/cli/waitinglists.mjs. It uses the included private JSON API, so you can manage waiting lists from a terminal or let a coding agent do it through a small, predictable command set.

The CLI runs directly from this repository. It is not a separately published npm package and does not require a global install.

Before you start

  1. Install the project and run the database migrations as described in README.md.
  2. Start the app locally or deploy it to infrastructure you control.
  3. Sign in to the private dashboard and open /admin/agent.
  4. Create an API key. Copy it when shown because the app stores only its hash.

Configure the CLI

From code/, pass the key through standard input so it does not appear in shell history:

read -s WAITINGLISTS_API_KEY
printf %s "$WAITINGLISTS_API_KEY" | npm run waitinglists -- configure \
  --key-stdin \
  --api-url https://waiting-lists.example/api/v1
unset WAITINGLISTS_API_KEY

For local development, omit --api-url. The CLI defaults to http://localhost:4321/api/v1.

The CLI saves credentials to ~/.config/waitinglists/credentials.json with owner-only permissions. You can instead provide WAITINGLISTS_API_KEY and WAITINGLISTS_API_URL as environment variables.

Create and link a list

Run this from the website project that will use the waiting list:

node /path/to/waiting-lists/code/cli/waitinglists.mjs init \
  --name "My product" \
  --origin "https://example.com"

init creates the list and writes .waitinglists.json in the current directory. This file contains the non-secret list ID, slug, and public collection endpoint. It is safe to commit if your project benefits from sharing that link.

If you run the command from inside the downloaded code/ directory, use the shorter form:

npm run waitinglists -- init --name "My product" --origin "https://example.com"

Commands

waitinglists configure --key-stdin [--api-url URL]
waitinglists init --name NAME --origin URL [--slug SLUG] [--json]
waitinglists create --name NAME --origin URL [--slug SLUG] [--json]
waitinglists lists [--json]
waitinglists show [LIST_ID] [--json]
waitinglists update [LIST_ID] [--name NAME] [--slug SLUG] [--origin URL] [--json]
waitinglists integration [LIST_ID] [--json]
waitinglists export [LIST_ID] [--format archive|universal|sendy|kit|mailchimp] --output FILE

Use npm run waitinglists -- help to print the same reference in the terminal.

Most commands accept a list ID. After init, commands run in the linked project can read the ID from .waitinglists.json instead.

Common workflows

List every waiting list:

npm run waitinglists -- lists

Print the linked list and its subscriber summary as JSON:

npm run waitinglists -- show --json

Get the public endpoint and generated form markup:

npm run waitinglists -- integration

Change the allowed browser origin:

npm run waitinglists -- update --origin "https://www.example.com"

Export confirmed subscribers without printing personal data to the terminal:

npm run waitinglists -- export \
  --format universal \
  --output confirmed-subscribers.csv

The export command refuses to overwrite an existing file and creates the new file with owner-only permissions.

Coding-agent use

Give your coding agent this package and ask it to read AGENTS.md and CLI.md. The agent can then use --json for structured output, create or inspect a list, fetch its integration markup, and connect the public form.

Do not put an API key in AGENTS.md, .waitinglists.json, prompts, source files, or Git. Configure it once through standard input or expose it to a trusted process through WAITINGLISTS_API_KEY.

Troubleshooting

  • No API key configured means the credentials file and WAITINGLISTS_API_KEY are both missing.
  • 401 Unauthorized means the key is invalid or has been revoked in /admin/agent.
  • No list ID supplied means the current directory has no .waitinglists.json; pass a list ID or run init.
  • Origin errors mean the collecting site's exact browser origin is missing from the list configuration.

Architecture

See how the software is put together.

Review the system flow, boundaries, integrations, and replaceable parts before you download it.

Overview

Waiting Lists is an Astro server-rendered application deployed through a Cloudflare Worker. D1 stores lists, subscribers, consent evidence, admin sessions, API keys, settings, and email delivery events. Cloudflare Email Service sends confirmation messages, a Queue reports delivery outcomes, and a Cron Trigger removes expired or over-retained records.

Request flow

  1. An administrator creates a list and configures allowed browser origins.
  2. A public form posts exactly email and consent to /api/subscribe/[slug].
  3. Validation, origin rules, and rate limits run before D1 changes.
  4. A pending subscriber and hashed one-time confirmation token are stored.
  5. Email Service sends a confirmation link and a separate removal link.
  6. The person reviews and confirms; the token is consumed and the subscriber becomes confirmed.
  7. The dashboard and exports expose confirmed subscribers to the authenticated administrator.
  8. Queue events update delivery status. Scheduled cleanup removes expired pending requests and old confirmed records.

Main boundaries

  • src/pages/api/subscribe/[slug].ts — public collection boundary
  • src/pages/admin/ — private human interface
  • src/pages/api/v1/ — private agent/API boundary
  • cli/waitinglists.mjs — included command-line client for people, coding agents, and automation
  • src/lib/auth.ts — password, session, cookie, and CSRF rules
  • src/lib/subscriber-tokens.ts — confirmation and removal token rules
  • src/lib/db.ts — database queries and lifecycle operations
  • src/lib/email.ts and email-events.ts — outbound mail and delivery events
  • src/lib/integration.ts — machine-readable integration contract
  • src/worker.ts — HTTP entry, scheduled cleanup, and Queue consumer
  • migrations/ — source of truth for the D1 schema

Replaceable infrastructure

Cloudflare is the reference implementation. A port can replace D1 with PostgreSQL, Email Service with another transactional provider, Queues with a job runner, Turnstile with another abuse-control layer, and Workers with any server runtime. Preserve the boundaries and acceptance behavior above rather than translating files line by line.

What’s included

  • Waiting Lists version 1.0 with the complete CLI in code/cli/, its private JSON API, and a dedicated CLI guide
  • Sanitized source snapshot with production resources, subscriber data, credentials, and analytics removed
  • D1 migration history and Cloudflare Worker configuration with portable placeholders
  • Public collection endpoint, confirmation and removal flows, private dashboard, API, and CLI
  • Cloudflare Email Service, Queue delivery events, Turnstile, rate limits, and scheduled cleanup
  • Automated unit tests and production build configuration
  • A plain-language human quick start, versioned changelog, and dedicated AI-agent instructions
  • Architecture, decisions, customization, configuration, security, deployment, and build guides
  • Audited source ZIP included in the free ZIP download

Documentation

The ZIP includes project context for you and your coding agents.

README.md

The starting point: what the software does, prerequisites, local setup, commands, and the shortest path to a working copy.

CHANGELOG.md

The release history and the public changes included in each version.

BUILDING.md

The build story: how the software was made, the difficult parts, how it was verified, and what could come next.

AGENTS.md

Project context and operating rules for Codex, Claude Code, Cursor, and other AI coding agents.

ARCHITECTURE.md

How the major parts fit together, where data flows, and where to make structural changes.

DECISIONS.md

The main technical and product choices, including tradeoffs worth preserving or revisiting.

CUSTOMIZATION.md

A practical map for changing the brand, interface, features, data model, and integrations.

DEPLOYMENT.md

A production checklist covering resources, environment setup, builds, and deployment verification.

CONFIGURATION.md

Every setting and environment variable, where it is used, and how to configure local and production environments.

SECURITY.md

Credential handling, trust boundaries, sensitive data, and checks to run before publishing your version.

CLI.md

Command-line usage, options, common workflows, and automation examples.

Why download this

  • Skip the consent, token, session, export, delivery, and cleanup groundwork
  • Start with a complete working product instead of a signup-form demo
  • Give an AI agent enough context to set it up or rewrite it safely
  • Own the subscriber database and deployment decisions
  • Keep the public integration tiny while the difficult lifecycle rules stay server-side
  • Replace the framework or platform without starting from a blank repository

Customize it

Use the working source as a foundation. Keep it small, change it for your own workflow, or turn it into a different product.

  1. Grow it into the waitlist product you run for every launch—or white-label for agencies that need double opt-in done right.
  2. Rebrand pages, emails, and consent copy until it feels like part of the product you are announcing.
  3. Add teams, billing, webhooks, and newsletter sync when a single list turns into a small SaaS.
  4. Swap email and database providers behind the existing boundaries without rewriting the core flow.
  5. Port Astro to the stack your team already ships, keeping the product contract intact.
  6. Deploy on Workers today, or move to a VPS/container later when your traffic story changes.

MIT license

Every source ZIP includes an MIT LICENSE file. You can use, copy, change, publish, distribute, sublicense, or sell the code, including as part of a commercial product.

Keep the copyright and license notice with copies or substantial portions of the code. Third-party dependencies and assets keep their own licenses.

Keep learning

Solo Lab

Connect a self-hosted waiting list to the work of finding customers and launching your own products.

Explore Solo Lab →

Join the newsletter to access my complete download library, including books, courses, and software. I’ll also email you about new software, building products with AI, and my courses. You can unsubscribe anytime.

Your email is stored on a secure server in the EU. Every email has an unsubscribe link. Unsubscribing stops future emails; you can keep using the public download library.