Live club site · Documentation · Quickstart · Screenshots · Releases
AlpineClubBookingsNZ is an open-source booking, membership, payment, and lodge-operations platform for small clubs — built for and running Tokoroa Alpine Club in production today. It is also published as a real-world reference implementation of a production Next.js application with payments, accounting, email, scheduled jobs, and Docker-based blue/green deployment.
Members book real beds against real capacity; admins run the whole club — bookings, membership lifecycle, fees, Stripe and bank-transfer payments, Xero accounting, lodge chores, even the TV in the lodge lobby — from one app.
| 🛏️ Booking engine — bed-capacity availability, NZ date-only lodge nights, waitlist and offers, holds, changes, cancellation rules, refunds, credits, promo and group discounts, exclusive whole-lodge holds → guide | 👪 Membership lifecycle — registration, families and partners, nominations, seasonal membership types and age tiers, annual subscription billing, cancellation with GST-aware refunds → guide |
| 💳 Payments, two ways — Stripe card payments (PaymentIntents + webhooks) and Xero-backed Internet Banking invoices with settlement tracking → guide | 📒 Xero accounting built in — OAuth, webhooks, retry queues, invoice/credit-note lifecycle, and a native finance dashboard on Postgres snapshots → finance docs |
| 🏔️ Lodge operations — rooms and beds, drag-and-drop bed allocation, chores and rosters, work parties, hut leaders, lockers, inductions, PIN lodge kiosk → guide | 📺 Lobby TV displays — paired read-only screens showing arrivals, rooms, chores, and notices, driven by live booking data with privacy-reduced names → display docs |
| 🏘️ Multi-lodge core — lodge-scoped rooms, seasons, lockers, and chores with a cross-lodge waitlist → multi-lodge docs | 🔐 Granular admin roles — seeded permission bundles (Booking Officer, Treasurer, …), custom roles, full audit log → guide |
| 🌐 Admin-editable public website — sanitised rich-text pages, menus, banners, club theming with no redeploy → guide | ✉️ Branded email — AWS SES with suppression feedback, editable lifecycle templates that inherit the club theme → guide |
| 📅 Events calendar — month view of club meetings and events, recurring events (incl. "3rd Tuesday of the month"), read-only for members, editable by committee and lodge admins → guide | 🎥 Video meetings — attach a self-hosted MiroTalk meeting to a calendar event for committee calls → guide |
| 📰 Member notices — committee-authored news targeted to member audiences (everyone, membership types, lodges, committee roles, or individuals), shown on the dashboard with per-member read and acknowledgement tracking and optional email-on-publish → guide | 📣 Bulk communications — one-off admin email to opted-in members with send history and preference/suppression filtering → guide |
| 💬 In-app help everywhere — a chat-style help widget on every surface answers page-specific questions from a curated corpus and shows a full page guide; with the optional AI help assistant module on (a club-supplied Anthropic key + a hard monthly spend cap), authenticated members can also ask free-text questions grounded strictly in that corpus → configuration | 🐛 One-click issue reporting — members and staff capture the current view and report a problem from any page straight into the admin triage queue |
Every feature above ships with an operator guide — 66 of them, nearly all illustrated with captured screenshots — plus member-facing user guides, all indexed in the documentation hub.
Admin dashboard |
Member booking wizard |
Drag-and-drop bed allocation |
Lobby TV board (design concept) |
Reports |
Public club website |
There are over 80 captured screens across the admin, member, and public surfaces.
Apart from the lobby-display design concept above, screenshots are generated
by a deterministic capture harness against seeded demo data
(npm run docs:screenshots, see docs/images/README.md)
and embedded throughout the operator guides.
flowchart LR
subgraph users [At the club]
M["Members & guests"]
A["Admins & committee"]
K["Lodge kiosk (PIN)"]
TV["Lobby TV displays"]
end
subgraph app [Next.js 16 App Router]
W["Web app · API routes · cron jobs"]
end
M & A & K & TV --> W
W --> DB[("PostgreSQL 16<br/>Prisma 7")]
W <--> S["Stripe<br/>payments"]
W <--> X["Xero<br/>accounting"]
W --> E["AWS SES<br/>email"]
W --> O["Sentry · pino<br/>observability"]
W -. "blue/green deploys" .-> D["Docker Compose + Caddy"]
TypeScript end to end: Next.js 16 App Router and React 19, PostgreSQL 16 with
Prisma 7, Auth.js credentials sessions (optional TOTP/email two-factor,
magic-link, and Google sign-in), Tailwind CSS and Radix UI, Vitest and
Playwright. The full system design — data model, booking capacity rules,
integration boundaries, cron, and deployment shape — is in
docs/ARCHITECTURE.md.
git clone https://github.com/thatskiff33/AlpineClubBookingsNZ.git
cd AlpineClubBookingsNZ
cp .env.example .env # then edit — see CONFIGURATION.md
cp config/club.example.json config/club.json
npm ci && npx prisma generate
npm run setup:check # guided: npm run setup:wizardBoot a full production-style stack (app + PostgreSQL) with Docker only:
cp .env.staging.example .env.staging
docker compose --env-file .env.staging -p tacbookings-staging \
-f docker-compose.yml -f docker-compose.staging.yml up -d --build postgres app
docker compose --env-file .env.staging -p tacbookings-staging \
-f docker-compose.yml -f docker-compose.staging.yml run --rm migrate
docker compose --env-file .env.staging -p tacbookings-staging \
-f docker-compose.yml -f docker-compose.staging.yml exec app npx tsx prisma/seed.tsThen open http://localhost:3001 and sign in with your SEED_ADMIN_*
credentials.
Adopting this for your club is a documented, tested path:
- Set your club name, beds, age tiers, and integer-cent rates in
config/club.json. - Seed the first admin, then finish the in-app checklist at
/admin/setup. - Brand it — colours, fonts, and logo at
/admin/site-style, no redeploy needed — and replace the included club branding and copy with your own (NOTICE.md). - Toggle optional modules (kiosk, Xero, waitlist, lobby displays, Internet
Banking, …) under Admin → Modules. Connecting Xero is fully in-app — a
guided wizard at Admin → Xero → Setup walks you through creating the Xero
app, entering its credentials (encrypted at rest), and the OAuth connect, with
no
.envedits or key generation.
The step-by-step adopter path from clone to first deployment is
docs/IMPLEMENTATION_GUIDE.md; every
environment variable and the config/club.json schema are in
CONFIGURATION.md; the reference Lightsail + Docker +
Caddy blue/green production setup is in DEPLOYMENT.md.
- Money is property-tested. Pricing, promo discounts, refund tiers, change
fees, credits, and Xero settlement math are enforced as universally-quantified
properties (integer cents; refund + retained = paid) with fast-check — see
docs/DOMAIN_INVARIANTS.md. - Critical journeys run in real browsers. Playwright E2E suites cover
booking, payments, waitlist, two-factor login, bed allocation, and more
against a seeded staging stack (
docs/E2E_PLAYWRIGHT.md). - Migrations are gated for zero-downtime. Every schema change is classified
under the blue/green ledger before it can merge
(
docs/BLUE_GREEN_MIGRATION_POLICY.md). - Accessibility is a baseline, not a feature. Semantic status tokens,
icon-or-text redundancy, keyboard focus outlines, and a reduced-motion guard,
verified by a staging Lighthouse workflow
(
docs/STAGING_ACCESSIBILITY.md). - CI blocks the merge. Lint, typecheck, unit + property tests, build,
migration-drift, static-analysis, and E2E checks are all required on
main(docs/MAINTENANCE.md). - Backups are drilled, not assumed. S3-backed PostgreSQL backups are
configured in-app at Admin → Integrations → Database Backups (no
.envedits), run on demand or nightly, and ship with a scripted quarterly restore drill (DEPLOYMENT.md,docs/MAINTENANCE.md).
Versioned, classified releases with written upgrade paths:
GitHub Releases ·
CHANGELOG.md ·
release notes index ·
docs/UPGRADING.md ·
docs/PRODUCTION_UPGRADE_RUNBOOK.md.
Deploys ship from GHCR images (alpineclubbookingsnz-app,
alpineclubbookingsnz-migrate) via a single blue/green deploy script.
Start at the documentation hub for recommended reading paths by audience. Key entry points:
| Audience | Where to go |
|---|---|
| Club members | User guides — booking a stay, paying, waitlist, family, your account — also on the project wiki |
| Adopting clubs | docs/IMPLEMENTATION_GUIDE.md · CONFIGURATION.md · DEPLOYMENT.md · docs/UPGRADING.md |
| Operators / committee | 65 illustrated operator guides · feature hubs: finance dashboard, multi-lodge, lobby display, Xero, config transfer · docs/CANCELLATIONS.md · docs/AUTHORITATIVE_FEES.md |
| Developers | docs/ARCHITECTURE.md · docs/DOMAIN_INVARIANTS.md · docs/STATE_MACHINES.md · docs/UX_FLOW_MAP.md · docs/E2E_PLAYWRIGHT.md · docs/MAINTENANCE.md · CONTRIBUTING.md |
| Maintainers | docs/ONGOING_DEVELOPMENT_WORKFLOW.md · docs/BLUE_GREEN_MIGRATION_POLICY.md · docs/PRODUCTION_UPGRADE_RUNBOOK.md · docs/SECURITY.md |
- Questions and help:
SUPPORT.md· conduct:CODE_OF_CONDUCT.md - Contributions welcome — read
CONTRIBUTING.mdfirst - Report suspected vulnerabilities privately via
SECURITY.md; never post secrets, personal data, or accounting records in public issues - MIT licensed (
LICENSE). Club branding, logos, copy, and domains are included for context only — replace them before using a fork for another organisation (NOTICE.md)
Built with ❤️ for Tokoroa Alpine Club, and for every small club still running its lodge on spreadsheets.







