Departures · the document, by section.
Click any row to jump. The full document is one continuous read; the board exists for navigation, not as a substitute for the narrative.
The MVP, the price, the timeline, the risks — in one screen.
A 90-second read. Everything that follows is detail. If you only read this section, you have the shape of the build.
- AX sells premium experiential travel through a workflow built for phone calls and back-office vendors.
- Every customer interaction routes through DigitalTrip — a platform AX doesn't own and one that's reaching end-of-life.
- Without rebuilding, AX cannot capture more leads, deliver an AI-native discovery experience, or scale beyond the current operating envelope.
- A bounded MVP (12–14 weeks, £40k) that replaces DigitalTrip with an AX-owned platform.
- AI advisor at discovery, structured TripBuilder at fallback, booking-ops vendor (TBD between FacilitaTrip and Travel Compositor) for back-office.
- Multi-currency, ATOL-compliant, observable, secure — production-grade architecture from commit one.
- Migration-safe by design: Year-3 vendor swap rewrites the integration seam, not the customer experience.
Top risks · explicit mitigations.
A platform built for the way Awesome Experiences sells.
Technical architecture for the AX MVP. What gets built, how, where the risks are, and how cost and timeline are protected. Written for the people deciding whether this gets built.
AX owns the platform.
- Every line of code, every database row, every booking record stays portable.
- FacilitaTrip is a back-office vendor — not a lock-in.
- Year-3 swap rewrites the integration layer only, not the customer experience.
Premium, not demo.
- No disabled features, no Vietnam-only restrictions, no mocked-for-screenshot flows.
- Multi-currency from day one. Six languages activated at launch.
- Production-grade security and performance budgets enforced in CI.
AI as advisor, not autopilot.
- Mid-tier conversational LLM with in-session memory; cross-session persistence architected for Phase 2.
- Hard-bounded to AX-approved inventory — cannot invent trips or quote unsanctioned prices.
- Cannot bypass booking guardrails. Accelerates discovery, never impersonates.
Build a system serious enough that customers trust it with the most expensive holidays they take, and investors trust it with the next round.
- Pioneers Club + structured discount-code engine
- Live agent take-over of customer bookings
- Multi-currency real-time + six-language launch, architected day one
- Defence-in-depth security: removed the attack surface, then hardened what's left
- In-flow lead capture, abandoned-search recovery automation
- Editorial blog module + structured SEO / GEO schema
- MVP fixed price: £40,000 + VAT
- Ongoing retainer: £500/month — website hosting + 3–4 hrs/month (maintenance of the live system, plus small development requests)
- AI / LLM usage billed at cost, on top of the retainer
- 12–14 weeks from project start to live launch
- Five named gates with descope / proceed / rescope option
- 10% AX-controlled change-request budget (£4k) — for items AX requests outside agreed scope; only invoiced if used
- Weekly Loom updates, fortnightly checkpoint calls
- Code, IP and data fully assigned on payment
A real platform with a deliberately narrow launch.
The most common question a CTO asks when reading an MVP plan is: where does MVP end and full-scale begin? That distinction is set out below. The platform we architect is sized for the full envelope from commit one. The catalogue we launch with is curated, not exhaustive. Phase 2 expands it.
Real, live, fully-functional.
Nothing in MVP scope is disabled, mocked, or placeholder. ATOL certificates are real. Stripe takes real money. The DMC genuinely receives the email. The matching algorithm genuinely learns. Cold Lava does not ship demonstration-only software.
Phase 2 expansion path.
The MVP catalogue of 40-50 trips across 15-20 countries is the starting envelope. The platform is built to scale to a full-scale catalogue of approximately 250 trips across 50 countries without architectural rework. Phase 2 expansion is a content and operational exercise, not a technical re-platforming.
Side by side.
The business model the platform is built around.
The platform is not a generic booking engine. It is a wrapper around AX's specific operating model: DMC-anchored, ATOL-protected, catalogue-owned, with a Pioneers Club layer for early adopters and discount-driven cohorts. Every architectural decision below traces back to one of those facts.
DMC-anchored business logic.
Awesome Experiences books packages, not flights. The Destination Management Company on the ground confirms inventory, supplies the experience, and handles in-resort. The platform is built around DMC orchestration: every booking starts with a DMC notification and ends with a DMC confirmation. The technology is a wrapper around that real-world workflow.
AX owns the catalogue.
Tour templates, day templates, components, pricing matrices, margin rules, hotel tier definitions, SEO copy, imagery, constraint rules — all stored in AX's database, not the vendor's. FacilitaTrip is a back-office booking engine; it does not own AX's product structure. This is the migration-safety guarantee written into the data model.
Booking confirmation within 48 hours.
Customer-facing promise: any booking that starts has a confirmed DMC outcome (accept / alternative / reject) within 48 hours of deposit. The system enforces this as an SLA — if a DMC is silent, escalation routes to AX admin automatically. Customers are not left waiting in 'DMC pending' state without a human eye on it.
ATOL legal model — confirmed at kick-off.
ATOL compliance is not primarily a software question. It is a question of who is legally principal for each package booking. The answer is a kick-off decision — and it determines who issues the ATOL Certificate, who holds customer money, and which booking system is mandated. The platform implements to whichever model AX confirms.
AX holds its own ATOL licence.
AX is the principal for every package. AX issues every ATOL Certificate. AX bears the financial protection responsibility — bonding, audited accounts, APC payments per passenger, CAA reporting, claims handling. The platform issues certificates directly from the booking flow. Most flexible long-term; highest compliance overhead up front.
AX sells under a host operator's ATOL.
AX operates as an agent under a written agreement with an ATOL-licensed host. The host is the principal; the host issues the ATOL certificate; the host typically holds the customer payment. The host's booking system may be mandated. Lower compliance overhead; some operational constraints depending on the host. Many UK boutique tour operators run this model.
Pioneers Club — discount and membership layer.
AX’s loyalty and acquisition model. Members get early access, exclusive trips, and discount codes scoped at trip or cohort level. Built into the data model from commit one so AX can run promotions from launch — not bolted on after.
Promo codes scoped per-tour, per-cohort, percentage or absolute, with date constraints. Powers Pioneers Club offers and standalone sales promotions alike — including partner-tied campaigns. Enforced on every quote.
Selected tours flagged as Pioneers Club exclusives, hidden from public catalogue, only visible to logged-in members.
New trips visible to Pioneers Club for a configurable window before opening to general catalogue.
Codes apply to sell price, never to net cost. AX margin is preserved even on the most aggressive discount.
Agent takeover.
AX staff can open any customer’s session from the admin dashboard, edit the booking on their behalf, and complete the payment via a Stripe payment link sent during a phone call. Every edit is audited under the agent’s identity; the customer sees the change set in their booking history with the agent’s name. Detail in §013 Booking Flow.
It is treated as a first-class state transition rather than a side feature. It is how AX retains high-touch customer service in a self-serve digital flow.
The end-to-end customer flow.
From the first ad impression to the post-trip review and back into the matching engine. Two parallel discovery paths (AI advisor and structured wizard), an exception loop on DMC rejection, and a self-perpetuating feedback loop that returns from post-trip improvements into both the matching algorithm and discovery for the next traveller.
Acquire
Lead enters via paid, organic, partner, or remarketing. UTM and behavioural data captured pre-consent at minimum-necessary level only; full tracking activates on cookie permission. Landing page is dynamic — same template, different hero based on campaign source.
Discover & match
Customer chooses path: AI advisor or structured wizard. Both feed the same matching engine. Engine applies hard filters, then ranks AX-approved trips with weighted scoring and returns top 5. Customer selections train the algorithm via damped feedback.
Tailor, book, confirm
Detail page → live tailoring with real-time re-pricing → provisional booking + Stripe deposit → DMC confirmation step (accept / alternative / reject) → confirmed booking with ATOL Certificate issued, margin frozen, customer in their account.
Trip & loop
In-resort experience and live itinerary in the web app. Post-trip questionnaire feeds Improvements — which tunes match-engine weights and seeds discovery for the next traveller in the same cohort. The system self-perpetuates.
Six layers, named at every level.
Stated precisely. The system is six horizontal layers, each owned explicitly by AX or by a vendor. AX owns every layer above the Integration Bus. The Integration Bus is the seam where AX-owned code talks to vendor systems — and the seam where a Year-3 swap would rewrite the integration layer only, not the customer experience above it.
Layer-by-layer.
Booking-ops vendor evaluation — Week 0 / Week 2 gate.
The AX brief leaves the vendor open between FacilitaTrip and Travel Compositor (§004b makes the comparison explicit). Week 0 is sales calls and demos with both. Week 1-2 is contractual and technical review of whichever vendor AX confirms — sandbox access, payload examples, sandbox booking proven end-to-end, gap analysis. AX retains the right at this gate to descope, defer, or proceed at the original scope.
The booking-ops vendor is a Week 0 evaluation. Architecture is shape-agnostic until it's resolved.
AX has left the booking-ops vendor open: ‘most probably FacilitaTrip or Travel Compositor.’ The architecture commits to neither until the Week 0 evaluation gate. The Integration Bus connects to whichever vendor AX confirms — and the rest of the API stack adjusts accordingly.
FacilitaTrip vs Travel Compositor — both are candidate connectors.
Pricing for both: not publicly available. FacilitaTrip starts at €1,500/user/month per Capterra. Travel Compositor is tier-based (‘choose 8 of 20 engines’). Both require sales conversations as a Week 0 gate item.
Connector inventory · MVP / Phase 2 hedged by booking-ops choice.
Flight connectors — the named primary.
The named primary flight connector is the Lyme / Aviate consolidator — two sides of the same business: Lyme handles British Airways and the broader BA group; Aviate handles all other airlines. Both expose an API (recently introduced; their previous model was offline-only via phone, email, or manual entry). They are named here as the most likely default for MVP and Phase 2, not as a required dependency — additional flight inventory sources can be added as connectors over time.
Why the booking-ops choice cascades.
FacilitaTrip's supplier breadth is shallower. Direct connectors fill the gap on day one.
- Duffel for flights — MVP day one
- Direct Viator Merchant — MVP day one
- Hotelbeds APItude — Phase 2
TC's 100+ supplier connectors collapse most of the direct-API stack into the booking-ops layer.
- Hotelbeds inventory — already in TC, no separate integration needed
- Viator inventory — already in TC, direct Merchant becomes optional Phase 2
- Duffel — Phase 2 / case-by-case (TC covers most flight needs)
Every choice named. Every alternative named.
Each technology was selected against named alternatives. Click any row to see why it won and what was rejected.
Speed is a budget. We commit to numbers.
Performance is treated as a budget, not an afterthought. The platform commits to specific Core Web Vitals targets per region, monitored from launch via Vercel Speed Insights. Regressions of more than 10% week-over-week trigger an alert.
Production targets per region.
Targets measured at the median of real-world traffic captured by Vercel Speed Insights. Lighthouse scores measured on mobile profiles in CI before each release.
How we hit them.
Edge rendering on Vercel.
Stateless pages — homepage, category landings, trip detail — render at the edge with Incremental Static Regeneration on a 5-minute revalidation cadence. Stateful pages (TripBuilder, account, booking) render from the user's nearest region.
Image pipeline.
Every image served via next/image with AVIF and WebP fallbacks, responsive sizes per breakpoint, blur placeholders. Vamoos-sourced imagery auto-resized and cached on Vercel's image CDN. Hero images carry priority and a per-page bundle budget of 350 KB.
Font subsetting.
Brand fonts subset to the Latin-1 character set, served via next/font with display: swap. Total font payload under 60 KB gzip. No FOUT, no FOIT, no layout shift on text load.
Bundle budget per route.
Hard limit of 180 KB JS gzip per route, enforced via next-bundle-analyzer in CI. Route-level code splitting on the TripBuilder, the LLM advisor, and the tailoring module — each is a separate bundle, loaded only when entered.
Database query budget.
Any list endpoint serving search results returns in ≤ 180 ms p95 from a warmed Postgres. Indexes on tour_template (destination, duration, party_size), pricing_matrix (tour_id, date_band, party_size), and a denormalised trip_search_index materialised view rebuilt nightly.
Reference points.
Liverpool Cotton Brokers
Built by Cold Lava, live since Q1 2026. 1.4 s LCP from UK in real-world traffic. The performance discipline behind that score carries directly into AX.
Greenstar Solar
Cold Lava rebuild of a legacy WordPress site. Image-heavy domain, rendered fast through the same image-pipeline approach used here.
Every browser, every screen, tested before release.
Browser and device coverage, made explicit. The platform supports an explicit matrix of browsers and three responsive breakpoints. The MVP ships as a fully responsive website — no native iOS or Android binary, no App Store / Play Store distribution. AX’s spec calls for a ‘downloadable APP’; the architecture is PWA-ready, with home-screen install activated in Phase 2 rather than the MVP build (see Phase 2 Roadmap).
Browser support matrix.
Coverage figures from StatCounter UK, rolling 90-day window. On iOS, third-party browsers (Chrome, Firefox, Edge) run on the same Safari / WebKit engine, so the Safari row covers them. Older browsers receive a simplified server-rendered fallback — bookings still complete, with reduced visual polish.
Three breakpoints, intentional layouts.
Single column. Sticky bottom nav on TripBuilder. Tap targets ≥ 44 × 44 px.
Two column. Sidebar collapsible. TripBuilder steps stack vertically with persistent progress bar.
Full layout. Persistent left sidebar. Map and itinerary share viewport. Hover affordances active.
PWA-ready architecture — home-screen install activates in Phase 2.
Home-screen install as a Progressive Web App — on iOS 16+ Safari and Android 12+ Chrome, with an icon, splash screen, and full-screen launch — is a Phase 2 addition. It bridges the spec’s “downloadable APP” ask without the App Store review cycle, the Play Store fees, or the native-code maintenance burden.
MVP scope is the fully responsive website. Both the PWA home-screen install and the richer in-trip companion experience — offline-first vouchers, push for flight delays, daily itinerary map, in-app contact-AX — are mapped in the Phase 2 Roadmap, not in the £40k commercial scope.
Phase 2App Store + Play Store distribution. React Native wrapper around the PWA, certificate management, ongoing store maintenance. Indicative add: £15–25k.
QA pipeline + accessibility.
BrowserStack matrix on every release branch.
A smoke suite covers homepage, TripBuilder happy path, search results, trip detail, booking flow on each browser × breakpoint combination. Visual regression diffs via Percy — any unexpected diff blocks the release until resolved.
WCAG 2.2 AA throughout.
Keyboard navigation, contrast ratios, ARIA labels, focus management on the TripBuilder steps. Verified via axe-core in CI plus a manual NVDA and VoiceOver pass before launch. No interactive element relies on hover or colour alone.
Multi-currency and i18n, day one architecture.
Multi-currency is built into the data model from commit one. Sterling is the platform's source-of-truth currency. Suppliers price in around ten base currencies; the platform retails to customers in three presentment currencies — GBP, EUR and USD. The MVP launches in six languages; the i18n architecture scaffolds further locales for activation as AX expands, quoted separately at that point.
FX rate freeze — five points, named.
Travel pricing is a finance system requirement, not a feature. The platform defines exactly when an FX rate is sourced, when it freezes, who bears exposure, and how refunds compute. Five named points; nothing implicit.
i18n architecture — six languages at launch.
ICU message catalogues.
All UI copy lives in next-intl JSON catalogues, keyed by string ID. Activating a language is a translation and review pass over the catalogue, not a code change. The catalogue ships with the six launch languages populated and further locales stubbed.
Locale-prefixed routes from commit one.
The site ships with locale-prefixed route segments in place for the launch languages. Further locales can be activated by populating the catalogue and toggling a flag — no routing rework, no new Next.js patterns to learn.
Currency abstraction.
The pricing layer takes a quote in supplier currency and renders in the requested presentment currency. Adding a presentment currency beyond the launch set is a Stripe configuration change plus a single backend toggle — no schema migration.
Supplier-currency capture.
Every component (hotel night, transfer, experience) stores its net cost in the supplier's currency. Margin computation respects supplier currency. This is what makes future multi-currency expansion non-disruptive.
Five layers of test coverage. Failures block merges, not launches.
Five test tiers, each with a tool, a coverage bar, and a CI gate. The point isn't 100% coverage — it's that nothing breaks silently between AX sign-off on staging and the customer reaching the deposit page.
Five tiers of coverage.
What blocks what.
Every test seeds its own data via fixtures. Production database is never touched. Stripe uses test mode keys. ATOL generation runs against a sandbox issuer. Anthropic uses a separate API key on a $20/month spend cap so test runs can't accidentally tip the production budget.
AX staff run a structured UAT pass against staging. Acceptance script per deliverable in §3 of the proposal. Failures block production promotion. UAT is a sign-off ritual, not a discovery — automated tests catch regressions before they reach UAT.
Four environments. Preview-per-PR. Migrations isolated by Neon branching.
The defensive answer to ‘how does code get from a developer's machine to production safely?’ Vercel handles deploys; Neon handles database branching; CI handles gates. Every PR has its own preview URL. Every migration is rehearsed on a branch before it touches production.
Four environments.
Pipeline · code → production.
- 01PR opened. Vitest + ESLint + type-check + axe-core + Percy diff. Vercel preview URL posted to PR.~3 min
- 02PR merged. Playwright golden flows on Chromium. Auto-deploy to staging.~6 min
- 03Staging deployed. Cross-browser Playwright on BrowserStack. Smoke test against real Stripe sandbox + ATOL sandbox.~12 min
- 04UAT sign-off. AX runs structured acceptance script. Tickets opened against any failures.Ad-hoc
- 05Production promote. Manual click in Vercel dashboard. Database migrations run via Neon branch-then-merge.~2 min + monitor
Database migrations · Neon branch-then-merge.
Migrations are the highest-risk part of any deployment. Neon's branching model lets us rehearse each migration against a real copy of the database before touching production.
Every PR gets a Neon branch off staging. Migrations run against the branch. Application connects via env-var-injected DSN.
Integration tests + E2E run against the branched DB. Real data shape, isolated writes. Branch is read-only against parent.
On PR merge, the migration is applied to staging. Forward-only — no rollback once merged. Reverts go through a new corrective PR.
Production migration is a separate explicit step at promotion time. Schema dry-run on a fresh production-clone branch first to catch surprises.
14 entities. Three layers. Audited everywhere.
The platform's data model is structured in three layers: catalogue (the AX product), booking (transactions), and user (identity + history). Every transactional row is versioned, every booking-affecting write is audited, every user-owned table is RLS-protected. The ERD below is the spine.
Catalogue layer.
AX-owned. Pre-built structured content. The differentiation lives here — AX’s curated tours, pricing rules, supplier mapping. Year 3 FacilitaTrip swap leaves this layer untouched.
Booking layer.
Transactional. Regulated (ATOL audit). Linked to FacilitaTrip via booking reference but not dependent on FacilitaTrip's schema.
User layer.
Identity, preferences, GDPR audit, AI session state. The only layer carrying personally-identifiable information at scale.
Versioning + audit — example.
The PricingMatrix is the most temporally-sensitive table. Below is its shape. Every other transactional table follows the same audit-column pattern.
CREATE TABLE pricing_matrix (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tour_template_id UUID NOT NULL REFERENCES tour_template(id),
date_band_start DATE NOT NULL,
date_band_end DATE NOT NULL,
party_size party_size_enum NOT NULL,
hotel_tier_id UUID NOT NULL REFERENCES hotel_tier(id),
room_type room_type_enum NOT NULL,
-- Costs in supplier currency, sells in GBP
net_cost NUMERIC(12,2) NOT NULL,
net_currency CHAR(3) NOT NULL, -- ISO 4217
sell_gbp NUMERIC(12,2) NOT NULL,
margin_pct NUMERIC(5,4) GENERATED ALWAYS AS
((sell_gbp - (net_cost * fx_to_gbp)) / sell_gbp) STORED,
-- Validity window, versioning
valid_from TIMESTAMPTZ NOT NULL,
valid_to TIMESTAMPTZ, -- NULL = current
superseded_by UUID REFERENCES pricing_matrix(id),
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by UUID NOT NULL REFERENCES users(id),
version INT NOT NULL DEFAULT 1,
CONSTRAINT no_overlap EXCLUDE USING gist
(tour_template_id WITH =, party_size WITH =, hotel_tier_id WITH =,
tstzrange(valid_from, valid_to) WITH &&)
);
CREATE INDEX idx_pricing_lookup
ON pricing_matrix (tour_template_id, party_size, hotel_tier_id)
WHERE valid_to IS NULL;Versioning rules — applied across the model.
Audit columns on every transactional table
created_at, created_by, updated_at, updated_by, version. Standard across User, Booking, Passenger, Payment, DMCRequest, ATOLCertificate.
PricingMatrix versioned, never overwritten
Each price update creates a new row with a valid_from / valid_to window. Historical bookings always reference the price they were booked at.
Immutable audit_log for booking writes
Every write to a booking-related table writes a row to audit_log. actor_id, action, before, after, correlation_id. 7-year retention for ATOL.
Soft deletes for user-deletable data
User-initiated deletion soft-deletes the record (deleted_at). Anonymisation pass redacts PII while preserving financial integrity. Hard delete after 30-day cooling-off.
An advisor, not an autopilot. Bounded by design.
The AI advisor is a Cold Lava USP — a mid-tier conversational interface, hard-bounded to AX-approved inventory. It cannot invent trips. It cannot quote prices it has not been given. It cannot bypass the booking guardrails. It accelerates the discovery experience, it does not impersonate the platform.
Try it. The advisor is live, scoped to a sample of AX's catalogue.
This is the actual claude-sonnet-4.6 model running through Vercel's AI Gateway against 157 real AX toursscraped from the existing site. The model is bounded by the same guardrails described below — try asking for Antarctica or somewhere AX doesn't cover, and watch what happens.
Destination, party, rough dates, budget, style — anything works. I'll search AX's 157 tours and recommend a few that fit.
This demo is an illustrative example. The production advisor — its prompts, conversational flow, and behaviour — is tailored to AX following detailed requirements discussions.
How it's wired.
Claude Sonnet 4.6 (Anthropic).
Mid-tier reasoning with strong instruction-following and tool use. Public pricing: $3 / $15 per million input / output tokens. Enough capability to handle nuanced travel preferences at materially lower latency and cost than the Opus 4.7 top tier ($5 / $25 — about 1.7× Sonnet, not the 3× ratio that Opus 4.x shipped with). The architecture supports an upgrade to Opus in Phase 2 with no application code change — only a model identifier swap. Pricing verified at docs.claude.com on 10 May 2026.
In-session in the MVP; cross-session in Phase 2.
Within a session, the advisor holds the full conversation context — preferences, dislikes, stated constraints. Cross-session persistence — remembering you didn't enjoy long bus transfers in Vietnam when you return weeks later to plan Cambodia — is architected from commit one but activated in Phase 2. Once live, AI memory falls under the right-to-erasure scope (§018), purged with the customer record on the 30-day hard-delete cadence.
Tool-calling schema.
The model interacts with the platform through four named tools. Conversation orchestration is the model’s job; data retrieval and scoring belong to deterministic Cold Lava code.
Hallucination guardrails — three layers.
System prompt as policy.
The Claude system prompt is a 1,200-word document, versioned in the repo, reviewed at every change. It explicitly bounds the model: AX trip catalogue only, no fabricated pricing, no fabricated routes, no fabricated hotel names, no off-catalogue destinations. Loaded fresh at every session start.
Tool-calling schema, not free generation.
The model does not produce trip recommendations directly. It calls four tools, each implemented in Cold Lava code, each backed by the AX catalogue. The model orchestrates the conversation; the matching engine produces the recommendations.
Output validation before render.
Every tool result is validated before reaching the user. Trip IDs must exist in the catalogue. Prices must match current pricing. Hotel names must match catalogue records. Validation failures route the model back through a stricter retry. Three consecutive failures end the session and route the user to the structured TripBuilder.
When a user requests a destination AX does not currently offer, the model never invents a trip. It acknowledges the gap and offers the closest available match.
Cost model and controls.
Cost model: pay-as-you-go metered API with multi-layer cost controls. Per-session cost (working range, with optimisations applied): £0.08–0.15; pessimistic ceiling £0.20. The earlier £0.40 figure represented an unoptimised baseline — standard optimisations bring it well below. AI / API run-rate costs are carried by Cold Lava through the build and testing phases; metered cost passes to AX at handover.
Six-layer defence-in-depth on run-rate.
- 01Structural optimisation. Prompt caching on system prompts (~90% cost reduction on repeated context), Haiku for filtering/classification, Sonnet for advisor reasoning, structured outputs. Combined: ~50–70% reduction vs unoptimised baseline.
- 02Per-session caps. 25,000-token budget per session, with graceful auto-handoff to the TripBuilder when reached.
- 03Per-user rate limiting. ~10 advisor sessions per IP per day, with cooldown windows on rapid-fire usage.
- 04Bot protection. Vercel BotID plus CAPTCHA on AI advisor entry, server-side request validation. See §017 Security for the full bot-protection scope.
- 05Real-time monitoring with AX-controlled safety threshold. Continuous token-spend monitoring with anomaly detection. A configurable monthly safety threshold (default £500/month) acts as a final backstop: when reached, the advisor temporarily pauses with a polite handoff to the TripBuilder until AX raises the threshold or investigates the cause. The threshold sits under AX’s control — it can be raised, lowered, or effectively disabled at any time, and is a commercial decision, not a Cold Lava-imposed ceiling. Alerts fire at configurable percentages (defaults 50% / 75% / 90%) ahead of the threshold.
- 06TripBuilder primacy. The structured 6-step TripBuilder is the default flow; the AI advisor is for complex or free-form needs. ~80–90% of visitors never invoke LLM spend. See §011.
£180–300 / month at MVP scale — assumes ~10,000 monthly visitors, ~15% engaging the AI advisor.
£500 / month default — a configurable backstop, not a fixed ceiling. AX can raise, lower, or effectively disable it at any time. When reached, the advisor pauses with a polite handoff to the TripBuilder until AX adjusts the threshold or investigates.
Hard filters, then weighted scoring, with damped feedback.
The engine ranks in clear stages. Hard filters come first — destination and activity type — narrowing the catalogue to trips that structurally fit; a trip that fails a hard filter is never shown. A weighted scoring pass then ranks what remains across the softer dimensions and returns a top-5. A conservative safety-and-suitability overlay sits across both, hard-excluding trips that would be genuinely unsuitable for the traveller. The weighting profile is configuration-driven and AX-owned: Awesome Experiences sets the initial values, and the profile itself is AX IP. Cold Lava's contribution is the engine and the damped-feedback loop — assigned to AX on payment, like every other Cold Lava-authored module in §025. Both the structured TripBuilder and the LLM advisor feed the same engine.
Try the matching engine live.
Drag the sliders. The top-5 reorders in real time as the engine rescores every catalogue trip against your preferences. The score breakdown bars show which dimensions drove each placement. Six dimensions shown here for clarity — the production engine runs the full set detailed below, across both stages.
- #1Highlights of Vietnam & Cambodia with Phu Quoc 14 Nights91 / 10015d£1,000slowVietnam · CambodiaPaceBudgetDurationAdventurePartyMonth
- #2Conquer Mount Kilimanjaro - Private Climb with Zanzibar88 / 10011d£750moderateTanzaniaPaceBudgetDurationAdventurePartyMonth
- #3Head to Toe Chile86 / 10013d£1,000moderateArgentina · ChilePaceBudgetDurationAdventurePartyMonth
- #4Head to Toe Chile86 / 10013d£1,000moderateChilePaceBudgetDurationAdventurePartyMonth
- #5Luxury Chile - Head to Toe86 / 10013d£1,000moderateChilePaceBudgetDurationAdventurePartyMonth
This demo is an illustrative example. The production matching engine — its filters, dimensions, weights, and scoring — is tailored to AX following detailed requirements discussions.
Try the structured trip builder.
The 6-step structured path — the default flow for most visitors. Each step writes to the same structured field set the matching engine consumes. This mirrors the functionality of AX’s existing trip builder, rebuilt to the platform’s design language.
What kind of experience are you after?
- Experience typeNot selected
- RegionNot selected
- DepartureNot selected
- PreferencesNot selected
- Guides & transfersNot selected
- Budget ppNot selected
This demo is an illustrative example. The production trip builder — its steps, options, and flow — is tailored to AX following detailed requirements discussions.
Matching engine: hard filters and scored dimensions.
The engine ranks trips against the customer’s stated preferences and returns a small ranked set — a top-5 with an overall match score. Not every input plays the same role. Some define structural feasibility and are applied as hard filters; the rest are weighted, scored, and ranked. A walking holiday returns walking trips — never a city break that happened to score well on budget and dates.
Applied before any scoring. A trip that fails one of these is excluded — or down-ranked so heavily it effectively never appears in the top results.
Destination, region, country
The customer must specify — or have inferred — at least a region before meaningful ranking can occur. A trip outside the stated destination is excluded; it does not enter the ranked set however well it scores on everything else.
Category / activity type
Specialist activity products — walking, wildlife, festival, culinary and similar — are respected as categorical needs. A customer who selects a walking holiday does not see non-walking tours in their top results, however well those tours score elsewhere. Category is matched directly, not approximated by a generic adventure score.
Run only on the trips that pass the hard filters. These contribute to the overall match score but do not exclude trips outright. Pace is decomposed into two underlying dimensions — physical intensity and schedule tempo — because it means two different things.
Safety and suitability overlay.
Certain combinations of customer attributes and trip attributes are treated as hard fails regardless of overall score:
- High-intensity treks for travellers who indicated mobility constraints, limited fitness, or relevant age flags — excluded.
- Trips requiring sustained altitude or remote conditions for travellers with relevant health flags — excluded.
The safety overlay is deliberately conservative. It is better to exclude a marginal-fit trip than to recommend something that would be unsafe or unpleasant for the traveller.
Configurable weighting.
The matching engine is data-driven, not hard-coded. Each scored dimension carries a weight (0–100) that determines its contribution to the overall match score. Weights are stored as a configurable data record, editable by Awesome Experiences without code changes, and new dimensions can be added with their own weights.
The initial weighting profile is provided by Awesome Experiences’ founder, William Burton, drawing on two decades of operating a tour-matching business. The weights themselves are provided at project kick-off; every weight shown or implied in this document is placeholder and illustrative until then. The relative shape is deliberate: destination and category weights sit very high — at near-hard-filter levels — while pace and adventure are important but subordinate, and other soft preferences lower still.
Booking-conversion data then refines the weights over time. The refinement is conservative— adjustments are small, validated against booking outcomes, and reversible if they degrade match quality. A poor initial profile destabilises the feedback loop, so AX’s existing operating intuition is the starting position; data-driven refinement layers on top of it, it does not replace it.
Damped feedback loop — how the algorithm learns.
Selection signal recorded.
When a customer selects one of the top 5, the dimensions where that trip outscored its peers are reinforced. Dimensions where it underperformed are softly downweighted.
Damping applied.
Each weight update is dampened by a momentum coefficient (default α = 0.15). Single sessions don't whip the algorithm — only consistent signal across many sessions moves weights materially.
Per-cohort, not per-individual.
Phase 1 learns at cohort level (segment buckets like 'culture-focused 30-50 traveller'). Individual-level personalisation is Phase 2, with explicit consent.
Bounded weight range.
No weight can grow beyond 2× its initial value or shrink below 0.25×. Prevents runaway feedback loops that lock the algorithm into a local optimum.
The update rule.
# Pseudo-code — scored-dimension weights only.
# Hard filters (destination, activity type) and the safety
# overlay run before this; only trips that pass are scored
# and ranked here.
def update_weights(prefs, ranked_top5, selected_index, weights, alpha=0.15):
selected = ranked_top5[selected_index]
for dim in SCORED_DIMENSIONS:
dim_score_selected = score(prefs[dim], selected[dim])
dim_score_others = mean(score(prefs[dim], t[dim])
for t in ranked_top5
if t is not selected)
# Reinforce dimensions where selected outscored others
delta = alpha * (dim_score_selected - dim_score_others)
# Damped update with bounds
new_weight = weights[dim] * (1 + delta)
weights[dim] = clamp(new_weight,
0.25 * INITIAL[dim],
2.00 * INITIAL[dim])
return weightsPace and adventure: getting the wording right.
The TripBuilder asks about pace and adventure in language that distinguishes the underlying dimensions without overwhelming the customer with questions. “How physically demanding do you want this trip to be?” drives the physical-intensity dimension. “How busy do you want your days to be?” drives the schedule-tempo dimension. Each question carries short helper text, so the customer always knows what it controls — the wording deliberately avoids the common mistake of conflating walking intensity with itinerary busy-ness.
Adventure level is asked separately again, and kept distinct from activity type — activity type is the categorical need, matched as a hard filter, not a slider. Where an answer is genuinely ambiguous, conversational follow-up and disambiguation are the job of the LLM Advisor: the structured TripBuilder stays structured, the Advisor is the conversational path, and both feed the same engine.
Two paths in, one engine.
The TripBuilder is the default flow for most visitors — its structured 6-step path handles the majority of trip-planning needs efficiently and intuitively. The AI Advisor is available for visitors with complex, multi-constraint, or free-form needs the structured path cannot easily express: pasted dream-trip descriptions, voice input, or unconventional combinations of regions and themes. Most visitors complete a trip via the TripBuilder; the AI Advisor is a power-user path.
6-step TripBuilder
Customer chooses dates → countries → experience type → guide preference → budget → review. Each step writes to the same structured field set the engine consumes.
LLM Advisor
Customer types a paragraph or pastes an itinerary. Claude extracts to the same structured fields via the extractPreferences tool (§010). Validates completeness before passing to the engine. Identical output format, identical scoring.
Allowed actions, named constraints, real-time pricing.
Tailoring is the most interactive piece of the platform — and the place where unbounded flexibility breaks the booking economics. The engine takes a small, named set of allowed actions, enforces a constraint engine, and re-prices every change. No free-text 'change anything' — every mutation is a typed action with rules.
Allowed actions — six, named.
Constraint engine — declarative DSL, evaluated per action.
Every action passes through a constraint engine before it commits. Rules are declarative (per-tour configuration, not hard-coded). If a rule fails, the customer sees an explanation, not a broken itinerary.
Live re-pricing pipeline.
- — 01Mutate. Customer triggers an action (add day, swap activity). The action is captured as a typed event.
- — 02Validate. Constraint engine checks the proposed mutation against all rules. Failure surfaces immediately to the customer with the rule name.
- — 03Recompute pricing. Pricing engine recalculates total + margin from PricingMatrix. Includes any FX delta if supplier-currency exposure shifts.
- — 04Persist. Tailored itinerary version saved with audit columns. Saved-search token updated so the customer can resume.
- — 05Render. UI updates with new total + margin (margin only visible to AX agents, not the customer).
A booking is a state machine. Every transition is named and audited.
The booking layer is regulated. ATOL, payments, supplier confirmation, and accounting all interact. The way to keep that surface honest is to model the booking as a state machine — every transition triggered by a named event, every transition logged. The diagram below is the system in one read.
Triggers and side effects.
Every transition is owned by a named event. The events listed are the load-bearing ones — the ones that move money, issue regulated documents, or notify external systems. Everything is logged to the immutable audit trail with correlation ID.
DMC email-confirmation model — edge cases.
Phase 1 uses an email-based DMC confirmation, not API integration. That constrains the failure modes we need to handle explicitly in the state machine. Each one below has an enforced behaviour, not an aspirational one.
DMC silent (no response)
Reminder at 48 h, AX admin alerted at 72 h, manual escalation from there. Booking holds in DMC Pending — deposit refundable on customer request until confirmed.
DMC partial accept (e.g. days 1-8 yes, day 9 no)
DMC submits an alternative via the hosted form. Booking transitions to Alternative. Customer reviews, accepts, or routes back to Tailored to adjust.
DMC accepts then later cancels
Booking reverts to Cancelled. Issued ATOL certificate is voided. Refund to customer triggered manually by AX with full record in audit log. ATOL host informed if applicable.
Multiple DMC channels per tour
Out of scope Phase 1. Each tour has one nominated DMC channel. Multi-channel routing is Phase 2.
DMC insolvency mid-booking
Manual ops by AX. Platform records the event and freezes the booking; refund / re-routing handled outside the system in v1.
Customer abandons mid-payment
Booking transitions Provisional → Cancelled after PaymentIntent expiry. Saved-search recovery email fires after 24 h with a resume link.
Agent takeover.
Agent take-over is a first-class state transition, not a feature bolted on. AX staff open a customer’s live session from the admin dashboard. Edits commit under the agent’s identity and are audited — the customer can see every change, with a timestamp and a reason note. Stripe payment links can be sent for phone bookings, completing the loop.
Customer trust is preserved by transparency. A booking edited by AX shows that fact in the customer’s booking history, with the agent’s name and the change set. There are no silent modifications.
Stripe-native, multi-currency, zero PCI burden.
Payments are handled end-to-end by Stripe Elements. Cold Lava code never sees, stores, or transmits card data. PCI compliance lands at SAQ-A — the lightest scope possible — by deliberate design: we removed the attack surface, then hardened what's left. 3DS / SCA enforced. Multi-currency built in from launch — see §008 Currency for the FX rate-freeze model that makes this work.
Deposit + balance, decoupled.
Deposit and balance are separate Stripe PaymentIntents linked by booking reference. A partial refund on deposit does not corrupt balance state. A failed balance does not reverse the deposit. Each intent has its own webhook, its own state, its own audit row. Two money events are not one event.
Locks the booking, freezes margin and FX.
On Stripe success, FX rate is captured against the booking record, margin snapshot persists, DMC notification fires, booking transitions Provisional → Deposit Paid → DMC Pending. ATOL Certificate is NOT issued at this stage — see §013 for the ordering that protects AX from issuing regulated documentation against unconfirmed inventory.
Scheduled, automated, monitored.
Balance due date is computed from tour start and supplier terms. Stripe PaymentIntent for balance is created when due. Customer reminder fires N days before; failure routes to AX admin chase flow. Late payment does not silently break the booking — exception path is named and visible.
Accounting webhook — the contract.
Every Stripe state transition fires a webhook to the accounting layer (Xero or QuickBooks at MVP launch, configurable). The webhook payload carries the fields below. AX’s accountant uses these to compute TOMS quarterly — the platform records the data, the accountant runs the calculation. TOMS-aware journal entries direct from the platform are Phase 2.
Captured at every step. Recovered automatically. Saved with audit.
Travellers do not book in one sitting. The platform captures lead data at every plausible stage, recovers abandoned searches automatically, and feeds the CRM with structured records. Every consent is logged with the wording version active at capture time. No exit pop-ups.
Capture points — six, distributed.
Every capture writes a row to the GDPR consent_ledger with timestamp, IP, and wording version. The platform never silently captures or repurposes data.
Recovery automation — five trigger paths.
CRM record shape.
The platform syncs records to AX's CRM (HubSpot at MVP launch, or equivalent — configurable) on every meaningful state change. The record below is the canonical shape; CRM-specific field mapping is configurable.
Email deliverability · ATOL certificates must never land in spam.
SendGrid handles transactional sends with Postmark as fallback (§015 stack). Beyond the provider choice, deliverability is its own discipline:
Deliverability monitored via SendGrid + Postmark dashboards plus weekly DMARC report review. ATOL cert delivery rate is a tracked SLO (target: 99.5% inbox placement, p95).
The screens AX staff use every day. Not an afterthought.
A platform that replaces phone calls with software needs the staff-side screens to be at least as polished as the customer-side. Ten named screens, four roles, every action audit-logged — the staff-side experience scoped as deliberately as the customer-side.
Screens · ten of them, all in MVP scope.
Role-based access · four roles.
Every write — bookings, refunds, catalogue edits, agent take-overs — produces an audit row containing actor, target, before/after diff, IP address, timestamp. Audit log is append-only, replicated to a separate Postgres database, retained seven years per ATOL + accounting rules.
Admin tooling is route-protected pages inside the same Next.js codebase as the customer site. No separate admin app, no separate deploy. Login uses the same auth, so AX staff can move between admin and customer-facing views with one session.
A single signed-in home for every customer.
Every customer who books or saves a trip with Awesome Experiences has access to a dedicated My Account portal. It consolidates all customer-facing functionality into a single signed-in experience, accessible from the main site header at all times.
What the portal covers.
Account management
Register, log in, manage profile, set communication preferences, update payment methods.
Saved trips and quotes
Resume any saved search or in-progress quote via signed magic-link emails. Trips stay saved indefinitely unless the customer deletes them.
Booking history
Full record of past, current, and upcoming bookings — status, payment history, and itinerary access.
Active itineraries
For trips in progress or imminent: itinerary details, vouchers, certificates, and supplier documents in one place. Read-only access to the in-trip dashboard views (§018b).
Documents
Centralised storage of all booking-related documents — invoices, vouchers, e-tickets, visa letters, insurance certificates, supplier confirmations.
Travel preferences
Dietary requirements, accessibility needs, room preferences and traveller details recorded once and carried forward to all future bookings.
After booking — a personalised checklist.
The moment a booking is confirmed, the portal switches the customer into a personalised to-do list — a clear, ordered view of everything they need to do and submit before they travel. Each item shows its status, what is needed, and a one-click action: upload a document, pay a balance, follow a link. It pulls directly from the pre-travel compliance checks in §018b, so the customer sees the same requirements AX’s staff track — visa requirements, passport validity, insurance proof, balance payments — without chasing or guessing. The journey is designed to be calm and obvious: the customer always knows exactly what is outstanding and what is done.
- ✓Booking confirmedATOL certificate issued and stored in your account
- Passenger & passport detailsAdd each traveller's details — passport flagged automatically if expiry is close
- Visa requirementsVisa needed for your destination — your responsibility, with a direct link to official guidance
- Travel insuranceUpload your policy document — one click, straight into your account
- Balance paymentDue date shown clearly; pay early or on schedule
- Pre-departure packItinerary, vouchers, contacts and packing notes — available from T-21 days
Why it matters.
Reduces customer-service load.
Customers self-serve on the majority of 'where do I find X' or 'what's my booking reference' queries.
Builds loyalty.
A saved account with travel history is a switching cost — customers have more reason to return to AX for their next trip.
Centralises compliance documents.
Vouchers, certificates and travel documents live in one customer-controlled location, reducing lost paperwork and missed pre-departure requirements.
SEO and GEO — built into the data model, embedded on handover.
Travel discovery starts on Google and increasingly runs through LLMs. The platform ships with structured data, server-rendered metadata, clean URLs, and an editorial blog framework — SEO and GEO are embedded into the build, not bolted on afterwards. Cold Lava also provides SEO and GEO audits of the live surface as part of the engagement.
JSON-LD structured data — six schemas.
Every page emits structured data. Google reads it for rich results; LLMs read it for retrieval-augmented generation. Both matter for travel discovery.
URL structure.
Server-rendered metadata.
Editorial blog module — Phase 2 framework, MVP foundations.
Foundation in place.
Routes scaffolded (/blog, /blog/[slug]). Database schema for posts (title, body, hero image, author, publish date, tags). RSS feed endpoint. JSON-LD Article schema. Editorial tooling itself (CMS, editor experience, scheduling) is Phase 2.
Editorial workflow.
Sanity (or equivalent headless CMS) for content authoring. Multi-author support with approval workflow. Image management. Scheduled publishing. Internal linking suggestions. AX content team gets a real authoring experience without paying for it twice in MVP.
Defence in depth, from edge to data.
Security is the single concern raised most often by serious technical reviewers, and the one most easily reduced to platitudes. This section is specific. Named controls at every layer, named tooling, named cadences. Nothing aspirational.
Edge
Vercel Firewall blocks known bad IPs and common WAF patterns. Rate-limiting on every /api/* route at 60 req/min per IP with burst tolerance. Vercel BotID challenges bot traffic across the booking flow, the AI advisor, and lead-capture forms. DDoS absorption is handled at Vercel's edge.
Transport
TLS 1.3 enforced. HSTS with preload. Strict CSP (default-src 'self', allow-list for Stripe, GA4, Meta Pixel). Trusted Types enforced. Subresource Integrity on all third-party scripts.
Application
Next.js 16 with Server Components — most data flows server-side, minimising client surface. All API routes guard on the userId from session. No user can read another user's saved trips, account data, or bookings under any code path.
Data
Postgres with Row-Level Security policies on every user-owned table — saved_searches, bookings, passengers, payments. AX admin role bypasses RLS via a separate service-role connection used only by admin endpoints, all of which require explicit re-authentication.
Secrets
All secrets in encrypted Vercel environment variables, scoped per environment. No .env in the repo. Rotation cadence: Stripe / FacilitaTrip / Anthropic keys every quarter. Rotation runbook lives in docs/runbooks/secrets-rotation.md.
OWASP Top 10 — every category, named mitigation.
Beyond the checklist.
Zero card data on Cold Lava infrastructure.
Stripe Elements iframes the payment form. PCI compliance is fully offloaded to Stripe (SAQ-A scope). Cold Lava code never sees, stores, or transmits card data — not even transiently.
CREST-accredited test against staging in Week 13.
A third-party penetration test runs against the staging environment one week before go-live. Findings triaged by severity; all critical and high findings are fixed before production launch.
Credential stuffing, payment fraud, ATOL-cert phishing.
Customer accounts use 2FA + email-confirmation on payment-method changes. Stripe Radar enabled with custom rules flagging high-value first-time bookings, IP/billing-country mismatch, unusual booking velocity. Audit log makes any post-incident forensics straightforward.
No unverified packages.
Only npm packages on Snyk's no-known-malware list with weekly downloads above 10k. Lockfile checked in. SRI on third-party scripts. No package added without a security review note in the PR.
Disaster recovery · explicit RTO and RPO.
A fair question of any booking platform: what happens if Postgres is down for 4 hours mid-booking? Concrete answer below.
RTO = recovery time objective (how long until service restored). RPO = recovery point objective (acceptable data loss window).
Backup and continuity.
The platform is resilient to multiple categories of failure — regional outage, database compromise, code-host loss, slow corruption, operational error. The continuity model rests on three independent layers.
Hourly snapshots (rolling 24-hour recovery), nightly off-region backups copied to an independent geographic region, and Write-Ahead Log replication for point-in-time recovery. Combined: an RPO of seconds, not hours.
All code in GitHub with full Git history. Production deployments versioned through Vercel — any version rolls back in seconds. A branch-based workflow means no production deploy without a tested, reviewed change.
All repositories mirrored weekly to a Hetzner Storage Box in Europe — different jurisdiction, different credentials from GitHub. Multi-generation retention (weekly snapshots kept for months) means a slow compromise can be recovered from a known-good state prior to the compromise window.
ATOL, GDPR, accessibility — designed in, not bolted on.
Travel is regulated. Selling to UK and EU residents adds GDPR and accessibility obligations. The platform handles each compliance surface explicitly: ATOL Certificate generation tied to confirmed bookings, GDPR consent ledger and DSAR/erasure tooling, WCAG 2.2 AA verified in CI.
ATOL Certificate generation.
On confirmed booking (post-DMC accept — see §013 Booking Flow), the platform generates an ATOL Certificate PDF. The certificate is emailed to the customer, stored on the booking record, and an immutable audit log entry is written. ATOL legal model (Option A: AX as principal vs Option B: host operator agency) is confirmed at kick-off — see §002 Operating Model.
GDPR — consent, DSAR, erasure, residency.
Consent capture
Every consent action (cookies, marketing, third-party) writes a row to the consent_ledger table with timestamp, wording version, and IP. Wording is versioned in repo; if it changes, prior consents are flagged for re-collection.
Data subject access (DSAR)
Admin endpoint returns a customer's full record (account, saved searches, bookings, communications) in machine-readable form. SLA: 30 calendar days, target 5 working days.
Right to erasure
Customer-initiated deletion soft-deletes account, anonymises booking records (PII redacted, financial records retained for legal requirement), tombstones consent ledger entries. ATOL audit retention overrides for 7-year window.
Data residency
Postgres + Redis instances run in eu-west-2 (London). Vercel Edge serves UK + EU customers from European edge nodes. No customer PII transits to US infrastructure.
Accessibility — WCAG 2.2 AA.
Terms & Conditions — visa requirements clause.
“It is the sole responsibility of each traveller to obtain any visa, entry permit, transit visa, or other travel documentation required by the countries of destination, transit, or return. Awesome Experiences will provide reasonable advisory information (including links to official government sources) but does not guarantee the accuracy, completeness, or currency of such information, nor accept liability for travel arrangements that cannot proceed because of missing, invalid, or refused visa documentation. Travellers are advised to verify visa requirements with the relevant embassy or consulate well in advance of travel. Refunds and rebookings in the event of visa failure are subject to the applicable cancellation policy and any insurance the traveller has in place.”
The clause above is indicative wording and is subject to legal review by AX’s solicitor before publication as live Terms & Conditions.
From deposit to departure to return — every check, every reminder, named.
Checks on passports, visas, vaccinations, insurance, and balance payments — with reminders and customer assistance during travel. In the MVP these run as a manual-plus-automated workflow: automated expiry flags and reminder cadences, with visa and vaccination data from AX-maintained tables. Real-time API validation (Sherpa) is the Phase 2 upgrade, costed when volume justifies it.
Pre-travel checks · MVP delivery vs Phase 2 upgrade.
Reminder cadence · seven touchpoints from deposit to T-1.
Customer assistance during travel.
Operational maturity, from the day the URL goes live.
The platform is observable from commit one. Every error has a stack trace, every request has a correlation ID, every booking-affecting write is audited. Custom dashboards surface the metrics AX will check daily — funnel, AI cost, DMC SLA, conversion. On-call paging is wired in for the launch window.
Custom dashboards.
Four dashboards ship with the platform. Each is curated for a real AX user role — leadership looks at funnel + revenue, ops staff look at operational, the AX growth lead looks at AI advisor health.
Booking funnel
- TripBuilder start → step 6 → results → trip detail → booking
- LLM advisor session → recommendation → click-through to trip detail
- Save-search → email capture → resume rate
- Deposit-paid → DMC confirmation latency
- Top abandonment points (per step + per source)
AI advisor health
- Sessions started, sessions completed, abandonment by step
- Token usage per session, per day, per month
- Hallucination guardrail triggers (validation failures + retries)
- Off-catalogue suggestions vs in-catalogue matches
- Spend vs the £500/month safety threshold — alerts at 50%, 75%, 90%
Operational
- DMC confirmation SLA: time from deposit to confirmed (target <48h)
- DMC silence escalations triggered (48h, 72h)
- Stripe payment success rate, 3DS challenge rate, fraud flag rate
- ATOL Certificate issuance — count, time-to-issue post-DMC
- Refunds initiated (count, value, reason code distribution)
Conversion + revenue
- Booking conversion by traffic source (organic / paid / partner)
- Average order value, by trip and by cohort
- Pioneers Club discount usage + revenue attribution
- Repeat customer rate
- FX exposure tracked (live supplier-payable across currencies)
Year 3 swap = rewrite the seam, keep the spine.
A core requirement: AX does not get locked into a single booking-ops vendor indefinitely. Six architectural principles applied from commit one. The Year 3 swap-out cost is bounded by design: 3-6 months of integration work, not a full rebuild. (Vendor-agnostic from day one — see §004b.)
The six principles, applied today.
AX owns the catalogue.
Tour templates, day templates, components, pricing matrices, margin rules, hotel tier definitions, SEO copy, imagery, constraint rules — all stored in AX's database. FacilitaTrip is a back-office booking engine; it does not own AX's product structure.
API abstraction layer.
The frontend never talks directly to FacilitaTrip. Every vendor call goes through the AX API → Integration Bus. Vendor-specific quirks live in the Bus only — they never leak into the AX-owned layers.
Portable booking records.
Bookings are stored in AX's Postgres with ALL relevant fields — passenger details, financial records, status history, ATOL certificate, payment references. Data export is tested monthly. Migration assumes export will happen one day.
Stripe under AX control.
Payment orchestration is owned by AX, not the vendor. Stripe API keys belong to AX. PaymentIntent records are linked from AX's Booking table. If FacilitaTrip is replaced, Stripe stays. PCI scope stays SAQ-A.
Accounting integration owned by AX.
Webhook fires from the Integration Bus to Xero/QuickBooks, not from FacilitaTrip directly. The accounting sync is replaceable as a single component, not a vendor-specific dependency tree.
Audit trail belongs to AX.
Booking audit log is in AX's Postgres, not FacilitaTrip's logs. ATOL audit (7-year retention legal requirement) survives any vendor change. CAA can audit AX directly without vendor cooperation.
Year 3 swap — what changes vs what doesn’t.
Mapped against today’s components. The honest assessment: the Integration Bus rewrites; everything above it stays.
Built to be built upon.
The MVP is not a standalone system that is set aside when Phase 2 begins. It is the foundation the entire roadmap is built on — and it is built that way deliberately. Cold Lava builds in stepping stones: each piece is designed to be extended, so the platform grows rather than restarts.
A planned progression, not a restart.
Phase 2 does not begin from scratch. The architecture for later phases is anticipated in how the MVP is built — every layer is designed to be extended, not replaced. The next phase grows from this platform; it does not require a rebuild.
A stepping-stone build.
Each component is built so the next can be added without rework. The broader roadmap is already planned — subject to change as the MVP's review and real-world performance inform priorities. Growth and scalability are designed in from commit one.
Every asset is AX-owned and reusable.
Everything built — including Additional Works modules such as the Contract Ingestion Agent, detailed in the Additional Works document — is an Awesome Experiences-owned asset. AX can carry it forward into any future amendment, build, or system it chooses. Nothing delivered is locked to this platform alone.
DigitalTrip → AX-architecture, with link equity preserved.
DigitalTrip end-of-life is end of June. The platform must replace it without losing search rankings or breaking customer-facing URLs. Migration is a four-phase activity overlapping the build, with redirect mapping and content audit as Week 1 work, not Week 14.
- Crawl existing DigitalTrip pages with Firecrawl — capture every URL, status code, and content hash
- Vamoos-source image catalogue inventoried — every image referenced + intended target
- Existing data export from DigitalTrip dump (already received) parsed and mapped to AX schema
- Content audit: which pages have material SEO equity, which are dead weight
- AX confirms the MVP catalogue (40-50 trips across 15-20 countries per §001b)
- Trips have full content drafted into the new platform: text, imagery, day-by-day breakdowns, pricing matrix, supplier mapping
- Imagery resized and optimised through next/image pipeline
- FAQ content for each trip + landing page entered
- 301 redirect map produced from existing DigitalTrip URLs to new AX URLs
- High-equity pages prioritised — those with backlinks, search rankings, or social shares
- Edge-level redirects via Vercel — fast, no application code involved
- Sitemap.xml regenerated and submitted to Google Search Console
- DNS cutover from DigitalTrip to AX-architecture (Vercel)
- DigitalTrip put into read-only mode for 30 days for any orphaned content
- Search Console monitored daily for crawl errors + ranking shifts
- First 14 days post-launch: dedicated on-call rotation watching for traffic anomalies
Premium-restrained, warm, editorial.
The visual register Cold Lava builds in is not 'agency premium' (mood-board mockups) and not 'big-tech minimalism' (cold, Helvetica-everywhere). It's editorial — tech publication, warm and confident, where every typographic choice and every motion cue earns its place.
Premium-restrained.
Lots of whitespace. Serif headings used as confident accents, not as decoration. Precise typography rhythm. Restrained motion — every animation has a reason. The editorial register: tech publication, not agency pitch.
Warm, not icy.
Backgrounds are warm-black (never pure #000). Text is paper-cream (never #FFF). Accent is burnt coral, confident and warm, not the AI-pink default. The system reads like print quality, not screen quality.
Type as architecture.
Display: Instrument Serif at editorial sizes. Body: Inter at honest reading sizes. Monospace: JetBrains Mono for codes, dimensions, signatures. The hierarchy is clear at a glance — every page is laid out, not just composed.
Typography scale.
Motion principles.
Every animation has a reason
Reveal on viewport entry communicates section structure. Hover-state changes communicate interactivity. Loading shimmers communicate state. Decoration is not a reason.
Reduced-motion respected
All animation queries useReducedMotion() and degrades to instant reveal. Accessibility built in, not bolted on.
No bouncing, no springing
Eased curves only ([0.2, 0.8, 0.2, 1] for primary motion, [0.16, 1, 0.3, 1] for hero reveals). Premium-restrained means no toy physics.
Velocity matched to scale
Large elements move slowly (0.7-0.9s); small elements move quickly (0.3-0.45s). Physically intuitive.
The way we deliver. Visible, testable, predictable.
Software is hard. Delivery against fixed price + fixed timeline is harder. The way to keep a 12-week regulated build honest is rigour about cadence, testing, and acceptance — and visibility for the client at every step. The detail below is what AX gets, by the week, by the test layer, by the acceptance test.
Communication rhythm.
Test approach — five layers, each in CI.
Every failing test in CI blocks merge to main. No silent passes. Pre-launch: a one-week UAT window where AX staff exercise the platform on a staging URL, identical to production except for test Stripe keys.
Acceptance criteria — per proposal §3 deliverable.
Each deliverable in proposal §3 has a corresponding test that AX or Cold Lava QA executes at UAT. A deliverable is “accepted” when its test passes. AX signs off acceptance per row; aggregated sign-off triggers the final 34% invoice (proposal §6).
Five gates. No silent overruns. AX controls every decision.
A fixed-price build lives or dies on one question: does the budget run out mid-build? The contract is built around five named gates, each with an explicit pass/fail criterion and an explicit descope/proceed/rescope option. Cost or time pressure shows up as a conversation at a gate, never as a surprise invoice or a silently shipped subset.
The five gates.
Drift protections — controls already in the contract.
The contingency model.
The £40k+VAT headline price covers everything in the agreed MVP architecture. A 10% scope-change contingency of £4,000 sits alongside it, available for items AX requests during the build that fall outside the agreed scope. It is not an automatic uplift and is not pre-billed — it is a pre-approved buffer for fast-tracking small, clearly-defined extras without a full re-proposal each time.
- 01AX identifies a change or extra during the build that isn’t in the architecture document.
- 02Cold Lava provides a quick estimate (typically in half-day or day units).
- 03AX approves the draw against the contingency pot.
- 04Cold Lava delivers the item and invoices the agreed amount from the pot.
- 05Unused contingency is not invoiced. If AX uses none of it, the project total is £40k+VAT.
Insurance, IP, continuity — every contract risk named.
The contract risks that matter before a build proceeds: are we insured against catastrophe, who owns the IP, what happens if Cold Lava disappears. Every line below is a real policy or commitment, named, and willing to be evidenced at contract.
Insurance — three policies in force.
Certificates of insurance available on request before contract signature. Renewal cycle is annual; certificates re-issued automatically.
IP — clean assignment, full transferability.
Code ownership
Full IP assignment to AX on payment of final invoice. Clean assignment, not a licence. Cold Lava retains no rights to the codebase post-handover.
Repository transfer
Git history transferable. Repo is moved to AX's GitHub organisation on handover, with all commits, branches, PR history, deployment history, and observability logs intact. No rewrites, no obfuscation.
No proprietary build steps
The build is `npm install && npm run build`. No Cold Lava-only tooling, no secret npm packages, no obfuscated build scripts. AX's next developer can clone and run.
Third-party licenses inventoried
All npm dependencies catalogued with their licenses. MIT/Apache/BSD only — no GPL, no AGPL surprises in the dependency tree.
Brand assets
AX-provided imagery, copy, and brand assets remain AX's property. Cold Lava-produced design work (component library, motion patterns) assigns to AX on payment.
Continuity — what happens if Cold Lava isn’t around.
Code escrow option
Iron Mountain or NCC escrow available as an add-on. Quarterly snapshots deposited; AX gains access on Cold Lava insolvency, breach, or written request.
Key-person redundancy
Minimum 2 senior developers across the project at all times. Cover policy means no single point of failure. Holiday rotated, not bunched.
Documentation handover pack
On project completion: README, architecture doc (this site), runbook for every operational task, secret-rotation guide, monitoring playbooks. AX's next developer can operate without contacting Cold Lava.
Handover support window
30 days of priority support included after final acceptance. Out-of-scope work in the window billed at £120/hour, on-demand. Beyond 30 days: standard support retainer or per-engagement.
Training & handover · seven sessions, then forty days of cover.
AX is replacing phone-call workflows with software. A single pre-launch handover session isn't enough — the schedule below replaces it with seven.
Written runbooks (every operational task).
Every runbook lives in docs/runbooks/ in the repository AX owns. Updated as the platform evolves.
Post-launch support window.
Daily Cold Lava check-in (15 min Loom or live). Same-day response on bugs. Slack channel staffed 09:00–18:00 UK. AX comfort grows fastest in this window.
Weekly check-in. 24-hour response on bugs. Customer-impacting issues escalate to same-day. Slack channel still staffed.
Standard support retainer (£500/month, scoped) or per-engagement at £120/hour. AX's call — never imposed.
Continuity if Cold Lava is no longer involved.
If Cold Lava ceases to operate or is no longer engaged for any reason, AX has everything required to keep running and developing the platform without us. Concretely:
- Source code and full Git history are held in AX’s own GitHub organisation, with full ownership transferred on final payment. No proprietary licence, no usage restrictions.
- All commits, branches, PR history, deployment history, and observability logs transfer with the repository. Nothing material is withheld.
- An independent off-platform mirror (see §017) holds weekly snapshots in a separate jurisdiction under different credentials — the codebase cannot be lost or locked away by any single account or provider.
- A handover documentation pack covers architecture, deployment, environment setup, observability, and runbooks — a new developer or agency can pick up the codebase from documentation alone.
- Operational accounts (hosting, database, vendor APIs, DNS, payment) are held directly by AX. None depend on Cold Lava’s continued involvement.
The platform is built on standard infrastructure (Vercel, GitHub Actions, Postgres) with no proprietary build steps. Any reasonably competent successor developer or agency can take over operation without rebuilding from scratch. Continuity is a transition exercise, not a recovery exercise.
14 weeks. Five named gates. Critical path called out.
The build is 14 weeks from kick-off. Five named gates with explicit pass/fail criteria. Critical-path phases highlighted — these are the ones where slip is hardest to absorb. Buffers stated explicitly: AX always knows what slack exists and where.
Phase plan, week-by-week.
- FacilitaTrip API contractual + technical review
- Sandbox booking written end-to-end against FacilitaTrip
- Data model approved against AX's spec
- ATOL legal model confirmed in writing (Option A or B)
- MVP catalogue (40-50 trips / 15-20 countries) confirmed with AX
- Brand assets, imagery, copy delivered by AX
- Homepage + navigation + brand system
- TripBuilder 6-step wizard with state management
- Trip detail pages, dynamic from catalogue
- Customer account: register / login / 2FA / saved trips
- MVP catalogue trips populated with content
- Staging URL live for AX review
- Matching algorithm with 14-dim weighted scoring
- Damped feedback loop on customer selection
- LLM advisor (Claude Sonnet 4.6) with tool-calling schema
- Hallucination guardrails — system prompt, validation, retry
- Saved searches, abandoned-search recovery automation
- Trip tailoring module: day add/remove/move, activity swap, hotel grade upgrade
- Live re-pricing pipeline with constraint engine
- Skyscanner-equivalent flight check on date change
- Stripe Elements integration: deposit + balance, multi-currency, 3DS
- Accounting webhook to Xero/QuickBooks
- Booking state machine with all transitions
- ATOL Certificate generation (post-DMC accept)
- DMC notification + accept/exception/alternative form
- Agent take-over flow with audit
- Pen-test against staging (CREST-accredited)
- Full UAT pass with AX staff on staging
- Acceptance criteria signed off per §3 deliverable
- DigitalTrip → AX-architecture cut-over
- Production monitoring + on-call paging activated
- Handover pack delivered (runbooks, secrets rotation, ops playbooks)
Visual timeline.
Buffer + slip handling.
Buffer week
1 weekBuilt in to weeks 9-11. Absorbs minor slip without renegotiating the launch date.
FacilitaTrip API gap
0-2 weeksIf gate 1 reveals material gaps, project pauses for re-quote. Not absorbed silently.
Pen-test remediation
0-1 weekPen-test runs week 13. Critical findings fixed before launch; medium findings tracked into hyper-care.
Content readiness
AX-sideMVP catalogue content must be ready by end Week 5. Slip is AX-managed; affects launch date directly if not met.
What's deliberately not in the £40k. What gets added later.
Every section that says 'Phase 2' in the doc collects here. Each item has the trigger that typically activates it and a section reference. Phase 2 is the architectural promise: nothing here requires a rebuild, only an addition. Costs are scoped at the time AX activates each item — no Phase 2 cost is committed in this document.
Phase 2 inventory.
Additional capabilities discussed in scoping.
In scoping conversations, several extensions to the platform were raised that sit outside the agreed £40k+VAT MVP scope. This section is not the next phase in full — the architectural roadmap is §026b — these are specific additions, raised for discussion, each optional and separately quoted. Every item here is detailed in full in the Awesome Experiences — Additional Works companion document.
Items discussed.
Contract Ingestion Agent
AI-assisted reading of supplier contracts (PDF and Word) with structured inventory mapping, configurable sanity checks, and a human-approval workflow. Designed as a deliberate replacement for the approximately £12,000/year manual contract-loading role. Fully detailed in Module 1 of the Additional Works companion document.
FCDO Monitoring & Customer Alerts
Active monitoring of UK Government travel advisories with affected-booking detection and draft customer notifications for staff review and dispatch. Fully detailed in the Additional Works companion document.
Additional language activation
Beyond the MVP six languages, further languages can be added — quoted separately per language, based on content volume and QA scope.
Sign-off, kick-off, build.
Five steps to start. Each named, each owned. The fastest version of this is one approving email from AX, a signed SoW the next day, and Cold Lava on the FacilitaTrip API by the end of the week.
Approve this document.
AX reviews this site end-to-end. Any concern, any gap, any change request — flag it as a comment or in writing. Cold Lava responds within 48 hours with either a clarification or an action.
Sign the contract + SoW.
MSA + SoW with the proposal §3 inclusions, §4 exclusions, §8 assumptions, and §9 protections as the canonical scope. Patches v1 + v2 (TOMS, refund/amendment, volume caps, ATOL legal model, narrowed launch catalogue) merged in. Clean revision, no tracked-change ambiguity.
Issue project kick-off invoice (33%).
First payment. Triggers Cold Lava's calendar reservation, FacilitaTrip API access request, and project board provisioning. AX confirms the MVP catalogue (40-50 trips / 15-20 countries) by end of kick-off week.
Kick-off call.
30 minutes. Cold Lava + AX. Walkthrough of the project board, communication rhythm, gate dates, AX-side content readiness milestones. Loom recording for anyone who couldn't attend.
Build begins.
Weeks 1-2 are FacilitaTrip API discovery + architecture sign-off (gate 1). Build proper starts week 3. From here, the contract is the source of truth. Surprises become conversations at the next gate, not silently absorbed.
Contacts.
Cold Lava's calendar is held for the build window. Sign-off triggers the project. Two flights from contract to live: one signed page, one kick-off call.
This document is a single living URL. It updates as the build progresses. Every change ships as a deploy. Every section’s state can be referenced by anchor link in any conversation. When the platform launches, this document becomes the handover record.
Cold Lava is built to ship platforms that survive their delivery. This is the start.
