Web · Next.js · Redux Toolkit · Stripe
Global Patient Booking Platform
A 0→1 multi-region scheduling and concierge coordination platform that became the company's primary patient acquisition channel — generating over $1M in annual revenue.
$1M+
Revenue generated
Solo FE lead
Role
0 → 1
Timeline
Web (Next.js)
Platform
01 — Problem
Patients couldn't book without calling
Vibrant Wellness offered concierge phlebotomy services but had no patient-facing booking system. Every appointment was coordinated manually over the phone — creating friction for patients, bottlenecks for staff, and a ceiling on revenue growth.
The company needed a self-service platform where patients could complete the entire service lifecycle independently: verify eligibility, agree to compliance terms, choose time slots, pay, and receive real-time status updates — with minimal operational intervention.
02 — Flow
Six steps. Zero phone calls.
Each step has distinct validation logic, conditional rendering, and business rules. The flow was designed so patients can complete it independently — and ops never need to intervene.
Kit eligibility gate — built in response to a real logistics failure.
- Origin: patients were discarding the foam shipping box or failing to freeze ice packs, causing blood samples to be unusable and shipments to be delayed. This screen was added to force acknowledgement before any appointment could be booked.
- Conditional branching: "No kit" path surfaces a kit request link and blocks progression until a kit is confirmed in-hand
- Accessory checklist (foam cooler, ice packs) and tube details rendered dynamically from the order — patients must confirm each item is present and in good condition
- Fasting notice pulled from lab order metadata — shown only when the provider requires it for this specific test
CLIA-compliant acknowledgement that creates a documented paper trail.
- Added alongside the pre-check after ops incidents — a legal acknowledgement ensures patients can't claim they were unaware of handling requirements
- Agreement copy is versioned server-side; the frontend always renders the latest content without a deploy
- "Acknowledged and Agreed" is a hard gate: step 1 completion state is validated server-side before this step is accessible
- Scroll position is tracked — the confirm CTA stays disabled until the patient has scrolled through the full document
Time slot selection with layered availability constraints.
- Max 2 slots per day enforced client-side with selection state tracking
- Mon–Thu only — Fri, Sat, and Sun disabled per ops policy
- 48 business-hour minimum lead time: the earliest bookable date skips weekends and non-working days, so the greyed-out range adjusts dynamically based on when the patient is booking
- Holiday blocklist and day-before-holiday exclusions derived from a holidays package and enforced client-side — no API call needed per date interaction
- Right-hand summary panel shows ranked selections in real time; minimum 3 required to confirm
User info collection with timezone intelligence and service area validation.
- Pre-fills name, phone, and address from existing patient records if a prior booking exists
- On address entry or change: geocodes the input and cross-checks against our serviceable zip code list — surfaces an inline error if the area isn't covered
- Derives the timezone from the appointment address, not the patient's browser — selected times are submitted as local time at the service location, ensuring the field tech and backend always see the correct local appointment time regardless of where the patient is booking from
- Conditional payment section: Stripe or PayPal block renders only when the order requires payment
- SMS OTP via Twilio authenticates the phone number before final submission
Submission receipt with timezone-normalized slot display.
- Confirmed time slots shown with the patient's local timezone label (e.g. Pacific Daylight Time)
- Triggers a confirmation email with appointment details, preparation instructions, and support contacts
- Clears booking state from Redux on success to prevent stale data on re-entry
Post-booking dashboard for patients to view and manage their requests.
- The booking link is state-aware: returning patients who already have an active appointment are redirected here automatically instead of re-entering the booking flow — one link serves both new and existing patients
- Displays accession ID, appointment type, status (Pending / Confirmed / Completed), and all requested time slots
- Cancel and Reschedule actions gated by appointment status — disabled once a slot is confirmed by ops
- Address and contact info surfaced for quick reference; email sent on any status change
03 — Key Decisions
Engineering choices that shaped the product
Multi-step wizard over a single long form
Why: Each step has distinct validation and conditional branching — the pre-check result changes which fields appear downstream. A wizard keeps errors local to one step and makes the compliance gate hard to skip.
Tradeoff: Adds navigation complexity and back-button state management — handled with a persistent Redux slice that survives re-renders.
Address-driven timezone resolution
Why: Patients often book from a different timezone than where the appointment takes place. By deriving timezone from the service address rather than the browser, selected times are submitted as local time at the appointment location — the field tech always sees the correct local time regardless of where the patient booked from.
Tradeoff: Requires a geocoding call on address entry, adding a small latency to that step. The UI deliberately keeps displayed times unchanged to avoid confusing patients mid-flow.
Calendar constraints enforced client-side
Why: 48 business-hour lead time, Mon–Thu only, no holidays, max 2 slots per day — these rules change infrequently but affect every date interaction. Enforcing them in UI state gives instant feedback without a round-trip per click.
Tradeoff: Business rule changes require a frontend deploy; mitigated by sourcing the holiday list from a package so only the scheduling logic itself is hardcoded.
RTK Query instead of Redux + Axios
Why: The legacy codebase had duplicated fetch logic and stale-cache bugs across multiple components. RTK Query gave normalized caching, automatic re-fetching, and eliminated ~40% of API boilerplate.
Tradeoff: Required a migration pass and team ramp-up on the new mental model, but paid off immediately in fewer race conditions.
04 — Testing & CI/CD
Automated coverage across the full booking flow
Given the compliance requirements and payment integrations, automated test coverage was essential — a broken booking flow directly impacts revenue. Tests were added incrementally as each step was built.
Jest — unit & integration
Calendar constraint logic, timezone resolution, and Redux state transitions are all unit-tested. These rules have zero tolerance for regression — a wrong date or timezone silently breaks the booking.
Playwright — E2E
5+ end-to-end scenarios cover the critical paths: full booking flow, payment submission, SMS OTP, and appointment management. Run against a staging environment on every PR.
GitHub Actions CI
Tests gate every pull request. A failing test blocks the merge — preventing broken booking flows from reaching production where they would directly impact patient acquisition.
Lighthouse CI
Performance budgets enforced on every deploy. The booking flow is patient-facing and revenue-critical — load time regressions are caught before they ship.
05 — Outcome
$1M+ in annual revenue
$1M+
Annual revenue generated
Primary
Patient acquisition channel
0 calls
Required from ops to complete a booking
The platform launched as the company's first digital acquisition channel and quickly became its primary revenue driver — enabling patients to independently complete the full service lifecycle without any manual coordination from the operations team.