FNN Dev ยท Internal Documentation

TripDataHub

An iOS app that turns a CrewAccess schedule PDF into a timezone-correct duty chronology for pilots. This is the internal reference covering the product, its architecture, current state, and roadmap.

Version 1.2.1 (build 68) iOS 17.0+ ยท iPhone / iPad As of 2026-06-13

1Overview

What it is ยท why it exists ยท who it's for ยท core features

What it is

TripDataHub is an iOS app (formerly "BidProSchedule"; bundle ID still com.sfune.BidProSchedule) that gives airline/cargo pilots a timezone-aware view of their crew duty schedule. The pilot exports a schedule PDF from CrewAccess, shares it into the app via the iOS Share Sheet, and the app parses, stores, and renders it as a duty chronology (Timeline) and an 8-week Bid Period calendar grid (iPad).

Positioning (important)

The app is not affiliated with UPS, any airline, employer, union, or schedule provider, and never connects directly to airline systems. All import is manual and user-initiated. It's a personal utility layered on data the pilot already has legitimate access to โ€” not a scraper, not an alternative scheduling system, not a system of record.

Why it exists

CrewAccess presents schedules as PDFs with raw UTC and local times mixed together โ€” no easy chronological "what do my next two weeks look like" view, no countdown to the next flight, no way to see a colleague's schedule. TripDataHub turns that PDF into:

Target users

Core features

Status

2Architecture

Build targets ยท data flow ยท storage ยท CloudKit ยท invariants

Build targets

All targets are generated from project.yml via XcodeGen.

Source layout (TripDataHub/)

Models/

Centered on TripModels.swift (PayPeriodSchedule, TripLeg, OpenTimeTrip, FriendConnection), plus CalendarModels, FlightCountdownSupport, FriendScheduleMatching, ProfileModels / ProfileSnapshot, DeviceScheduleModels, RosterParsingModels.

Services/ โ€” logic, parsing, sync

ViewModels / Views / app entry

Data flow โ‘  โ€” import pipeline

  1. User shares a PDF โ†’ share extension accepts public.pdf, copies the file + manifest JSON into the App Group container, and deep-links into the main app.
  2. AppGroupImportHandoff reads the manifest/PDF.
  3. CrewAccessPDFImportService (PDFKit) extracts text; PDFTripParser parses line-by-line into trip/duty/leg/hotel/crew JSON.
  4. CrewAccessTripSummaryStore writes the JSON to Documents/CrewAccessImports/{date}_{tripId}.json โ€” this local JSON is the source of truth (INV-006).
  5. On startup, reconcileCrewAccessSchedulesWithImportFiles() rebuilds in-memory state from these files.
  6. CloudKit sync (below) mirrors both the raw import files and the parsed snapshot for cross-device availability.

Data flow โ‘ก โ€” Timeline & Calendar rendering

Storage

External services

CloudKit

Container iCloud.com.sfune.TimelineSchedule, Public Database only (no private DB, no CKShare). See docs/ADR/ADR-001-public-cloudkit-phase1.md.

Record typeRole
TDHGEMSVerificationAdmin-written GEMS ID โ†” DOB-hash verification table (read by all users).
TDHVerifiedUserCreated on first successful GEMS verification.
TDHFriendLinkPairing record for two mutually-approved users.
TDHSharedScheduleA user's parsed schedule exposed read-only to friends.
TripScheduleSnapshotWeb-friendly serialized schedule (consumed by an external viewer).
TDHDeviceScheduleSnapshotOne per user; device-to-device sync (local-wins).
TDHCrewAccessImportFileOne per imported trip; raw JSON sync with tombstone deletes.

Synchronization

Operational risk

CloudKit Development vs Production schema drift is a recurring cause of friend-sharing bugs. New record types/fields must be manually deployed to Production before TestFlight/App Store builds will work (see docs/CLOUDKIT.md).

Countdown / Live Activity

The widget extension reads shared schedule data via the App Group. The Home Screen Widget covers T-12hโ†’T-6h; the Live Activity (iOS 16.1+) covers T-6hโ†’T+6h on Lock Screen / Dynamic Island, switching to "Delayed" after STD if the flight hasn't departed. Coordinated by FlightCountdownCoordinator / FlightCountdownSupport.

Invariants

Load-bearing rules every change must respect. Full text in docs/INVARIANTS.md.

IDRule
INV-001UTC is the source of truth for all internal calculations; Calendar.current/TimeZone.current are forbidden.
INV-002All timezone conversions are explicit (formatters/calendars set timeZone explicitly).
INV-003Bid/Pay Period membership uses the 03:00 LDT (local domicile time) boundary, not UTC midnight.
INV-004Domicile (ANC, SDF, ONT, MIA; SDFZ normalized to SDF) controls the timezone for LDT conversions.
INV-005iOS and iPad keep UI/feature parity for shared concepts (Timeline rows, layover cards).
INV-006On-disk import JSON is the source of truth; CloudKit is a redundant sync layer.
INV-007CloudKit device sync is local-wins.
INV-008Cross-device deletes use tombstones, not hard deletes.
INV-009Calendar day indices are computed in UTC, not local startOfDay.
INV-010Calendar layers are strictly Operational > Bid > Personal; operational events never appear in Bid/Personal, personal events never in Operational/Timeline.
INV-011Timeline = Trips + Flights + Deadheads + manual Operational events only (excludes Bid/Personal).
To verify (TODO from source)

docs/ADR/*, docs/CLOUDKIT.md, docs/BID_PERIODS.md, docs/TERMINOLOGY.md were referenced but not read in full. Consult them directly for schema field lists and worked timezone examples.

3Current State

Version ยท production features ยท focus ยท watchOS ยท tech debt ยท tests

Current version

On the v2.x tags

v2.0โ€“v2.3 (Febโ€“Apr 2026) are older pre-1.0 legacy tags from before the rename to TripDataHub and the switch to 1.x versioning (the 1.0.0 rename was 2026-03-16). They do not represent newer versions than 1.2.1 โ€” ignore them for "current version" purposes.

To verify (TODO from source)

CHANGELOG.md / RELEASE_NOTES.md stop at v1.0.0 (2026-03-16); v1.0.1โ€“v1.2.1 are undocumented (only a v1.1 draft exists). Accurate notes would need reconstructing from git log. Also, build 68's App Store Connect status (Live / In Review / TestFlight only) can't be determined from the repo.

Production features

Recent focus

The last ~12 commits (2026-05 to 06-13) center on Friend Sharing / Profile CloudKit sync reliability: friend timeline sync fixes, request sync recovery/restore, link-permission fallbacks, notify-on-match, preserve-request-on-account-delete. The 2026-06-10 "sync profiles and refresh demo data" change and the v1.2.0/v1.2.1 releases (build 67/68) are the stabilization and release wrap-up of that work.

Several claude/* and feature/* branches exist, but feature/statistics, refactor/consolidate-dedup-layers, etc. are fully merged history โ€” not active work (the exception is watchOS, below). The working tree also has some stale worktrees and untracked files (docs/SIMULATOR_TROUBLESHOOTING.md, TDH-icon-1024.png).

watchOS support DEFERRED

Complete and validated, but not yet integrated into main.

For anyone touching this

Don't assume watchOS exists in main โ€” there's no watch target or related files in the working tree. But don't assume it was abandoned โ€” a complete, validated, tested implementation lives on feature/watchos; it was deferred on priority, not cancelled. If watch work is requested, review feature/watchos first. Canonical record: ~/Documents/FNN-Obsidian/20_Projects/TripDataHub/releases/Deferred_Features.md.

What the investigation found

What's on the branch (for reference)

Reviving it means rebasing/merging feature/watchos onto current main, resolving ~3 weeks of drift (Friend Sharing and domicile model/service changes landed since b1cf1ff), then re-validating against the branch's checklist.

Known tech debt

Next work

No forward-looking roadmap doc exists beyond the Roadmap section. The clearest signal is that Friend Sharing / Profile sync just reached a stable release point (v1.2.1 / build 68). Absent a new sync bug, focus is likely to shift toward roadmap items (web timeline viewer, additional countdown variants, Calendar V2).

Test coverage

Unit tests cover: countdown phases/duration/leg selection; calendar day-index, BP/PP membership, DST edge cases; PDF parser regression (golden JSON); device-sync local-wins; LogTen export format; import-file CloudKit sync; GEMS verification sync (incl. the domicile/schemaVersion: 2 field added in build 32+); device snapshot sync; import handoff; profile sync; friend request matching; snapshot encoding; App Group handoff; next-report window calculation. Plus a separate UI test target (TripDataHubUITests).

4Roadmap

Planned (scoped/in progress) ยท Proposed (future per specs) ยท Ideas (loose)

Source

Derived from CALENDAR_IMPLEMENTATION_SPEC.md, docs/RELEASE_NOTES_v1.1_DRAFT.md, AGENTS.md, code TODOs, and commit history.

Plannedscoped / in progress

  • Continue hardening Friend Sharing / Profile CloudKit sync (request matching, restore-after-account-delete, permission fallbacks, stale-notification fixes).
  • Maintain CloudKit Dev/Prod schema parity for any new record types or fields before release.
  • Continue timezone/DST regression coverage as new domiciles or Bid Period tables are added.

Proposedfuture per specs / out of V1 scope

From Calendar V2 (V1 non-goals):

  • Fatigue overlays on the calendar.
  • Trip editing UI (calendar/timeline are read-only today).
  • Drag-and-drop rescheduling.
  • Colleague/friend calendar overlays (beyond the current read-only friend timeline).
  • Real-time operational / flight-status tracking.
  • Month view (vs. the current 8-week grid).

From the v1.1 notes draft / AGENTS.md:

  • Geopolitical warning engine ("later phase").
  • Additional countdown variants โ€” Van Time, Report Time, "next operational event" (not just next flight).
  • Web timeline viewer โ€” an external consumer of TripScheduleSnapshot (the encoder side already exists).

Ideasloose / unscoped

  • Remove the unused sharedTimelineCards field once the web viewer consumes snapshots directly ("Phase B+").
  • Add domiciles beyond ANC/SDF(Z)/ONT/MIA โ€” requires updates to DomicileSupport, docs/BID_PERIODS.md, BidPeriodServiceTests, and the date table.
  • Update README to reflect current TripDataHub branding/features (still framed as BidProSchedule).
To verify (TODO from source)

Check open issues/PRs on github.com/Tony747-G/TripDataHub and docs/AI_CONTEXT_INDEX.md for a more authoritative, current roadmap than what's inferable from specs and commit history.