Jin Oh · Full-stack developerContact

P-02 · Multi-tenant SaaS · Web + iOS/Android

Velvet Studio

Salon CRM and booking platform with SMS marketing, loyalty tiers, in-person payments and AI assistants.

Role
Solo — product design, development, deployment
Timeline
Feb 2026 — May 2026
Platforms
Web app · iOS & Android (Capacitor + Expo) · Embeddable booking widget
Links
velvetstudio.ca ↗
React 19TypeScriptViteSupabase (Postgres, Auth, Realtime, Edge Functions)CapacitorExpo / React NativeStripeCloverTwilioGemini APIRevenueCatPlaid

TL;DR

Velvet Studio is a CRM for salons, studios and spas: online booking, a day/week calendar, checkout, SMS campaigns, loyalty tiers and AI assistants, on web and native mobile. Jin Oh designed, built and deployed it alone — 32 Supabase Edge Functions, 129 migrations and nine third-party integrations including Stripe, Clover, Twilio, Plaid and Gemini.

Key facts

  1. 01One sign-in serves three kinds of user — owner, staff and customer — resolved to the right tenant by a single database function.
  2. 02Public booking works without an account, yet anonymous users can never read the salon’s tables: all public writes go through SECURITY DEFINER RPCs.
  3. 03Automated SMS reminders run from a job queue processed by a scheduled Edge Function, cutting no-shows.
  4. 04Loyalty tiers are earned by spend or visit count and applied automatically at booking and checkout.
  5. 05Web subscriptions (Stripe) and in-app subscriptions (RevenueCat) are reconciled into one plan state: trial, active, past-due grace, comped or suspended.
  6. 06Admin UI in English, Korean, Spanish and Chinese.
  • 32Supabase Edge Functions
  • 129schema migrations
  • 9third-party integrations
  • 4admin languages

The problem

Small salons run on paper books, Instagram DMs and a card terminal that knows nothing about the client. No-shows cost them real money every week.

Velvet Studio replaces all of it: clients book online, reminders go out automatically, loyal clients are recognised at checkout, and the owner gets a daily AI briefing of the day ahead.

Who it serves — and what they needed

  • Salon ownersFewer no-shows, repeat clients, and one place to see the business.
  • Stylists & staffTheir own schedule and pricing, on their phone.
  • ClientsBook in under a minute, get reminded, get rewarded.

How it fits together

FIG.Booking, reminders and payments
bookRPCRealtimetickSMScheckoutchargebillingAIjobsUSERClientWeb · embeddable iframeAPPBooking web appReact · ViteDBSupabase PostgresRLS · SECURITY DEFINER…DEVICEOwner & staff appsCapacitor · ExpoSVCSchedulerExternal cron · secret…SVCEdge Functions32 Deno functionsEXTStripeSubscriptions · checkoutEXTCloverOAuth · devicesEXTTwilio SMSCampaigns · replies · o…AIGeminiGoogle Gemini API
  1. 01A client books; staff see it instantlyClient → Booking web app → Supabase Postgres → Owner & staff apps
  2. 02Reminders go out automaticallySupabase Postgres → Edge Functions · Scheduler → Edge Functions → Twilio SMS
  3. 03In-person checkout through CloverOwner & staff apps → Edge Functions → Clover
  4. 04Plans, billing and AIEdge Functions → Stripe · Edge Functions → Gemini

What’s inside

Calendar & booking

  • Day/week calendar; one booking can hold several services, each with its own stylist
  • Server-side conflict checks against working hours and schedule blocks
  • Public booking flow, embeddable by iframe, plus a customer portal

Checkout

  • Discounts, tax, retail add-ons and deposits
  • Clover in-person payments with device sync and refunds
  • Per-staff pricing

Marketing

  • Segmented SMS campaigns: inactive, high-spend, frequent
  • Inbound replies and opt-out handling
  • Google review link and merchant SMTP email

Loyalty

  • Membership tiers by spend or visits
  • Auto-assigned and applied in calendar and public booking

AI

  • Multilingual support chatbot over an owner and sales knowledge base (hCaptcha-protected)
  • AI daily booking briefing

Platform

  • Stripe plans with trial, comped, past-due grace and suspended states
  • RevenueCat for app-store subscriptions
  • Platform admin console, audit log, rate-limited demo workspaces

Hard parts, solved

  1. C-01

    Three kinds of user, one login

    Problem

    Owners, staff and customers share one auth system but must land in different tenants with different powers.

    Approach

    The tenant key is the owner’s auth id; a single function, rpc_resolve_session_tenant, resolves any session to its role and merchant, and RLS policies — including separate employee-level ones — hang off that.

    Result

    Every screen asks one question and gets one answer; no role logic duplicated in the UI.

  2. C-02

    Public booking without public tables

    Problem

    Anyone must be able to book, but anonymous access to bookings or clients would expose personal data.

    Approach

    Anonymous roles have no table access at all; booking goes through SECURITY DEFINER RPCs that validate staff, service, time and overlap on the server before writing.

    Result

    Open booking, closed data.

  3. C-03

    Two billing systems, one truth

    Problem

    Web users pay through Stripe; app-store users must pay through Apple / Google via RevenueCat. Both must unlock the same features.

    Approach

    Webhooks from both providers write into one plan-state model with explicit trial, grace and suspended transitions.

    Result

    Feature gating reads one field, regardless of where the customer paid.

Screens

Velvet Studio website home page
velvetstudio.ca