← Back

Paid List vs. Rooming List

Compare payment and rooming records, identify discrepancies, and keep group travel organized with confidence through faster, smarter, and more accurate data reconciliation.

☁️ Custom SaaS Platforms
Works with
  • Google Sheets
  • TypeScript
  • Node.js
  • Railway

Project Overview

Paid List vs. Rooming List is a web app that compares group travel payment records with room assignments exported from Google Sheets. It identifies fully paid travelers assigned to rooms, flags missing or unpaid records, and highlights similar-looking names that may need staff review.

Business Problem

Group travel teams maintain separate Paid List and Rooming List tabs in Google Sheets. As lists change, they can become inconsistent: someone may pay but not be assigned to a room, appear on a rooming list without being listed as paid, or have a slightly different spelling of their name across the two lists. Finding these discrepancies manually in spreadsheets with 100 or more rows is slow and error-prone.

An internal tool for a group travel company. Each student travel group keeps two separate tabs in Google Sheets, a Paid List (who paid, how much, and their payment status) and a Rooming List (who’s actually assigned to a room). Those two lists can drift apart: someone pays but never gets added to a room, someone’s on the rooming list but never paid, or a name is slightly misspelled between the two. Catching that manually in a 100+ row spreadsheet is slow and error-prone.

Solution

A small web app where a staff member uploads both CSVs (exported straight from the Google Sheet tabs) and gets back three buckets instantly:

  • Matched: paid in full and on the rooming list. No action needed.
  • Paid List issues (🔴/🟨): on the Paid List but missing from the Rooming List, or not marked “Paid in Full.”
  • Rooming List issues (🔴/🟨): on the Rooming List but missing from the Paid List.
The upload screen: a staff member adds the Rooming List and Paid List CSVs exported from the group’s Google Sheet and clicks Compare.
The results summary and the Paid List issues. Red rows are real discrepancies and yellow rows are similar-name warnings. Names, amounts, room and confirmation numbers are blurred for privacy.
The Rooming List issues: people on the rooming list who are not on the paid list. Names and booking numbers are blurred for privacy.
The matched list: people who paid in full and are on the rooming list, with no action needed. Names, amounts and booking numbers are blurred for privacy.

How It Works

  • Parse both CSVs: the Rooming List always has a header row; the Paid List usually doesn’t, so the parser detects whichever shape it’s in (including an optional leading row-number column, and an “Amount” or “Payment” column).
  • Flatten each rooming-list row into individual occupants (up to 2 per room).
  • Match people by exact, case-insensitive name between the two lists.
  • For anyone with no exact match, check the other list for a close-but-not-exact name (same last name, or a small edit-distance typo/nickname), if found, flag it yellow (“Similar Name Found”) on both sides as a precaution; if truly nowhere on the other list, flag it red as a real discrepancy. A matched person who isn’t “Paid in Full” is also red.
  • Results render as sortable tables in the browser, each downloadable as its own CSV.

Everything runs stateless: nothing is saved to disk; each upload is compare-and-respond.

Tech Stack

Built in TypeScript running on Node.js (a plain Node HTTP server, no framework), with a plain HTML/CSS/vanilla JS frontend. Deployed on Railway.