Skip to content

Latest commit

 

History

119 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ReviewPing

CI License: MIT Website Next.js React TypeScript Prisma Supabase Stripe Tailwind CSS Vitest

Automatic review requests for sole traders and local trades.

Send SMS and email review invitations after every job — without remembering to follow up. Built for plumbers, electricians, cleaners, roofers, and other small service businesses.

Live: reviewping.co.uk


Table of contents


What is ReviewPing?

ReviewPing is a single-purpose SaaS for getting more online reviews. It is not a CRM — every feature exists to support one outcome:

Help sole traders automatically get more Google (and other platform) reviews after each job.

Core loop

  1. Add a customer (name + phone or email)
  2. Log a job and mark it complete (or send manually)
  3. System sends an SMS or email with a tracked review link
  4. Customer clicks through and leaves a review
  5. You see sent / clicked status in the dashboard

Business model

  • 14-day free trial with 40 credits
  • Credit costs: SMS = 4 credits, email = 1 credit
  • Plans: Starter £9/mo · Growth £19/mo · Pro £39/mo (see lib/billing/config.ts)

Features

Authentication

  • Email + password signup with email verification
  • OTP magic-link sign-in (8-digit code)
  • Password reset flow
  • Session middleware on all routes

See docs/SUPABASE_AUTH.md for Supabase dashboard configuration.

Customers & jobs

  • Create, edit, delete, search, and filter customers
  • CSV import and mobile contacts import
  • Quick-paste customer add (settings-gated)
  • Job logging with completion triggers for automation

Review requests

  • Manual send from customer or job dialogs
  • Automated send on job completion (configurable delay and send window)
  • Lifecycle: pendingscheduledsent / failed / cancelled
  • Cancel with lead-time rules, resend failed requests
  • Filterable requests table

Templates

  • Editable SMS and email message templates
  • Custom template variables
  • Default template selection per channel
  • Pro plan: email builder

Tracking

  • Short tracked links at /r/[code]
  • Click tracking and redirect to review site
  • Optional testimonial collection mode

Billing

  • Stripe subscriptions (monthly and yearly)
  • Credit packs, rollover, low-credit warnings
  • Plan-gated features (analytics on Growth+, team on Pro)
  • Webhook-driven subscription sync

Team (Pro)

  • Invite up to 5 team members
  • Shared business context under owner profile
  • Accept invites at /invite/[token]

Dashboard & onboarding

  • Getting-started checklist (7 steps to first click)
  • Analytics charts (Growth+ plan)
  • Onboarding gates: profile, password, billing setup

Operations

  • Vercel Cron jobs for background processing
  • Webhooks: Stripe, Resend (Svix), Twilio
  • Health check endpoint for uptime monitoring
  • Rate limiting via Upstash Redis (in-memory fallback for local dev)

Technical highlights

This section is for engineers and recruiters evaluating the codebase.

Modern full-stack monolith

A single Next.js 16 App Router application — no separate backend service, no microservices. Mutations use Server Actions; reads use server components and cached queries.

Hybrid auth and data layer

Credit-metered messaging

Atomic credit spend and refund logic in lib/billing/credits/spend.ts. Dispatch orchestration (billing check → template render → Resend/Twilio send) in lib/messaging/dispatch-review-request.ts.

Cron-as-queue

No Redis job queue. Scheduled review processing uses Vercel Cron hitting bearer-authenticated API routes (lib/cron/handle-cron-request.ts):

  • Promote pending requests (5-minute cancellation window)
  • Generate automated requests from job rules
  • Process due scheduled sends

Third-party integrations

Service Purpose
Stripe Subscriptions, credit packs, webhooks
Resend Transactional email (invites, review requests)
Twilio SMS sending and delivery status callbacks
Cloudflare R2 Logo and support attachment uploads
Upstash Redis Distributed rate limiting
Google Web Risk Review link safety checks

Security

  • Google Web Risk API on review link changes (lib/security/web-risk.ts)
  • Outbound URL validation before dispatch
  • Cron secret with timing-safe comparison (lib/cron/verify-cron-secret.ts)
  • Per-IP rate limits on cron and public redirect routes
  • Webhook signature verification (Stripe, Svix/Resend, Twilio)

Test discipline

625 unit tests across 118 co-located Vitest test files under lib/**/*.test.ts, covering billing, requests, cron auth, webhooks, validation, and mappers. Run with npm test.

SEO and discoverability

Sitemap, robots.txt, JSON-LD structured data, and machine-readable /llms.txt for crawlers.


Architecture

System context

flowchart TB
  subgraph client [Client]
    Browser[Browser]
    Customer[Customer SMS/Email]
  end

  subgraph vercel [Next.js on Vercel]
    App[App Router + Server Actions]
    Cron[Cron API Routes]
    Webhooks[Webhook Handlers]
    PublicLink["/r/code redirect"]
  end

  subgraph data [Data and Auth]
    SupabaseAuth[Supabase Auth]
    Postgres[(Postgres via Prisma)]
  end

  subgraph external [External Services]
    Stripe[Stripe]
    Resend[Resend]
    Twilio[Twilio]
    R2[Cloudflare R2]
    Upstash[Upstash Redis]
    WebRisk[Google Web Risk]
  end

  Browser --> App
  App --> SupabaseAuth
  App --> Postgres
  Cron --> Postgres
  App --> Stripe
  App --> Resend
  App --> Twilio
  App --> R2
  App --> Upstash
  App --> WebRisk
  Webhooks --> Postgres
  Customer --> PublicLink
  PublicLink --> Postgres
Loading

Core review request flow

sequenceDiagram
  participant User as Tradesperson
  participant App as ReviewPing
  participant Cron as CronJobs
  participant Channel as Resend_or_Twilio
  participant Customer as Customer

  User->>App: Add customer and job
  User->>App: Mark job complete or manual send
  App->>App: Create ReviewRequest pending or scheduled
  Cron->>App: promote-pending-requests
  Cron->>App: generate-automated-requests
  Cron->>App: process-due-scheduled-requests
  App->>Channel: Dispatch SMS or email with /r/code link
  Channel->>Customer: Review invitation
  Customer->>App: Click tracked link
  App->>App: Record click redirect to review site
Loading

Data model (simplified)

erDiagram
  Profile ||--o{ Customer : owns
  Profile ||--o{ Job : owns
  Profile ||--o{ ReviewRequest : owns
  Customer ||--o{ Job : has
  Customer ||--o{ ReviewRequest : receives
  Job ||--o{ ReviewRequest : triggers
  Profile ||--o{ CreditBucket : has
  CreditBucket ||--o{ CreditTransaction : logs
  Profile ||--o{ TeamMember : manages
  ReviewRequest ||--o| Testimonial : optional
Loading

Tech stack

Layer Technology Key paths
Framework Next.js 16 (App Router) app/
UI React 19, Tailwind 4, shadcn/ui components/
API Route handlers + Server Actions app/api/, app/actions/
Database Prisma 6 on Postgres prisma/, lib/db/
Auth Supabase (@supabase/ssr) lib/supabase/
Email Resend lib/email/
SMS Twilio lib/sms/
Payments Stripe lib/billing/
Storage Cloudflare R2 (S3-compatible) lib/storage/
Tests Vitest vitest.config.ts
Deploy Vercel

Prerequisites

  • Node.js 20+
  • npm
  • Supabase project (Auth + Postgres)
  • Stripe account (test mode for local billing)
  • Resend account (for email sending)
  • Twilio account (optional — required for SMS)
  • Cloudflare R2 bucket (optional — for business logo uploads)

Local setup

1. Clone and install

git clone https://github.com/your-org/review-ping.git
cd review-ping
npm install

2. Environment variables

Copy .env.example to .env.local:

cp .env.example .env.local

Fill in values from your service dashboards. Minimum tiers:

Tier Variables What works
Boot + auth DATABASE_URL, DIRECT_URL, NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, NEXT_PUBLIC_SITE_URL Sign up, login, dashboard shell
Send messages + RESEND_API_KEY, TWILIO_* Email and SMS review requests
Billing + STRIPE_*, STRIPE_PRICE_* Subscriptions and credit packs
Cron (local) + CRON_SECRET Background job endpoints
Prod hardening + UPSTASH_REDIS_REST_* Distributed rate limits

Generate a cron secret:

openssl rand -hex 32

See .env.example for the full variable list with comments.

3. Database

Get connection strings from Supabase: Project → Connect → ORMs → Prisma.

  • DATABASE_URL — pooled connection (port 6543, ?pgbouncer=true)
  • DIRECT_URL — direct connection (port 5432) for migrations only

Apply migrations:

npm run db:migrate

After the first migrate, run supabase/sql/profiles_rls.sql in the Supabase SQL Editor (RLS policies — not managed by Prisma).

4. Supabase Auth

Configure the Supabase dashboard per docs/SUPABASE_AUTH.md:

  • Set Site URL and Redirect URLs (/auth/callback, /login/reset-password)
  • Enable Email provider with OTP (8-digit code)
  • Turn Confirm email ON for signup flow

5. Start dev server

npm run dev

Open http://localhost:3000.


Scripts

Command Purpose
npm run dev Start development server
npm run build Prisma generate + production build
npm run start Start production server
npm test Run Vitest unit tests (625 tests, 118 files)
npm run test:watch Vitest in watch mode
npm run lint ESLint
npm run db:migrate Unlock stale locks + apply pending migrations
npm run db:migrate:deploy Production/CI migration apply
npm run db:migrate:status Check migration state
npm run db:generate Regenerate Prisma client
npm run db:studio Open Prisma Studio

Cron jobs

Background processing runs via authenticated HTTP endpoints at /api/cron/*. In production, Vercel Cron triggers these on a schedule (see vercel.json_bk for reference — copy to vercel.json to enable).

Authentication

All cron requests require:

Authorization: Bearer <CRON_SECRET>

Invalid or missing auth returns 401. Rate limiting (default 10 req/min per IP per route) returns 429.

Endpoints

Route Schedule Purpose
/api/cron/promote-pending-requests Every 5 min Move manual pending requests to scheduled after ~5 min hold
/api/cron/generate-automated-requests Hourly Create scheduled requests from job automation rules
/api/cron/process-due-scheduled-requests Every 5 min Send due requests via Resend (email) or Twilio (SMS)
/api/cron/health External monitor Database liveness check

Local testing

Ensure the app is running and CRON_SECRET is set, then:

# Recommended order for a full cycle
curl -s -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/generate-automated-requests
curl -s -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/promote-pending-requests
curl -s -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/process-due-scheduled-requests

# Health check (safe to call anytime)
curl -s -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/health

Webhooks

Route Provider Purpose
/api/webhooks/stripe Stripe Subscription sync, invoice paid, credit pack grants
/api/webhooks/resend Resend (Svix) Email delivery events (bounce, complaint)
/api/webhooks/twilio Twilio SMS delivery status callbacks

Project structure

app/
  (landing)/          # Marketing site (home, guides)
  (auth)/             # Login, signup, password reset
  (dashboard)/        # Authenticated app (customers, jobs, requests, etc.)
  api/                # Cron routes, webhooks
  actions/            # Server Actions (mutations)
  r/[code]/           # Public tracked review link
  invite/[token]/     # Team invite acceptance

components/           # UI (dashboard, landing, auth, billing, etc.)
lib/                  # Business logic
  billing/            # Stripe, credits, plan access
  cron/               # Cron auth, rate limiting
  email/              # Resend integration
  sms/                # Twilio integration
  messaging/          # Dispatch orchestration
  requests/           # Review request lifecycle
  jobs/               # Job automation
  tracking/           # Click tracking, rate limits
  supabase/           # Auth clients
  security/           # URL validation, Web Risk

prisma/               # Schema and migrations
docs/                 # Setup guides (Prisma, Auth, Profiles)
supabase/sql/         # RLS policies (manual post-migrate step)

Documentation

Guide Contents
docs/PRISMA.md Database setup, migrations, cron env vars, troubleshooting
docs/SUPABASE_AUTH.md Auth dashboard config, OTP setup, flows
docs/PROFILES.md Profile and business data model

Deployment

Vercel (recommended)

  1. Connect the repository to Vercel
  2. Set all environment variables from .env.example
  3. Run npm run db:migrate:deploy on deploy (or via a CI step)
  4. Copy vercel.json_bk to vercel.json to enable cron schedules
  5. Register webhook endpoints in each provider dashboard:
    • Stripe → https://yourdomain.com/api/webhooks/stripe
    • Resend → https://yourdomain.com/api/webhooks/resend
    • Twilio → status callback set automatically at send time

Cron schedules (production)

Route Cron expression
promote-pending-requests */5 * * * *
generate-automated-requests 0 * * * *
process-due-scheduled-requests */5 * * * *

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-change)
  3. Make your changes and add tests where appropriate
  4. Run npm test and npm run lint
  5. Open a pull request with a clear description

License

MIT — Copyright (c) 2026 Jay

ReviewPing is not affiliated with or endorsed by Google, Stripe, Twilio, or any review platform.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages