This folder collects everything that is safe to publish in a public “Clearbook” portfolio repo. It covers the product story, architecture, lessons learned, and a few sanitized snippets so I can expose some depth of the project without exposing the proprietary codebase.
- Note: The real Clearbook codebase remains private. This repository is a curated, non-sensitive showcase so people can see the scope without accessing the proprietary repo.
- Live site: https://clearbook.app — launches a fresh demo tenant at
/demowith no login required.
- Product: Multi-tenant booking SaaS with admin workspace + embeddable public widget.
- Stack: Next.js 15 (App Router, React 19.1), TypeScript, MongoDB/Mongoose, Redis (Upstash), NextAuth, Stripe Connect, SCSS Modules, Cypress, GitHub Actions, Render.
- Status: Live demo at https://clearbook.app · repo remains private.
- Production-ready: Fully fleshed SaaS with RBAC, tenant theming, billing, availability planning, booking validation, and an embeddable widget — ready for real clients/business workspaces.
- Role: Solo founder/engineer — product design, full-stack build, infrastructure, and ops.
| Resource | Details |
|---|---|
| Marketing site | https://clearbook.app |
| Demo workspace | Visiting https://clearbook.app/demo provisions a fresh tenant and automatically signs in as owner@demo.test (no credentials needed). |
| Widget preview | After a demo launches, the marketing page updates the “View booking widget demo” link to /embed/<demo-slug>. The generic /embed/demo route exists only for local development. |
| Contact | alle7000.andersson@gmail.com |
Marketing
| Hero & CTA | Feature highlights | How it works | Pricing | Demo CTA |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
Booking widget
| Choose service/time | Confirm details |
|---|---|
![]() |
![]() |
Dashboard
| Overview | Availability planner | Bookings |
|---|---|---|
![]() |
![]() |
![]() |
| Services | Staff | Staff details |
|---|---|---|
![]() |
![]() |
![]() |
| Settings: Profile | Settings: Booking rules | Settings: Payments | Settings: Notifications |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
- Scheduling chaos: Businesses needed service- and staff-specific availability, rotating patterns, and a way to draft schedules before publishing.
- Concurrency safety: Public bookings hit the same slot at the same time → I built idempotent APIs with unique compound indexes and Redis tag invalidation.
- Payment clarity: Stripe Connect with fee explanations, automatic application fees, reverse transfers for refunds, and dedicated demo Stripe keys.
- Tenant governance: GDPR-compliant soft deletes, nightly cleanup cron (bookings/staff/demo tenants), and audit logs.
- Demo + onboarding: Sandbox launcher that seeds a tenant, drops a browser cookie, and expires automatically.
Next.js App Router
├─ Marketing routes (public)
├─ Dashboard (auth-protected)
├─ Public API (bookings, demo, embed)
└─ Internal API (Stripe, admin tooling)
MongoDB (per-tenant collections)
├─ Tenants, Services, Staff, Availability presets
├─ Bookings (soft delete + purge window)
└─ Demo tenants (expiresAt, seeded flag)
Redis (Upstash)
├─ Availability cache per tenant/service/day
└─ Tag-based invalidation on create/update/cancel
Stripe Connect
├─ OAuth onboarding with fee education modal
├─ Checkout sessions + webhooks
└─ Reverse transfers on refund/dispute
- RBAC: Owner/Admin/Staff roles with NextAuth sessions. Middleware enforces tenant scope on every action.
- Themable UI: CSS variables + SCSS modules. Tenants can brand the dashboard and widget without touching code.
- Edge rate limiting: Middleware stores per-IP counters in Redis to protect public endpoints.
- Draft/publish workflow in the availability planner so schedule tweaks stay isolated until reviewed.
- Service catalog supports per-staff overrides (duration, price, buffers) that flow through analytics and booking validation.
- Booking API enforces
Idempotency-Keyheaders, spam-honeypot fields, and concurrency-safe writes with Mongo unique indexes. - Demo sandbox automatically seeds a tenant, sets browser cookies/localStorage, and expires via nightly cleanup.
- Stripe Connect flows show an educational modal explaining fee math before the account is linked (reduces support tickets).
- Node test runner: unit + feature coverage (schemas, RBAC helpers, booking math).
- Integration suites: spin up Mongo + stripe-mock via Docker to test bookings, availability, Stripe checkout/webhooks, and tenant tooling.
- Cypress: end-to-end flows for the widget and dashboard quick actions.
- GitHub Actions: lint → typecheck → build → tests; workflow is disabled in the private repo and kept only as reference. Render cron runs the cleanup scripts (archive → bookings → staff → demo) daily at 01:00 UTC.
- Render deployment: Node 20 service with
/health check, log streaming, and alerting on failed deploys/health checks.
- Caching needs invalidation discipline. Tag every Redis entry with tenant/service/day so invalidation is deterministic.
- Stripe disputes remain costly unless transfers are structured carefully. Using
application_fee_amount+transfer_data+reverse_transferkeeps payouts predictable. - Demo data quickly becomes a liability without cleanup. Nightly cron jobs plus short-lived cookies keep the sandbox safe.
- Docs are part of the product. GDPR SOPs, fee modal copy, and onboarding explainers saved time in support conversations.
snippets/checkConflicts.ts– Pure TypeScript overlap detector extracted from the booking engine.snippets/checkConflicts.test.ts– node:test example showing how I structure fast-running unit tests.snippets/idempotencyMiddleware.ts– Framework-agnostic helper enforcing Idempotency-Key semantics.snippets/loadTenantTheme.ts– Minimal tenant theme loader that merges DB tokens with defaults.
















