Build AirHelp
KINDAback to the verdict
A local case file per disrupted flight: journey facts, a distance and delay calculation producing a compensation band, an evidence checklist, generated letters citing the right regulation, and deadline tracking that knows the limitation period differs by jurisdiction.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the case file, calculations and document generation.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - decidefree, and it is the first task rather than a formality
Why Phase 1 builds a table of legal figures, and secondary summaries simplify in ways that change outcomes. Reading the text is the difference between a tool that helps and one that misleads you about your own claim.
Get it Read the regulation on the official legal database for your jurisdiction, and the enforcement body's guidance. Record what you checked and when. open ↗
Verify
The rules table has been corrected against the regulation text and the corrections are recorded - have readyfree with an open dataset
Why Distance drives the compensation band, so the coordinates must come from a source you can cite and are licensed to use.
Get it Use an openly licensed airport dataset and record its licence. Verify a few known city pairs against published distances before trusting it.
Verify
Three known city pair distances match published figures - have readyfree
Why Every phase is meaningless against invented data, and real cases have the awkward details: separate bookings, connections, and a vague airline reason.
Get it Use your own disruption if you have one, including the actual airline correspondence. Otherwise construct one in detail from a friend's.
Verify
A complete journey with real times and a real airline reason is entered - decidefree
Why A tool that produces a compensation figure will be read as an answer. If anyone but you uses it, the framing matters more than the calculation.
Get it Decide whether this stays private. If it does not, write the disclaimer before the first screen, not after someone relies on it.
Verify
The non-advice statement appears on every screen that produces an output
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- cases(id, created_at, state, jurisdiction, regulation, rules_version) · state is drafting, submitted, escalated, settled or refused - flights(case_id, ordinal, carrier, number, date, origin_iata, destination_iata, scheduled_departure, actual_arrival, distance_km) - passengers(case_id, name, booking_reference, is_claimant) - disruption(case_id, kind, delay_minutes_at_destination, airline_reason, reason_category) · kind is delay, cancellation or denied_boarding - evidence(case_id, kind, path, added_at, notes) · boarding pass, booking confirmation, airline correspondence, receipts - correspondence(case_id, direction, at, channel, subject, body_path, deadline_at) - rules(version, effective_from, jurisdiction, band_km_min, band_km_max, amount, currency, notes, source_url, checked_on) - The rules table carries a source URL and a check date on every row. A figure without both is not usable.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DB_PATH | required | ./data/cases.db | Case files, containing passenger names and booking references. Local, and worth encrypting the backup. |
EVIDENCE_DIR | required | ./data/evidence | Where evidence files are stored, one folder per case. |
DEFAULT_JURISDICTION | required | UK | Which rules set to resolve by default. Changing it changes amounts, currency and limitation period. |
DEADLINE_WARN_DAYS | required | 90 | How far ahead of the limitation date to warn. Long enough to actually act. |
RULES_PATH | required | ./data/rules.json | The dated rules table. Every figure here carries a source and a check date. |
The build, in order
The rules table, before any logic
Every legal figure lives in dated data with a source, and nothing is hard coded.
As of September 2026 the EU bands are 250 euro under 1,500 km, 400 euro from 1,500 to 3,500 km and 600 euro above 3,500 km, and the UK equivalents are 220, 350 and 520 pounds. Enter them with sources and check them yourself.
Files
data/rules.jsonThe three hour arrival threshold, and the rule allowing a reduction for a long flight arriving between three and four hours late. Both as data.
Files
data/rules.jsonSecondary sources summarise and simplify. Read the text itself for the rows you entered, and record what you changed.
Files
docs/rules-review.md
done when · tick each as it passeswatch out- A compensation amount written as a constant in the code is a figure nobody will re-check, and these change. Reform proposals were under discussion in 2026 that would replace the current patchwork of national limitation periods with a single deadline, potentially from around the second half of 2027. Keep every figure in dated data so a change is a row rather than a rewrite.
Journey facts and distance
A case records the journey accurately, and the distance is computed the way the regulation means it.
With scheduled and actual times per leg, and a flag for whether they share one booking reference.
Files
src/journey.jsFirst origin to final destination. Verify against a published distance for a city pair you know.
Files
src/distance.jsActual arrival against scheduled arrival at the final destination. This is the number the regulation uses.
Files
src/delay.js
done when · tick each as it passeswatch out- Two errors here change the answer and both are easy to make. Distance is measured from the first departure to the final destination on a single booking, so a connecting journey is one distance rather than the sum of its legs. Delay is measured at the final destination, so a two hour delay on the first leg that causes a six hour arrival delay is a six hour case.
Eligibility, with the uncertainty visible
The application says which band applies and, just as clearly, what it cannot decide.
Distance and delay to a band and amount, using the version effective on the flight date.
Files
src/assess.jsTwo lists in the output. Anything requiring judgement goes in the second list with a note on where the burden lies.
Files
src/assess.jsCategorised for your own tracking, with the burden of proof noted, and no verdict.
Files
src/reasons.js
done when · tick each as it passeswatch out- Extraordinary circumstances is the airline's defence and the burden of proving it rests with them, but whether a given reason qualifies is a legal judgement that has been litigated extensively and is not reducible to a lookup table. Present the airline's stated reason, note that the burden is theirs, and never output a confident yes or no on it.
Evidence, and what is missing
The case knows what it has and what it still needs.
Delay, cancellation and denied boarding need different evidence. Keep the lists as data.
Files
data/checklists.jsonIn a case folder with recorded kinds and notes. The manifest is what you attach.
Files
src/evidence.jsBooking access and app records disappear. Say which and how soon.
Files
data/checklists.json
done when · tick each as it passeswatch out- Airline apps and booking sites remove access to a booking within months of travel, and a boarding pass in an email is easy to lose in a search. Capture the evidence at the time of the disruption rather than when you get round to claiming, and make the checklist say which items become unobtainable.
Letters and the deadline patchwork
You can send a correctly framed letter and you know when the claim expires.
First claim and escalation, both drawing figures from the rules version rather than restating them.
Files
templates/From the rules table, with the basis shown next to the date. Never one global period.
Files
src/deadlines.jsA warning with real notice, and a copy of every letter with its date.
Files
src/correspondence.js
done when · tick each as it passeswatch out- Applying one limitation period everywhere will either lose a valid claim or waste effort on an expired one. The period depends on where the claim is brought and is set by national law rather than by the regulation itself, so keep it per jurisdiction in the rules table with its own source, and show the basis alongside the date.
Escalation, records and knowing when to stopproduct builder
You know what happens after a refusal, and you can hand the whole case to someone else.
Per jurisdiction, with a source and a check date, exactly like the rules table.
Files
data/escalation.jsonFacts, evidence, letters and the assessment. Readable by a solicitor without this application.
Files
src/export.jsIn the documentation and in the interface at the point of refusal. This is the honest part.
Files
README.md
done when · tick each as it passeswatch out- A refused claim is where the service you are replacing earns its fee, because contesting a refusal means arguing about evidence and law rather than filling in a form. Record the escalation route, and be honest in your own documentation that a contested case is where a no-win no-fee arrangement is often worth the percentage.
That is the whole plan for AirHelp. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Legal advice or a judgement on a contested case.
- Someone to argue with the airline for you.
- No-win no-fee risk sharing.
- Case law interpretation of extraordinary circumstances.
- AirHelp staff handling airline correspondence and negotiation
- case-specific legal judgment across jurisdictions
- lawyer access and funded legal action under a no-win, no-fee model
- commercial flight, weather, and disruption data used to validate claims
- professional support and accountability when a claim becomes contested
- A capture flow for the moment of disruption, since evidence is easiest to collect at the airport
- Support for a second jurisdiction, which is a rules table addition rather than code
- A reminder that checks stale rules rows against their sources on a schedule
Need the files? The project pack on the verdict page hands your agent the whole brief · more travel.