Case Study

Salsa Con Flow Dance

A full-stack booking platform for a professional Latin dance instructor — built on Next.js and Vercel, then systematically hardened: rate limiting, CSP headers, Vercel Analytics, and a Node.js 20 upgrade shipped before a GitHub Actions deprecation deadline.

4
CI checks added
0
CI failures on merge
Node 20
Upgraded before June deadline
4
Security layers shipped

Context

Salsa Con Flow Dance needed a professional web presence: booking form, testimonials, contact management, and analytics — all production-grade and maintainable. The stack is Next.js (App Router), TypeScript, Tailwind, and Vercel.

After the initial feature build, the platform needed systematic hardening: the CI pipeline lacked coverage, security headers were absent, and the GitHub Actions Node.js version was facing a June 2026 deprecation. Each of these was an independent work track managed in parallel.

Key Challenges

Challenge 1 — Rate limiting on testimonial submissions

The POST /api/testimonials endpoint accepted unlimited submissions with no IP-based throttle. A simple form automation could flood the testimonials queue. The fix added a sliding-window rate limiter keyed by IP: 5 submissions per hour per client. Excess requests receive a 429 Too Many Requests with a Retry-After header.

Challenge 2 — Security hardening: CSP + strict headers

The platform shipped without a Content Security Policy. A CSP audit identified inline script/style risks and missing frame-ancestors directives. The fix added a strict CSP via Next.js headers() config: nonce-based script-src, locked object-src none, frame-ancestors none, plus X-Content-Type-Options, Referrer-Policy, and Permissions-Policy.

Challenge 3 — Node.js 20 upgrade before June 2026 deprecation

GitHub Actions deprecated Node.js 16 runners in June 2026. The CI pipeline used actions/setup-node@v3 with node-version: 18. The fix upgraded to actions/setup-node@v4 with node-version: 20 across all workflow files — shipped 5 weeks before the deadline.

Challenge 4 — Booking form integration test coverage

The booking form submission path had zero automated test coverage — a regression in the happy path would be invisible until a real user hit it. Playwright integration tests were added covering the happy path (successful submission), validation errors (empty required fields), and boundary conditions (long inputs, special characters). Tests run in CI on every PR.

Execution Approach

Each work track was independent with its own branch, its own CI validation, and its own merge window. No track blocked another — all could proceed in parallel.

Quantified Results

Zero CI failures on merge

All 4 security/hardening PRs merged with full CI pass — no rollbacks, no hotfixes.

Node 20 before deadline

Upgraded 5 weeks before GitHub Actions' Node.js 16 deprecation window. Zero CI disruption.

Rate limiting live

POST /api/testimonials now throttled at 5 req/hr/IP with RFC-compliant 429 + Retry-After headers.

Booking form fully tested

Playwright E2E tests cover happy path, validation errors, and boundary conditions. Runs on every PR.

Tech Stack

Next.jsTypeScriptTailwind CSSVercelGitHub ActionsPlaywrightVitest

Lessons

← A Lo Cubano Boulder FestAll Case Studies →