Studio Management Case Study

Sandor Tattoos

A production-grade booking and studio management system — online deposits, Tap to Pay terminals, automated accounting software integration, and a full admin dashboard. More engineering than most people expect from a tattoo studio website.

Overview

Not just a website. A full studio operating system.

On the surface, Sandor Tattoos looks like a clean studio website. Under the hood it's a complete booking management platform — handling online reservations with deposits, walk-in sessions with flexible timing, contactless tap-to-pay collection, and automatic invoice generation in the accounting software.

The admin dashboard gives the artist full control over every booking from first inquiry to final payment, with built-in accounting sync and enterprise-grade security including TOTP two-factor authentication.

3

Booking types

32+

API endpoints

2

Stripe integrations

6

Security layers

Sandor Tattoos Website

Booking Workflows

Three ways to book. One system.

Each booking type handles a different real-world scenario — with automatic conflict prevention at the database layer.

💳

Online Booking + Deposit

  1. 1Customer selects date & time slot
  2. 2Uploads reference images (Cloudinary)
  3. 3Pays £50 deposit via Stripe Checkout
  4. 4Webhook confirms → booking auto-confirmed
  5. 5Email confirmation sent to customer & admin
🚶

Walk-In (Flexible Timing)

  1. 1Admin opens walk-in form on dashboard
  2. 2Sets exact time in 5-minute increments
  3. 3Enters custom price for the session
  4. 4Selects Cash or Contactless payment
  5. 5Booking instantly confirmed — no deposit needed
📱

Admin Booking + Tap to Pay

  1. 1Admin creates manual booking for customer
  2. 2System redirects to Tap to Pay page
  3. 3Customer taps card / Apple Pay / Google Pay
  4. 4Card terminal captures payment in real time
  5. 5Booking auto-confirmed on payment success

Admin Dashboard

Full control from one screen

📅

Booking Management

Filter by status (Pending / Confirmed / Cancelled). Expand any booking to view customer details, reference images, deposit status, and final payment info. Edit, confirm, cancel, or upgrade bookings to full-day sessions.

💰

Final Payment Recording

After each session, the artist enters the final price. The system calculates the balance owed (total minus deposit), records the payment method (Cash or Contactless), and timestamps the completion.

📊

Finance Dashboard

Two-tab finance view: Accounting software integration with synced invoices and P&L data, plus a local Cash Tracking tab for cash income and expenses.

🗓️

Blocked Dates

Block entire days or specific 3-hour slots for holidays, conventions, or personal time. Blocked dates are hidden from the customer booking calendar in real time.

🔗

Accounting Sync

Sync individual bookings or bulk-sync all confirmed card payment sessions to the accounting software with one click. Each invoice is automatically categorised by type.

🔐

Security & 2FA

JWT-protected admin with optional TOTP two-factor authentication (Google Authenticator). Token revocation table prevents reuse of logged-out JWTs. 6-layer CSV import security for bulk data.

Payments

Two payment modes, not one

Most booking systems offer one payment mode and call it done. This project uses two distinct integrations to cover every scenario the studio encounters.

🖥️

Online Checkout — Deposits

Customers pay a £50 deposit online when booking. Stripe sends a webhook on payment success which auto-confirms the booking and triggers the confirmation email.

📱

Tap to Pay Terminal

For in-studio payments, the admin redirects to a Tap to Pay page pre-filled with the booking and amount. The customer taps their card, Apple Pay, or Google Pay directly on the artist's phone. No card reader hardware required.

Accounting

Accounting software integration

Card payment bookings sync to the accounting software as invoices via OAuth 2.0. Cash payments are tracked separately in the studio's local finance dashboard.

Regular deposit

✓ Syncs to accounting

Deposit invoice created in the accounting software on payment confirmation.

Walk-in (card payment)

✓ Syncs to accounting

Full session invoice created in the accounting software with appropriate tax treatment.

Cash payment

— Tracked separately

Recorded in the studio's local finance dashboard. Tracked in the local finance dashboard.

Tech Stack

Production-grade from day one

Frontend

  • Next.js 14
  • TypeScript
  • Tailwind CSS
  • React 18
  • react-icons

Backend

  • Next.js API Routes
  • Raw SQL (mysql2)
  • JWT auth (jsonwebtoken)
  • bcryptjs
  • TOTP 2FA (otplib)

Database

  • MySQL 8.0
  • Pessimistic locking
  • Unique slot constraints
  • Atomic transactions

Payments

  • Stripe Checkout (deposits)
  • Stripe Terminal (Tap to Pay)
  • Stripe Webhooks
  • Live keys in production

Integrations

  • Accounting software OAuth 2.0
  • Cloudinary CDN (images)
  • Nodemailer SMTP (email)
  • Redis (rate limiting)
  • Sentry (error tracking)

Engineering Highlights

The details that matter

Pessimistic locking prevents double-booking

The database has a UNIQUE constraint on (booking_date, slot_start). On top of that, slot availability is checked inside a SELECT ... FOR UPDATE transaction — so two simultaneous bookings for the same slot can never both succeed, even under race conditions.

Full-day bookings as two atomic rows

A 6-hour session is stored as two linked 3-hour slot records, created in a single transaction. If either insert fails, both roll back. The client identifies them with a FULL: prefix; the DB links them by matching customer details.

Walk-in slots bypass the 3-hour constraint

Walk-ins use flexible 5-minute timing (e.g., 14:35) which would conflict with the standard slot unique key. Walk-in bookings have the booking_type column in the unique constraint, so they can coexist with regular bookings on the same day without conflict.

JWT revocation without a session store

Serverless functions are stateless, but logging out still needs to invalidate the token. Each JWT carries a unique identifier. On logout, that identifier is stored server-side and every protected route validates against it before allowing access.

OAuth token refresh in a stateless environment

The accounting software's OAuth tokens expire frequently. Since Vercel functions have no persistent memory, tokens are securely persisted server-side. Each API call loads, uses, and if needed refreshes the token — then saves the updated credentials back.

Content Security Policy with SHA-256 script hashes

A strict CSP blocks all inline scripts except those with precomputed SHA-256 hashes. This prevents XSS even if an attacker injects content into the page. Google Analytics and Stripe are whitelisted by domain; all other sources are blocked.

Need a booking system that actually works?

I build custom booking platforms with real payment processing, accounting integration, and admin tools — not off-the-shelf plugins. Let's talk.