Pickleball at Sea

Pickleball at Sea is a small business that organizes doubles and singles pickleball tournaments on cruise ships and at resort properties, and the site I wrote for it handles player registration, bracket generation, scoring, photo galleries, and the event calendar. The organization runs two tournaments a year with roughly twenty-four teams in each, and the site replaces a workflow that used to rely on a stack of spreadsheets and a handful of shared email accounts.

Pickleball at Sea tournament management homepage
10DB Tables
12Route Files
24Teams per Event
2/yrEvents
Node.js 20 Express 5 SQLite (WAL) EJS Docker Traefik Nodemailer Google OAuth bcrypt CSRF

The business

Pickleball at Sea organizes both doubles and singles tournaments, and its two currently scheduled events are an Eastern Caribbean cruise aboard the Norwegian Luna in October of 2026 and a week at Sandals Royal Curaçao in May of 2027, for which twenty rooms have been secured. Each event hosts twenty-four doubles teams, twenty-four singles players, and roughly a dozen alternates and spectators who travel with them.

The site itself handles event information, player registration, photo galleries, and a hall of fame. Actual travel bookings are handled through TravelTamers as a Nexion Travel Group affiliate, which keeps the tournament software focused on the tournament and leaves the commerce where the commerce already worked.

Architecture

The application is a straightforward Express 5 server with EJS templates rendered on the server, and it uses SQLite in WAL mode with foreign-key enforcement turned on. I chose SQLite over Postgres here because the dataset is small, the write load is negligible, and a single file backed up nightly by the same Docker volume as the rest of the container is simpler to reason about than a network service would be. The session store is SQLite-backed for the same reason.

Project Structure

server.js              Express app entry point
entrypoint.sh          Docker: auto-seeds DB + bootstraps admin
data/database.js       SQLite schema — 10 tables
data/seed.js           Event + FAQ seeder (INSERT OR REPLACE)
lib/email.js           Google OAuth → SMTP fallback → console
middleware/auth.js     Player auth (requireLogin, loadPlayer)
middleware/rateLimit.js In-memory rate limiter
routes/                12 Express routers
views/                 EJS templates
  layouts/             main.ejs (public), admin.ejs (admin panel)
  partials/            navbar, footer

Features

Deployment

Docker container behind Traefik on the same VPS that runs the Travel Tamers ecosystem. Auto-SSL via Let's Encrypt, health check endpoint at /health, persistent SQLite volume. The entrypoint script handles database seeding and admin bootstrapping — deploy once, everything initializes automatically.

"24 teams. One ship. Zero spreadsheets. Everything from registration to brackets to post-tournament photos runs through the same codebase."

Visit Pickleball at Sea →