Contributor App

The PWA at contribute.flighthelp.net. A separate application from the consumer site, with its own codebase, its own bundle, and its own design surface. Consumer-site visitors never download contributor code.

Why a separate app

Three reasons.

Bundle hygiene. The consumer site needs to be under-100kb of JavaScript to hit the performance targets. A contributor workflow needs forms, camera APIs, offline sync, and a richer UI. Combining them would compromise both. Splitting them lets each be excellent at its job.

Audience clarity. Travelers visiting flighthelp.net are not necessarily contributors and should not be confused by contributor UI. Contributors visiting contribute.flighthelp.net are not casually browsing and want a workspace, not a reference site.

Security boundary. The contributor app has authentication and write access. The consumer site does not. Separating them limits the attack surface on the read-only side.

What contributors do in the app

Five core workflows. The app exists to make each of them fast.

1. Verify a known fact

The most common workflow. A contributor receives a notification ("Flying Iberia tomorrow from Madrid. Verify three things during your trip?") or opens the app and gets a list of suggested verifications based on their travel history and recent flights.

Each verification is a swipeable card:

  • The fact ("Iberia Economy carry-on: 56 × 40 × 25 cm, 10 kg max")
  • The last-verified date and verifier count
  • Three buttons: "Still accurate" / "Different now" / "Skip"

"Still accurate" submits a verification record (no edit needed; just confirms). "Different now" opens an inline edit form. "Skip" moves to the next card.

Each verification takes under a minute. The cards are batched so contributors can do five before boarding.

2. Submit a new edit

When existing data is wrong or missing. The contributor opens the airline or airport, taps "Edit" next to any field, and fills the structured form.

The form enforces the schema. Required fields are required. Source URLs or source photos are required. The submitter can save a draft and submit later (drafts sync to the cloud).

After submission, the edit goes to the moderation queue. The contributor sees its status in their personal "My edits" view.

3. Upload a sizer photo

Tap to take a photo of an airline's gate sizer, with the contributor's bag in it for context. The app stamps the photo with timestamp, geolocation (rounded to airport precision, not exact GPS), and the airline/airport tags.

Photos go to Cloudflare R2, get processed (orientation, EXIF strip, sizes for thumbnails), and attach to the relevant BaggageRule entity after moderation approves.

4. Log a contact attempt

A contributor calls an airline. After hanging up, they tap "Log this call" and answer three questions:

  • Did you reach a human? (yes / no / IVR maze)
  • How long did you wait? (minutes)
  • Was your issue resolved? (yes / partially / no)

These responses feed the success_rate and typical_wait_minutes fields on ContactMethod. The data is anonymous; only the aggregate is shown publicly.

5. Resolve a dispute

When two contributors have submitted conflicting data, the dispute appears in trusted contributors' queues. The card shows both values, both sources, and lets the trusted contributor vote for one, the other, or "needs more evidence."

A simple majority of trusted contributors resolves the dispute. The core team intervenes only when consensus cannot be reached.

Home screen

When a contributor opens the app, they see:

  • Header: Their display name, reputation score, current trust tier, and a streak counter (consecutive days with activity).
  • Today's queue: Up to 5 contextually-relevant tasks based on the contributor's upcoming flights, home airport, and recently-flown airlines. Each card is swipeable.
  • Recent badges: Last 3 badges earned, with a "View all" link.
  • My edits: Status of recent submissions (pending, approved, rejected).
  • Activity feed: Other contributors' recent approved edits, scoped to airlines/airports the user has visited.

The feed is a passive surface. It is not endless; it shows the last 50 events and stops. The app does not optimize for engagement time. The goal is for a contributor to spend 60 seconds, complete a task, and close the app.

Flight import and verification queue

The killer feature.

When a contributor pastes a flight itinerary, forwards a confirmation email to bookings@contribute.flighthelp.net, or connects their email via Gmail OAuth (optional), the app extracts:

  • Airline (operating + marketing)
  • Route
  • Date
  • Fare class (when available)

The day before the flight, the app sends a push notification: "Flying Iberia tomorrow from Madrid. Want to verify 3 things during your trip?"

The verification list is contextual: the bag sizer (since the contributor will be at the gate), the published phone number (the contributor can call from the lounge), the seat pitch in the cabin they're in. Three to five tasks, each under a minute.

Offline-first. The contributor can take photos and answer questions on the jetway with no signal; submissions queue locally and sync when they're back on wifi.

Reputation visible

The contributor's reputation score is visible on the home screen. Tapping it opens a breakdown:

  • Approved edits: +X reputation
  • Verifications: +X
  • Photos accepted: +X
  • Rejected edits: -X
  • Trust tier progress: "X edits until 'Trusted'"

Reputation is updated nightly. Increases are shown as small animations the next time the contributor opens the app. The animations are tasteful — no confetti, no banners, no gamified noise. Recognition without manipulation.

Badges

The badges screen shows earned and unearned badges. Each badge has:

  • Name and description
  • Rarity (common / uncommon / rare / legendary)
  • Progress toward unearned badges (e.g., "Verified at 50 airports: 32/50")
  • Date earned (for owned badges)

Unearned badges are visible but greyed out, with their criteria shown. This creates aspirational goals without being pushy.

Offline mode

The PWA caches:

  • The contributor's home airport data
  • The contributor's most-flown airlines
  • Recent verification tasks
  • Pending submissions

A contributor at an airport with no signal can:

  • See their verification queue
  • Take photos and queue them
  • Answer fact-checks
  • View previously-cached pages

When connectivity returns, submissions sync automatically. Conflicts are rare (the same contributor rarely conflicts with themselves) and are surfaced for resolution.

Onboarding

Five steps, each takes under 30 seconds:

  1. Sign up. Email-only, magic link. No password. (Auth.js / NextAuth v5.)
  2. Pick a display name. Pseudonyms welcome. Profanity-filtered.
  3. State your home airport. Optional but used for task prioritization.
  4. State your languages. Helps with translation tasks.
  5. Optional: state credentials. Cabin crew, frequent flyer, lawyer, gate agent. Credentials can be verified later (peer vouch, ID check, or employer verification) and become a badge.

After onboarding, the user is given three tutorial tasks:

  • Verify one fact on their most-flown airline.
  • Add one missing data point about their home airport.
  • Translate one sentence into a language they speak.

Completing all three earns the "First Steps" badge.

Notifications

Conservative. Only when there's something useful to surface.

  • The day before a known flight: "Verify 3 things during your trip?"
  • After a flight: "How did your Iberia flight go? Anything to log?"
  • When a submission is approved: "Your edit on Lufthansa was published."
  • When a badge is earned: "You earned 'Verified 50 airports.'"
  • Weekly (Sunday): "5 verifications need your help this week" (only if the user has been active recently).

Users can opt out of any notification category. The default is opt-in for "submission status" and "earned badges" and opt-out for everything else.

Privacy

The app collects:

  • Contributor email (for auth)
  • Display name
  • Self-reported home airport, languages, airlines flown, airports visited
  • Submission history
  • Verification history
  • Contact-call logs (anonymous aggregates)
  • Photo metadata (timestamp, airport-level location, EXIF-stripped)

The app does not collect:

  • Precise GPS (location is rounded to airport precision)
  • Device fingerprints used outside the moderation system
  • Browsing history beyond the app
  • Anything cross-site

Contributors can export their data and delete their account at any time. Deletion removes the contributor's profile, edits remain in the public dataset (attributed to a generic "Former Contributor") because the data belongs to the public.

Technology

Separate Next.js app in the flighthelp/web monorepo at apps/contribute/. Shares the design system and data client with the consumer site but has its own bundle.

  • Auth: Auth.js (NextAuth v5) with magic-link only.
  • Storage for offline: IndexedDB via Dexie.
  • Push notifications: Web Push API.
  • Camera: getUserMedia for sizer photos.
  • Sync: Background Sync API for queued submissions.

See TECH-STACK.md for the full stack.