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.4Inertia + React 19 + TypeScriptTailwind 4 + shadcn/uiMySQL 8.4 / MariaDBRedis + Horizondompdf + PHPWordWhatsApp via GeekAdsRazorpayPest + PHPStan level 8TAMP 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.
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 justparent_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
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.