← Back to Blogs

TAMP v3: Rebuilding Travel Agency Software for Andaman Tour Operators

From enquiry to island itinerary, quoted in minutes. How I rebuilt a slow legacy portal into a multi-tenant SaaS, proved its pricing against the old code, and moved eight years of history across.

Table of Contents

  1. What is TAMP?
  2. Why a Rebuild, Not a Patch
  3. The Stack & Locked Decisions
  4. Multi-Tenancy Without Row-Level Security
  5. A Pricing Engine Proven Against the Old Code
  6. The Quote Builder, in Four Steps
  7. Contract Rates vs Live Rates
  8. Bookings, Invoices & Money
  9. Operations: Duties & Drivers
  10. Migrating Eight Years of Data
  11. Going SaaS
  12. Engineering Lessons
  13. FAQs

1. What is TAMP?

TAMP (Travel Agency Management Portal) is the back office for an Andaman tour operator. A lead arrives from the website or mail. A sales executive builds a Port Blair, Havelock and Neil itinerary with hotels, ferries, cabs and entry tickets. The quotation goes out on WhatsApp. Then the booking, GST invoice, payments and drivers’ duties all happen in the same place.

I built the first versions years ago for a Port Blair agency. TAMP v3 is a ground-up rebuild. It’s live as a multi-tenant SaaS at tamp.threegeeks.in, where any agency can start a 14-day trial on its own address, and the same code also ships as a dedicated install.

What an agency does inside TAMP:

  • Capture leads from the website through a per-agency intake API, then track follow-ups and the pipeline
  • Build quotes day by day, with up to six hotel options and a live server-side price
  • Send quotations as PDF or Word, by WhatsApp or email
  • Turn an accepted option into a booking with travellers, hotel reservations and ferries
  • Issue GST invoices and credit notes, verify payments and pay supplier bills
  • Auto-generate driver and escort duties, and send WhatsApp alerts the night before
  • See dashboards and monthly statements, with real margins and conversion

2. Why a Rebuild, Not a Patch

The legacy app had become painfully slow for an agency with eight years of data, yet the database was under 5 GB. Volume wasn’t the problem. Code and schema were:

  • No secondary indexes and no foreign keys.
  • Date filters like MONTH(col) = … that no index can use, and the financial year computed row by row.
  • Dashboards that re-ran the full quotation-costing routine for every booking. One page view could issue tens of thousands of queries.
  • Related ids stored as comma-separated lists and split with correlated subqueries.
  • Pricing logic inside a 9,300-line class, mixed with HTML.

Indexes alone could buy time, and a stop-gap index kit for the running app was part of the plan. But a real fix needed a new data model, and a new data model meant a rebuild with a migration path. It was also the right moment to bring security up to modern standards.

3. The Stack & Locked Decisions

Laravel 13 · PHP 8.4
Inertia + React 19 + TypeScript
Tailwind 4 + shadcn/ui
MySQL 8.4 / MariaDB
Redis + Horizon
dompdf + PHPWord
WhatsApp via GeekAds
Razorpay
Pest + PHPStan level 8

TAMP v3 is a modular monolith: one deployable, split into domains for platform, identity, catalog, CRM, quotes, pricing, bookings, finance, operations, documents, comms, reporting and archive. App servers keep no state, so it scales out by adding nodes. Twenty decisions were locked before the first line of code, and every new one since is recorded as a short ADR, so nothing gets quietly re-argued mid-build.

AAll money is integer paise. No floats, anywhere.
BThe server is authoritative. The UI sends selections, and client-posted totals are ignored.
CTotals are computed once and snapshotted. Lists never re-price.
DInvoice and voucher numbers are gapless, per agency and per financial year.
EPublic identifiers are ULIDs. Numeric ids are never exposed.
FEvery list is server-paginated, with an index that leads on tenant_id.

4. Multi-Tenancy Without Row-Level Security

TAMP shares one database across agencies with a tenant_id column. Unlike my PegWise build on PostgreSQL, MySQL has no row-level security, so isolation has to come from elsewhere:

  • Composite foreign keys. Every child row references (tenant_id, parent_id), not just parent_id. The database itself refuses to link a quote to another agency’s hotel.
  • A fail-closed scope. A tenant model queried without a tenant context throws instead of returning everything.
  • Architecture tests. The build fails if a table lacks UNIQUE(tenant_id, id), if a foreign key isn’t composite, if a model is missing the tenant trait, or if raw SQL appears outside the reporting and migration modules.
  • A route-sweeping isolation test. Every route that takes a record is called with another agency’s record and must return 404. A new route parameter fails the test until it’s mapped.

5. A Pricing Engine Proven Against the Old Code

Pricing an Andaman package is fiddly: room shares, extra beds, children with and without beds, vehicles, ferries, group costing, markups and GST bands. Agencies trust the old numbers, so the new engine had to match them exactly before anything else was built on it.

I built a golden-master harness that runs the real legacy pricing code on PHP 7.4 against a scratch copy of the old schema. It covers 323 scenarios: every package type, passenger mix, GST band, extra-mattress variation and group variant. The new PricingEngine is pure, uses integer paise and exact fractions for room shares, and matches all 323 on line rates, persons, GST and totals. To check the tests themselves, I deliberately broke the engine and confirmed that 25 to 159 fixtures fail each time.

Where the old maths had quirks, the owner decided each one. The fixes live in a v3 rule set, and a per-agency switch keeps imported history on the legacy rules, so old quotes still show the price the customer actually saw.

6. The Quote Builder, in Four Steps

My first builder was one long page. It was powerful, and it confused the people who’d used the old flow for years. So the old steps came back as a stepper on the same page, with the data model and pricing unchanged underneath:

1 · Itinerary

Trip, travellers and day plans. “Quick suggestions” fill every day from the agency’s most-used sequences.

2 · Hotels

Up to six hotel sets, a price table per night, apply-to-all for meal plan and rooms, and “Suggest options”.

3 · Costing sheet

Day and night tables, per-traveller lines, markups and discount, and a printable view.

4 · Send & book

Documents, WhatsApp or email, terms, and “Book this option”.

A costing sign-off sits between steps 3 and 4. No PDF, WhatsApp or email goes out until someone verifies the costing. The sign-off is tied to a fingerprint of everything that affects the price, so editing notes keeps it but changing a room clears it. The live price preview takes about 130 ms per round trip with 13 queries or fewer.

7. Contract Rates vs Live Rates

Agencies price mostly from hotel contracts, but sometimes a live rate is cheaper. TAMP shows two prices per option: the assured contract rate, and the live-optimised rate as built. A “cheaper combination” view compares contract and live prices night by night and applies the better one in a click.

Live prices are valid for 24 hours, after which documents and sending are blocked until someone rechecks them. “Suggest options” runs a branch-and-bound search for the cheapest hotel sets within a budget and category, using contract rates only. Online price comparisons are shown for evidence but never become a price line on their own.

8. Bookings, Invoices & Money

A booking freezes its option’s price as a snapshot. Invoices and reports read the booking, never the quote, so editing a hotel rate next season can’t rewrite last year’s revenue.

  • Invoices are immutable once issued. Corrections are credit notes.
  • Only verified payments count towards a balance.
  • Invoice numbers are allocated last, inside the transaction, so they’re gapless.
  • Traveller ID numbers are encrypted, write-only, and always shown masked.
  • PDFs and Word files are generated in a queue and stored privately. Share links are signed and point at the agency’s own address.

9. Operations: Duties & Drivers

When a booking is confirmed, TAMP creates one duty per day-plan leg. Times are adjusted for flight arrival and departure and for booked ferry sailings. Ops assigns drivers, escorts and vehicles on a daily chart that warns about double-bookings and gaps.

Drivers and escorts don’t need an account. Each day they get a signed link on WhatsApp showing their duties, the guest’s phone number, pickup point and time, where they can mark a duty done or log an expense. At 7 pm the next day’s duty list goes to staff and the driver details go to guests. At 9 am, anyone in operations is told about duties that still have no driver. Vendor drivers’ completed duties draft a supplier bill automatically.

10. Migrating Eight Years of Data

A rebuild is only useful if the history comes with it. The legacy importer is idempotent, so a re-run is a delta sync. Rows it can’t import go to a quarantine table with a reason, and every module ends with a reconciliation that has to add up.

On the original agency’s production data:

  • ~36,600 quotes, ~101,000 hotel sets and ~510,000 night rows imported, with every checksum exact
  • 400 random historic hotel sets priced by the old app matched the import line for line
  • Closed leads from past financial years moved to an archive database in about 2 minutes, which made live lists faster (bookings in ~71 ms)
  • A full cutover rehearsal, from loading the dump to a restored production copy, took 1 h 54 min

The archive is invisible to reports. Periods before the cut-off read live and archive together, so archiving changes no number, and a test proves it. Lists have a Live / Archive toggle, and old links still open archived records read-only.

11. Going SaaS

With the core done, TAMP became a product. Plans limit staff seats, modules and new quotes per month. Any agency can sign up on the landing page, pick its own subdomain, and land in its own workspace with a 14-day trial. When a subscription lapses there are seven days’ grace before the account is locked.

A platform console manages agencies, plans and payments. Its “view as owner” support mode signs in for 30 minutes with a visible banner, and every change is logged as platform support, so an agency always knows when someone helped. Owners and admins must use two-factor authentication.

12. Engineering Lessons From the Build

ASlow on a small database is a schema problem. Indexes, sargable date ranges and snapshotted totals beat more hardware.
BBefore rewriting money logic, capture the old system’s outputs as a golden master, and mutation-test the tests.
CWithout RLS, composite foreign keys make the database itself refuse cross-tenant links.
DSnapshot prices on the quote and the booking, so history never re-prices itself.
EDon’t fight users’ muscle memory. A stepper over the same data model kept power users happy.
FRehearse the cutover end to end on real data before go-live. The first attempt ran out of disk two hours in.

13. Frequently Asked Questions

What is TAMP?

A travel agency management portal for Andaman tour operators. It covers leads, a quote builder with a server-side pricing engine, WhatsApp quotations, bookings, GST invoices, payments, driver duties and reports, as a SaaS at tamp.threegeeks.in or as a dedicated install.

Why rebuild instead of optimising the old app?

The slowness came from the schema and from pricing being recomputed on every page, not from data volume. Fixing that properly needed a new data model, so v3 is a rebuild with a full migration path.

How do you know the new prices match the old ones?

Golden-master tests run the legacy pricing code on 323 scenarios, and the new engine must match every one. Imported historic quotes were also spot-checked against the old app.

Can TAMP run on our own server?

Yes. The same code runs single-tenant on your own VPS, and an agency can move between SaaS and dedicated hosting.

Can you build travel software for my company?

Yes. Whether you need a CRM, quotation builder, booking engine, B2B agent portal or full SaaS for a Port Blair or Andaman travel business, I can scope and build it end to end.

Running a travel agency in the Andamans?

Tell me how your team quotes and books today and I’ll come back with a scope, timeline and price. Or start a free TAMP trial.