Hammers Lab

Case study

PlayPadel

Operations platform for a padel club

Client
Padel club (Italy)
Duration
Ongoing since 2024
Role
Sole engineer: architecture through operations

The problem

The club ran bookings through Playtomic, communications through WhatsApp, and match organisation through spreadsheets and memory. Staff spent hours reconciling court availability, chasing no-shows, and manually notifying players about schedule changes.

Constraints

  • Playtomic's API is the source of truth for court bookings: the system must sync, not replace.
  • Players expect WhatsApp messages, not emails, and delivery must be reliable and traceable.
  • Single VPS budget: no Kubernetes, no managed queue service, no room for operational complexity.
  • Real player data in production: GDPR compliance and PII scrubbing are non-negotiable.

What we built

A full-stack operations platform: admin panel for staff, automated Playtomic sync, WhatsApp notification pipeline, match management, and reporting, deployed as Docker containers on a single VPS with automated rollback.

Architecture

Hexagonal (ports and adapters) architecture keeps domain logic isolated from infrastructure concerns.

  • Domain layer: booking rules, match lifecycle, notification policies. Pure TypeScript, zero framework imports.
  • Application layer: use cases orchestrate domain services through defined ports.
  • Infrastructure adapters: Playtomic REST client, Twilio WhatsApp sender, Prisma repositories, Sentry error reporting.
  • Presentation layer: Next.js admin UI with server components and typed API routes.
Domain Playtomic Twilio Admin UI Postgres
Hexagonal architecture diagram for PlayPadel

Playtomic integration

Scheduled sync jobs pull court availability and reservations from Playtomic's API. Conflicts are detected at the domain level and surfaced to staff before they become double-bookings. The adapter handles rate limits, pagination, and API version drift behind a stable port interface.

WhatsApp / Twilio outbox

Outbound messages go through a transactional outbox: the domain event is persisted first, then a background worker delivers via Twilio's WhatsApp API. Failed sends retry with exponential backoff; permanent failures are logged and surfaced in the admin panel. No message is lost because the HTTP call failed.

Data layer

PostgreSQL with Prisma ORM. Migrations are version-controlled and applied in CI before deploy. Schema changes follow expand-contract pattern to avoid downtime on the single-instance database.

Infrastructure & rollback

Docker Compose on a single VPS. GitHub Actions builds and pushes images to GHCR; deploy script pulls, runs health checks, and automatically rolls back to the previous image if the new container fails to start. Observed rollback time: under 60 seconds.

Observability

Sentry for error tracking with PII scrubbing configured at the SDK level: names, phone numbers, and message bodies are stripped before events leave the server. Structured logging for integration failures; no personal data in log lines.

Results

  • Staff time on manual booking reconciliation reduced from hours daily to minutes weekly.
  • WhatsApp delivery rate above 99% with full audit trail via the outbox table.
  • Zero unplanned downtime from bad deploys since rollback automation shipped.
  • Platform handles peak booking volume (weekend mornings) without manual intervention.

Stack

TypeScript · Node.js · Next.js · PostgreSQL · Prisma · Docker · GitHub Actions · Twilio · Sentry · Cloudflare

Want a walkthrough of the admin panel? Get in touch and we'll show you the interesting parts.

Request a walkthrough

Your project could be next.

We're selective because we're small. If the problem is interesting and the fit is right, we'd rather go deep than wide.

Tell us about it