FNN Dev · 社内ドキュメント

TripDataHub

パイロットが CrewAccess から書き出したスケジュール PDF を、タイムゾーンを正しく扱った「乗務の時系列ビュー」に変換する iOS アプリ。本書は概要・設計・現状・ロードマップを一つにまとめた社内向け資料です。

Version 1.2.1 (build 68) iOS 17.0+ · iPhone / iPad 基準日 2026-06-13

1概要

何をするアプリか / なぜ必要か / 誰のためか / 主な機能

どんなアプリか

TripDataHub は、貨物・旅客のパイロットが自分の乗務スケジュールをタイムゾーン込みで正しく把握するための iOS アプリです(旧称 BidProSchedule、バンドル ID は今も com.sfune.BidProSchedule)。使い方はシンプルで、パイロットは社内スケジューリングシステム CrewAccess からスケジュール PDF を書き出し、iOS の共有シートから本アプリに渡すだけ。あとはアプリが PDF を解析・保存し、乗務の時系列ビュー(Timeline)と、iPad では 8 週間の Bid Period カレンダーとして表示します。

立ち位置(重要)

本アプリは UPS・航空会社・雇用主・労働組合・スケジュール提供元のいずれとも無関係で、航空会社のシステムに直接つなぐこともしません。データの取り込みは すべて手動・ユーザー起点 です。スクレイパーでも、代替スケジューリングシステムでも、記録の正本(system of record)でもありません。あくまでパイロットが正規にアクセスできるデータの上に重ねる、個人用のユーティリティです。

解決する課題

CrewAccess が出すスケジュールは PDF で、UTC とローカル時刻が混在した生の形式です。そのため「これからの 2 週間が実際どうなるのか」を時系列で一覧する手段がなく、次のフライトまでのカウントダウンもなければ、同僚の予定を見る方法もありません。TripDataHub はこの PDF を、次の 4 つに変換します。

対象ユーザー

主な機能

現在のステータス

2アーキテクチャ

ビルド構成 / データの流れ / 保存先 / CloudKit / 守るべき不変条件

ビルドターゲット

すべて project.yml から XcodeGen で生成しています。

ソース構成(TripDataHub/

Models/ — データ型

TripModels.swift(PayPeriodSchedule / TripLeg / OpenTimeTrip / FriendConnection)を中心に、CalendarModelsFlightCountdownSupportFriendScheduleMatchingProfileModels / ProfileSnapshotDeviceScheduleModelsRosterParsingModels などが並びます。

Services/ — 業務ロジック・解析・同期

ViewModels/ ・ Views/ ・ その他

データの流れ ① 取り込みパイプライン

  1. ユーザーが PDF を共有 → 共有拡張public.pdf を受け取り、ファイルとマニフェスト JSON を App Group コンテナ にコピーし、本体アプリへディープリンク。
  2. 本体の AppGroupImportHandoff がマニフェストと PDF を読み込む。
  3. CrewAccessPDFImportService(PDFKit)でテキスト抽出 → PDFTripParser が行単位でトリップ・勤務・レグ・ホテル・クルーの JSON に変換。
  4. CrewAccessTripSummaryStore が JSON を Documents/CrewAccessImports/{date}_{tripId}.json に保存。このローカル JSON が正本(INV-006)
  5. 起動時に reconcileCrewAccessSchedulesWithImportFiles() がファイル群からメモリ上の状態を再構築。
  6. CloudKit 同期(後述)が、生の取り込みファイルと解析済みスナップショットの両方をミラーし、複数端末で利用可能に。

データの流れ ② Timeline / Calendar の描画

保存先

外部サービス

CloudKit の使い方

コンテナは iCloud.com.sfune.TimelineSchedulePublic Database のみ(プライベート DB・CKShare は不使用)。背景は docs/ADR/ADR-001-public-cloudkit-phase1.md を参照。

レコード型役割
TDHGEMSVerification管理者が書き込む GEMS ID ↔ 生年月日ハッシュの照合表(全ユーザーが読み取り)。
TDHVerifiedUserGEMS 認証に初めて成功したときにユーザーが作成。
TDHFriendLink相互承認した 2 ユーザーのペアリング記録。
TDHSharedSchedule友人に読み取り専用で公開する、解析済みスケジュール。
TripScheduleSnapshotWeb ビューア向けにシリアライズしたスケジュール。
TDHDeviceScheduleSnapshotユーザーごとに 1 件。端末間同期用(local-wins)。
TDHCrewAccessImportFile取り込みトリップごとに 1 件。生 JSON の同期、削除はトゥームストーン。

同期の設計

運用上の注意点

CloudKit の Development 環境と Production 環境のスキーマずれが、フレンド共有まわりの不具合の 常連の原因 です。新しいレコード型やフィールドは、TestFlight / App Store ビルドで動く前に Production へ手動デプロイ しておく必要があります(docs/CLOUDKIT.md)。

カウントダウン / ライブアクティビティ

ウィジェット拡張は App Group 経由で共有スケジュールを読み取ります。ホーム画面ウィジェットは T-12h〜T-6h、ライブアクティビティ(iOS 16.1+)は T-6h〜T+6h をロック画面・ダイナミックアイランドで表示し、STD を過ぎても未出発なら「Delayed」に切り替わります。制御は FlightCountdownCoordinator / FlightCountdownSupport

守るべき不変条件(Invariants)

変更時に必ず守るべき土台のルールです。全文は docs/INVARIANTS.md

IDルール
INV-001内部計算の基準は常に UTC。Calendar.current / TimeZone.current は使用禁止。
INV-002タイムゾーン変換は必ず明示的に行う(フォーマッタ・カレンダーに timeZone を明示)。
INV-003Bid / Pay Period の所属判定は UTC 深夜ではなく 03:00 LDT(母基地ローカル時刻)境界で行う。
INV-004母基地(ANC / SDF / ONT / MIA。SDFZ は SDF に正規化)が LDT 変換のタイムゾーンを決める。
INV-005共通概念(Timeline 行、レイオーバーカード)は iPhone / iPad で UI・機能を揃える。
INV-006ディスク上の取り込み JSON が正本。CloudKit は冗長な同期層にすぎない。
INV-007端末間同期は local-wins。
INV-008端末間の削除はハード削除でなくトゥームストーンで行う。
INV-009カレンダーの日付インデックスはローカル startOfDay でなく UTC で計算。
INV-010カレンダーのレイヤーは厳密に「運用 > Bid > 個人」。運用イベントは Bid / 個人に現れず、個人イベントは運用 / Timeline に現れない。
INV-011Timeline は「トリップ + フライト + デッドヘッド + 手動運用イベント」のみ(Bid / 個人レイヤーは除外)。
要確認(原資料の TODO)

docs/ADR/* / docs/CLOUDKIT.md / docs/BID_PERIODS.md / docs/TERMINOLOGY.md は参照のみで全文未確認。スキーマのフィールド一覧やタイムゾーンの具体例は、これらを直接参照してください。

3現状

現行バージョン / 本番機能 / 開発の重心 / watchOS / 技術的負債 / テスト

現行バージョン

v2.x タグに注意

v2.0v2.3(2026 年 2〜4 月)は、BidProSchedule から TripDataHub への改名・1.x 採番への移行より の古いレガシータグです(1.0.0 への改名は 2026-03-16)。1.2.1 より新しいわけでは なく、現行バージョンとしては無視してください。

要確認(原資料の TODO)

CHANGELOG.md / RELEASE_NOTES.md は v1.0.0(2026-03-16)止まりで、v1.0.1〜v1.2.1 は未更新(v1.1 のみドラフトあり)。正確なリリースノートが要る場合は git log から再構築が必要。また build 68 の App Store Connect 上のステータス(公開中 / 審査中 / TestFlight のみ)はリポジトリからは判別できません。

本番に載っている機能

最近の開発の重心

直近 12 コミットほど(2026-05〜06-13)は フレンド共有 / プロフィールの CloudKit 同期の信頼性向上 に集中しています。具体的には、友人タイムライン同期の修正、友人リクエストの同期リカバリと復元、リンク権限のフォールバック、マッチ時通知、アカウント削除時のリクエスト保持など。2026-06-10 の「プロフィール同期とデモデータの刷新」と、v1.2.0 / v1.2.1(build 67 / 68)が、この一連の作業の安定化・リリースの締めにあたります。

git 上には claude/*feature/* ブランチが複数ありますが、feature/statisticsrefactor/consolidate-dedup-layers 等は main に取り込み済みの完了履歴で、現在進行中の作業ではありません(例外は次の watchOS)。ほかに、マージ済みブランチに対応する古いワークツリーや、未追跡の docs/SIMULATOR_TROUBLESHOOTING.md / TDH-icon-1024.png が作業ツリーに残っています。

watchOS 対応 保留中

完成・検証済みだが、まだ main には統合されていない状態です。

今後この件を触る人へ

「main に watchOS 対応がある」と思い込まないこと。 現在の作業ツリーには watch ターゲットも関連ファイルも存在しません。一方で 「放棄された」とも思い込まないこと。 完成・検証・テスト済みの実装が feature/watchos に残っています(優先順位の都合で保留にしただけ)。watch 作業が必要になったら、新規実装の前にまず feature/watchos を確認してください。正式な記録は ~/Documents/FNN-Obsidian/20_Projects/TripDataHub/releases/Deferred_Features.md

調べて分かったこと

ブランチ側の内容(参考)

復活させるには、feature/watchos を現在の main にリベース/マージし、約 3 週間ぶんのずれ(分岐後に入ったフレンド共有・母基地まわりのモデル/サービス変更を含む)を解消したうえで、ブランチ内の検証チェックリストに沿って再検証する必要があります。

既知の技術的負債

次の作業

ロードマップ以上の明確な将来計画ドキュメントはありません。最も具体的な兆候は、フレンド共有 / プロフィール同期が安定リリース点(v1.2.1 / build 68)に到達したこと。新たな同期不具合が出ない限り、次の重心はロードマップ側の項目(Web タイムラインビューアの実装、カウントダウンの種類追加、Calendar V2 項目)へ移ると見られます。

テストの状況

ユニットテストは次をカバー:カウントダウンのフェーズ/時間/レグ選択、カレンダーの日付インデックス・BP/PP 所属・DST のエッジケース、PDF パーサのリグレッション(ゴールデン JSON)、端末同期の local-wins 挙動、LogTen エクスポート形式、取り込みファイルの CloudKit 同期、GEMS 認証同期(build 32+ で追加の domicile / schemaVersion: 2 を含む)、端末スナップショット同期、取り込み受け渡し、プロフィール同期、友人リクエスト照合、スナップショット符号化、App Group 受け渡し、次レポート時刻の計算。加えて UI テストターゲット(TripDataHubUITests)あり。

4ロードマップ

Planned(着手・確定済み)/ Proposed(仕様上の将来項目)/ Ideas(緩い言及)

出典

CALENDAR_IMPLEMENTATION_SPEC.md / docs/RELEASE_NOTES_v1.1_DRAFT.md / AGENTS.md / コード内 TODO / コミット履歴から整理したもの。

Planned着手・確定済み

  • フレンド共有 / プロフィールの CloudKit 同期 の継続的なハードニング(リクエスト照合、アカウント削除後の復元、権限フォールバック、古い通知の修正)。
  • 新しいレコード型・フィールドについて、リリース前に Dev / Prod のスキーマ整合を保つ運用。
  • 母基地や Bid Period 表を追加した際の、タイムゾーン / DST リグレッションの拡充。

Proposed仕様上の将来項目 / V1 では非対応

Calendar V2(V1 の非ゴール)より:

  • カレンダーへの疲労オーバーレイ。
  • トリップ編集 UI(現状はカレンダー・タイムラインとも読み取り専用)。
  • ドラッグ&ドロップでの再スケジュール。
  • 同僚カレンダーの重ね合わせ(現状の読み取り専用フレンドタイムラインの先)。
  • リアルタイムの運用 / フライトステータス追跡。
  • 月表示(現状の 8 週間グリッドに対して)。

リリースノート v1.1 ドラフト / AGENTS.md より:

  • 地政学的な警告エンジン(「later phase」)。
  • カウントダウンの種類追加 — Van Time、Report Time、「次の運用イベント」(フライトに限らない)。
  • Web タイムラインビューア — TripScheduleSnapshot を消費する外部ビューア(書き出し側 TripScheduleSnapshotEncoder は既にある)。

Ideas緩い言及・未スコープ

  • Web ビューアがスナップショットを直接消費するようになったら、未使用の sharedTimelineCards を削除(「Phase B 以降で削除予定」)。
  • ANC / SDF(Z) / ONT / MIA 以外の母基地追加 — DomicileSupportdocs/BID_PERIODS.mdBidPeriodServiceTests・日付表の更新が必要。
  • README を現在の TripDataHub のブランディング・機能に合わせて更新(今は旧 BidProSchedule のまま)。
要確認(原資料の TODO)

github.com/Tony747-G/TripDataHub の未解決 Issue / PR と、docs/AI_CONTEXT_INDEX.md を確認すること。仕様とコミット履歴からの推測より、権威があり最新のロードマップが得られる可能性があります。