AI authorship note: I created this article with AI assistance. I provided the experience and source material, directed the research and drafting, checked the technical claims and approved the final text.
Working out status credits for a multi-leg domestic itinerary is not difficult, but doing every segment by hand is tedious. The distance band can change from one leg to the next, the earning rate depends on the fare, and the totals still need to be added across the complete trip.
I wanted a quicker way to estimate the result before booking. That became the Status Credit Calculator, the first application I built with AI assistance.
The calculator is deployed and publicly accessible. It currently covers Australian domestic Qantas routes and provides estimates for Classic Reward and cash fares. I have not linked the current deployment from this article because it still needs to be moved to a personal hostname.
Starting with the requirement
My first brief was fairly direct. A user should be able to enter an itinerary such as BNE-SYD-MEL, or separate trips divided by commas, and receive a result for every leg as well as trip and overall totals.
The application also needed to:
- Reject malformed input and repeated adjacent airport codes.
- Confirm that each code represents an Australian airport.
- Check that each origin and destination pair is a valid route.
- Use the route distance to select the appropriate earning band.
- Show normal and Double Status Credit estimates.
- Plot the itinerary on a map when coordinates are available.
The first version handled Classic Reward fares. Cash-fare comparisons, multiple-trip presentation and more detailed responsive controls came later.
The first version
I built the initial application with GitHub Copilot in Visual Studio Code. It used Python and Flask and ran on an Ubuntu VM behind Nginx and Gunicorn.
That version proved the calculation and validation flow, but the infrastructure was more than this small application needed. It introduced another operating system, web server, application process and certificate path to maintain.
I later used Claude to refactor the application for Cloudflare. The calculation rules and validation behaviour remained, but the runtime changed to JavaScript and managed Cloudflare services.
Browser
|
| itinerary
v
Cloudflare Pages and Pages Functions
|-- validate input
|-- read route data from Workers KV
|-- calculate each leg and trip total
|
+--> Qantas route API on a genuine cache miss
|
+--> JSON result to the browser
|
+--> tables, totals and Leaflet route map
Scheduled Cloudflare Worker
+--> refreshes older KV route data
The current design uses:
- Cloudflare Pages for the browser application.
- Pages Functions for validation, route lookup and calculation.
- Workers KV for airport and route data.
- A separate scheduled Worker to refresh older cached entries.
- Cloudflare Turnstile to reduce automated form submissions.
- Leaflet and OpenStreetMap tiles for the route map.
There are no user accounts, saved itineraries or server-side sessions.
Treating the cache as operational data
The early Cloudflare version gave KV entries a 48-hour expiry. That worked while the upstream route API was available, but it created an avoidable failure mode. If an entry expired while the API was unavailable, valid routes could appear invalid.
The revised design keeps route data in KV without automatic expiry. A scheduled Worker refreshes older entries, and new API responses are checked before they replace known-good data.
If the application has neither cached data nor a usable upstream response, it returns a clear temporary-unavailability error. It does not pretend that the airport or route is invalid.
That decision was more important than shaving a little time from the request. The cache became a resilience mechanism, not just a performance feature.
Adding cash fares without duplicating the workflow
Cash-fare support was added after the initial Cloudflare migration. Classic Reward and cash results are calculated from the same validated itinerary in one request. The user can switch between them without submitting the route again.
The cash view has more fare columns than the Classic Reward view, so the presentation needed different treatment. On a wide screen it uses a grouped table. On smaller screens it focuses on one cabin at a time while keeping the route column visible. The result still includes per-leg values, trip totals and overall totals.
This was a useful reminder that adding a calculation is often the easy part. Making a wide result understandable on a phone took more iteration than adding the underlying fare table.
How I used AI
This project began before I had a settled process for agent-assisted development. I wrote the initial requirements and used Copilot to help turn them into the first Flask application. I then used Claude for the Cloudflare refactor and continued to use coding agents for later changes.
My part was not to claim every generated line as hand-written code. It was to define the behaviour, decide what was operationally acceptable, review the proposed changes, test the results and approve each step forward.
The cache redesign is a good example. A simple expiring cache was technically easy, but it could turn an upstream outage into a misleading validation result. Keeping known-good route data, validating replacements and failing clearly was the more supportable decision.
Limits and assumptions
The calculator is an estimator, not a booking or airline system.
- It covers Australian domestic Qantas routes, not every airline or itinerary.
- Earning tables are stored in the application and need review when airline rules change.
- Route validation depends on an upstream Qantas endpoint that is not a contracted API for this project.
- Cached route data can become stale if the upstream source changes or remains unavailable.
- Workers KV is eventually consistent.
- The map depends on third-party browser assets and tile services.
- Estimates must be checked against the current airline rules and fare conditions before booking.
The application deliberately does not store personal profiles or itinerary history. That keeps the data flow simple, but it also means there is no account-based history or saved-trip feature.
What the project demonstrated
The useful result was not just the calculator. It gave me a complete first pass through AI-assisted requirements, implementation, review and deployment, followed by a real platform migration and several rounds of operational improvement.
The move from Flask to Cloudflare removed a VM from the support path. More importantly, the later cache and error-handling work was designed to reduce dependence on a live upstream response and avoid giving a confident but wrong explanation when data was unavailable.
It remains a small project with a narrow scope. That is part of its value. The design does not need to be larger than the problem, but it still needs honest failure behaviour, maintainable rules and a clear boundary between an estimate and an authoritative result.