Work Time Recorder — システム概要

対象: IT部門・インフラ担当 作成日: 2026-04-15 機密: クライアント社内限り
1バックエンドアーキテクチャ図

主要処理フローの通信シーケンスを表示。タブで切り替えてください。

関連するLambda・データストア・外部連携を機能クラスタ別に表示。各クラスタをクリックすると詳細が展開されます。

GraphQL呼び出し クリックで詳細展開 React Native App Expo Router / iOS GraphQL + Firebase IDトークン AWS AppSync — GraphQL API ゲートウェイ 全リクエスト認証: appsyncAuth Lambda Authorizer(DynamoDBセッション検証) 認証 / セッション 3関数 3連携 LAMBDA 関数 appsyncAuth ServiceNowSSOLoginLambda setActiveSessionLambda 連携先 Microsoft Azure AD Firebase Auth DynamoDB: ActiveSessions 打刻 / BTP 4関数 4連携 LAMBDA 関数 BTPSSOLambda SSORefreshToken BTPTokenRefresherLambda SSOBTPIASLambda 連携先 SAP BTP (OData 打刻API) SAP IAS (OAuth 2.0) DynamoDB: SSOBTPToken EventBridge (30分毎起動) タスク / ServiceNow 8関数 2連携 LAMBDA 関数 ServiceNowLambda PMLambda PMSalesforceLambda ServiceNowUpdateStatusLambda ServiceNowMetricInstanceLambda UpdateMetricTimeLambda SNOAuthCallbackLambda SNOAuthRefreshLambda 連携先 ServiceNow (REST API) Salesforce (SOAP API) データ / 残業 5関数 5テーブル LAMBDA 関数 OTupdaterLambda CompanyConfigLambda PersonalConfigDB Lambda dailyActivityLogSaver pageViewTrackingLambda DYNAMODB テーブル OvertimeSummary dailyActivityLog PersonalConfigDB ActivityLog PageViewTracking

    ※ DynamoDBは単一インスタンスに7テーブル。うち ActiveSessions は認証クラスタ、SSOBTPToken は打刻クラスタ、残り5テーブルはデータ/残業クラスタが管理します。
    2主要データフロー
    1
    アプリ → Microsoft Azure AD(SSOログイン画面を開く)
    sessionId(UUID)を生成しOAuth stateパラメータとして渡す。prompt=select_accountで共有デバイスにも対応。
    2
    バックグラウンドポーリング(最大180回 × 1.5秒間隔)で認証完了を待機
    Microsoft → ServiceNowOAuthCallbackLambda → DynamoDBにトークンを一時保存。
    3
    ServiceNowSSOLoginLambda → Microsoft Graph APIでユーザー情報取得
    4
    Lambda → Firebase Auth(カスタムトークン発行)
    5
    アプリ → Firebase signInWithCustomToken → IDトークン取得
    6
    アプリ → setActiveSessionLambda(DynamoDB ActiveSessionsにセッション登録)
    1デバイス1セッション制御。別デバイスからのログインを自動検知・強制ログアウト。
    7
    以降すべてのGraphQLリクエストはappsyncAuthで認証(60秒グレースウィンドウ)
    Firebase IDトークン検証 + DynamoDBセッション一致確認。不一致は即時拒否。
    1
    アプリ → AWS AppSync(GraphQL mutation: createTimeRecorderSSO)
    2
    AppSync → appsyncAuth Lambda(認証検査)
    Firebaseトークン検証 + セッションID一致確認。失敗時は GraphQL Unauthorized エラーを返却。
    3
    AppSync → BTPSSOLambda(打刻処理エンジン)
    4
    BTPSSOLambda → DynamoDB SSOBTPToken(ユーザーのBTPアクセストークン読み取り)
    5
    BTPSSOLambda → SAP BTP OData API(打刻レコード送信)
    001=出勤、011=直行出勤、002=退勤、012=直帰退勤。HimatagiFlg=1で日またぎ対応。
    6
    レスポンス → アプリ(打刻完了表示)
    7
    ※トークン期限切れ時: BTPSSOLambda → SSORefreshToken → SAP IAS → 新トークン取得 → 自動リトライ
    分散ロック+ランダムジッターで同時リフレッシュ(サンダーリング・ハード)を防止。
    1
    アプリ → AWS AppSync(GraphQL query: getServiceNowTasks)
    2
    AppSync → appsyncAuth(認証検査)
    3
    AppSync → ServiceNowLambda
    4
    ServiceNowLambda → Salesforce SOAP API(認証セッション取得)
    セッションは90分間キャッシュ。有効期限内は再認証不要。
    5
    ServiceNowLambda → ServiceNow REST API(u_work_taskテーブルからタスク一覧取得)
    OAuth 2.0認証(SN_CLIENT_ID/CLIENT_SECRET)。state: 1=未着手, 2=対応中, 3=完了, -5=保留。
    6
    レスポンス → アプリ(受信トレイ表示)
    1
    Amazon EventBridge(30分毎にスケジュールトリガー)
    2
    → BTPTokenRefresherLambda 起動
    3
    → DynamoDB SSOBTPTokenテーブルをスキャン
    60分以内に期限切れの USER_* トークンを検出。バッチ上限200トークン/回。
    4
    → 各トークンを SAP IAS refresh_token grant で更新
    5
    → DynamoDB に新トークンを保存
    100msペーシングで過負荷を防止。無効なrefresh_tokenは自動削除。
    6
    効果: 月曜朝の出勤打刻時にトークン一斉期限切れが起きない
    週末の非稼働時間でもプロアクティブに更新することで、月曜朝の打刻失敗リスクをゼロにする。
    3テスト概要
    層 1 — ユニット・統合テスト(Jest)
    ツールJest(Meta、オープンソース、無償) 規模62スイート / 1,247テスト 実行時間〜3秒
    残業計算(日次・月次・年次の集計、端数処理)
    トークン処理(BTP / Firebase認証トークンの検証・更新・有効期限)
    セッション管理(打刻セッションの開始・終了・日またぎ補正)
    データフォーマット(時刻変換、ServiceNowフィールドマッピング)
    GraphQLクエリ(AppSyncクエリ・ミューテーション構造の検証)
    コンテキスト配線(全14プロバイダーの正しい接続を保証)
    層 2 — E2Eデバイステスト(Maestro)
    ツールMaestro(オープンソース、無償) 規模18フロー 実行環境iOSシミュレーター
    SSOログイン → 待機画面
    出勤打刻 → メイン画面
    タスク開始(受信トレイ → スワイプ)
    タスク切替・中断・再開
    退勤打刻
    残業カウンター表示
    アプリ強制終了 → 再起動(データ永続性確認)
    その他11フロー(お気に入り、学習、コラボレーション 等)
    層 3 — 大規模負荷テスト(k6)
    ツールk6(Grafana、オープンソース、無償) 規模1,200ユーザー同時接続 テスト時間25分間
    パート1: Lambda認証レイヤー(✅ 完了 — p95 103ms)
    パート2: DynamoDB 読み込み(✅ 完了 — p95 280ms)
    パート3: DynamoDB 書き込み(✅ 完了 — p95 524ms)
    パート4: ServiceNow・Salesforce連携(✅ 完了 — p95 276ms)
    4負荷テスト状況
    パート 1 — Lambda認証レイヤー ✅ 完了 2026-04-14
    指標結果目標値
    レスポンスタイム(p95)103ms3,000ms以下
    Lambdaスロットル0件0件
    ピーク同時接続数1,200 / 1,200人1,200人
    総リクエスト数214,014件
    パート 2 — DynamoDB 読み込み ✅ 完了 2026-04-15
    指標結果目標値
    残業サマリー取得(p95)280ms3,000ms以下
    エラー率0.00%1%未満
    Lambdaスロットル0件0件
    パート 3 — DynamoDB 書き込み ✅ 完了 2026-04-15
    指標結果目標値
    打刻書き込み(p95)524ms3,000ms以下
    エラー率0.00%1%未満
    Lambdaスロットル0件0件
    パート 4 — ServiceNow・Salesforce連携 ✅ 完了 2026-04-15
    指標結果目標値
    タスク取得(p95)276ms3,000ms以下
    エラー率0.00%1%未満
    Lambdaスロットル0件0件
    テスト実施: 2026-04-15(ユーザー利用なし)。総リクエスト数: 330,568件、テスト時間: 25分間。全4パート合格。
    5Ad Hoc デバイステスト

    ビルド・配布プロセス

    アーカイブ方法Xcode 手動アーカイブ(方法B)
    署名Ad Hoc プロビジョニングプロファイル
    出力IPAファイルをエクスポート
    配布テストデバイスに直接インストール

    プロビジョニング情報

    プロファイル名WTR-Internal-Adhoc-Testing
    Bundle IDcom.benben0505.Project01App20250531
    有効期限2026年10月27日
    登録デバイス数26台(上限100台 / 年)

    OTA アップデートチャンネル

    internal
    内部開発テスト用
    開発チームのみ。最新ビルドを随時配信。
    preview
    クライアントテスト用
    Ad Hoc IPAインストール済みデバイスへ配信。
    OTA更新はEAS Update経由で配信。アプリ起動時に自動チェック・ダウンロード。ネイティブコード変更がない限りストア再申請不要。

    将来計画

    配布方式Apple Business Manager + カスタムアプリ配信
    メリットUDID登録制限なし(本番展開対応)
    対象全社員への展開
    6外部システム連携設定 — ServiceNow / Salesforce / SAP BTP

    アプリは3つの外部エンタープライズシステムと連携しています。タブで各システムの認証設定・API・Lambda構成・トラブル対処を確認できます。

    役割
    タスク一覧の取得・状態更新・作業時間(metric_instance)の管理。Flow Designer 経由でテーブルを更新。
    認証 — OAuth 2.0 Client Credentials
    項目値 / 説明
    OAuth アプリ名Mobile App Flow API(ServiceNow Application Registry に登録)
    Grant Typeclient_credentials
    Token エンドポイントPOST {SN_URL}/oauth_token.do
    トークン有効期限60分(Lambda 内 60秒バッファ付きキャッシュ)
    Lambda 環境変数SN_URL / SN_CLIENT_ID / SN_CLIENT_SECRET(全5 Lambda に設定)
    使用 Lambda・テーブル・エンドポイント
    Lambdaテーブル / エンドポイント操作
    ServiceNowLambdau_work_task担当タスク一覧取得(最大1,000件)
    ServiceNowUpdateStatusLambdaFlow: workstateupdate_ejecmobileappタスク状態更新(state フィールド書き込み)
    ServiceNowMetricInstanceLambdametric_instance作業時間レコード取得(直近3日間)
    ServiceNowUpdateMetricTimeLambdaFlow: mobile_edit_workflow_time作業開始・終了時刻の更新
    PMLambdau_work_taskプロジェクト管理者向けタスク取得
    Flow Designer — 2フロー
    フロー名トリガー処理重要な注意点
    workstateupdate_ejecmobileappREST PATCH(非同期)入力: record_sys_id, stateu_work_task.state を更新⚠ スクリプトステップは必ず Global スコープ で実行。EJEC Mobile App スコープのみでは u_work_task の ACL に阻まれ .update()null を返す
    mobile_edit_workflow_timeREST PATCH(非同期)入力: metric_instance_sys_id, new_start, new_end → duration を自動計算して更新
    トラブルシューティング
    症状原因対処
    タスク取得が空 / 401OAuth トークン失効 or 環境変数未設定Lambda 環境変数を確認。CloudWatch で [ServiceNowLambda] ログ参照
    状態更新が反映されない(エラーなし)Flow のスクリプトが EJEC スコープで動作し ACL にブロックされているFlow Designer のスクリプトステップを Global スコープに変更
    Flow の入力値が空トリガーボディの変数がフローにワイヤリングされていないInput Variable に inputs.record_sys_id 等を正確にマッピング
    OAuth App の User フィールドが空ServiceNow UI では非表示のフィールドREST API で PATCH /api/now/table/oauth_entity/{sys_id}{"user":"<user_sys_id>"} を送信
    役割
    ServiceNow タスクに紐づくプロジェクト情報(顧客名・契約期間・担当者)を補完。SOAP API 経由で WorkItem__c および Bumon__c テーブルを照会。
    認証 — SOAP ユーザー名・パスワード
    項目値 / 説明
    SOAP Login URLhttps://ejec-saleforce.my.salesforce.com/services/Soap/u/59.0
    Lambda 環境変数SF_USERNAME / SF_PASSWORD(パスワード+APIセキュリティトークンを連結した文字列)
    セッション有効期限90分(Lambda モジュール変数にキャッシュ)
    REST クエリ URL{instanceUrl}/services/data/v59.0/query
    使用テーブル(SOQL)
    オブジェクトLambda用途主なフィールド
    WorkItem__cServiceNowLambdaServiceNow タスクとプロジェクト情報のクロス参照(TransferId で紐付け)WRI_TransferId__c, WRI_ProjectName__c, WRI_Gijutsusha__r.Name
    Bumon__cPMSalesforceLambda個別プロジェクト詳細(契約期間・進捗・予算状況)BMN_AccountName__c, BMN_KeiyakuKokiFromDate__c, BMN_YosanshoStatus__c
    トラブルシューティング
    症状原因対処
    SOAP ログイン失敗SF_PASSWORD にセキュリティトークンが連結されていない[設定 → セキュリティトークンのリセット] で新トークンを取得し パスワード+トークン の形式で設定
    プロジェクト情報が空WRI_TransferId__c が ServiceNow タスクと一致しないServiceNow の u_work_item_number と Salesforce TransferId を照合
    Socket hang-up / タイムアウトネットワーク不安定Lambda は最大3回・1秒間隔で自動リトライ。継続する場合は Salesforce 側の API 制限を確認
    役割
    出退勤打刻の実体。OData API 経由で SAP BTP の TimeRecorderSet に打刻レコードを送受信。SAP IAS(Identity Authentication Service)が OAuth 2.0 トークンを発行・管理。
    認証 — SAP IAS OAuth 2.0
    項目値 / 説明
    IAS テナント (test)ejec-qas-sa001.authentication.jp10.hana.ondemand.com
    OData ベース URL (test)ejec-qas-btp001-sf01-bxlbe-odata-srv.cfapps.jp10.hana.ondemand.com/odata/v4/kinmu
    Lambda 環境変数TOKEN_URL / CLIENT_ID / CLIENT_SECRET / ODATA_BASE_URL / TOKEN_TABLE_NAME
    コールバック URIhttps://{api-gateway}.execute-api.ap-northeast-1.amazonaws.com/{stage}/callback
    トークン保管先DynamoDB: SSOBTPToken — PK: USER_{email} SK: CURRENT
    Lambda 構成とトークンライフサイクル
    Lambdaトリガー役割
    SSOBTPIASLambdaAPI Gateway GET /callbackOAuth 認可コードを受け取りアクセス・リフレッシュトークンを取得。id_token から empCode とメールを抽出して DynamoDB に保存
    BTPSSOLambdaAppSync GraphQL打刻操作(001=出勤 / 002=退勤)。DynamoDB からトークン取得 → OData 送信 → 401 時に SSORefreshToken を呼び出してリトライ
    SSORefreshTokenBTPSSOLambda 呼び出し(リアクティブ)refresh_token で新アクセストークンを取得。分散ロック+ランダムジッター(0〜300秒)で同時リフレッシュを防止
    BTPTokenRefresherLambdaEventBridge rate(30分)(プロアクティブ)60分以内に失効するトークンを全ユーザー分スキャンして事前更新。朝ピーク時の一斉失効を防止
    OData 操作
    操作メソッド主なフィールド
    打刻状態取得GET /TimeRecorderSet?$expand=HistoryListEmpCd, KinmuDate, DakokuTime, DakokuKbn, HimatagiFlg, HistoryList
    出勤打刻POST /TimeRecorderSetDakokuKbn: 001(011=変形労働), TzOffsetMin: -540(JST)
    退勤打刻POST /TimeRecorderSetDakokuKbn: 002(012=変形労働), HimatagiFlg: 0/1(日またぎ)
    再認証フロー(2経路)
    経路条件ブラウザ方式動作
    Path A — シームレス前回と同じユーザーopenBrowserAsync(Safari 共有 Cookie)Microsoft / IAS セッションを再利用 → パスワード入力不要
    Path B — アカウント切替別ユーザーを検出openAuthSessionAsync + preferEphemeralSession独立 Cookie ジャー → 必ず該当ユーザーの資格情報で認証
    ⚠ この2経路設計は変更禁止(build 243 以降ロック済み)。Path A を削除すると共有デバイスで毎回パスワード入力が発生。Path B を削除すると異なるユーザーの Cookie が混入するリスクがある。
    トラブルシューティング
    症状原因対処
    打刻が 401 で失敗し続けるリフレッシュトークンも失効(約7日間未使用)アプリ内の再認証モーダルで BTP SSO フローを再実行。CloudWatch [BTPSSOLambda]REAUTH_REQUIRED を確認
    DynamoDB にトークンが存在しない初回 OAuth コールバックが未完了SSOBTPIASLambda のコールバック URL が IAS に登録されているか確認。API Gateway がステージにデプロイ済みか確認
    常に 401(エラー詳細なし)DynamoDB キーのメールアドレスに大文字・空白が混入DynamoDB で USER_{email} キーを直接確認。保存・参照の両側で trim().toLowerCase() が適用されているか検証
    OAuth コールバックが届かないAPI Gateway がステージに未デプロイAPI Gateway コンソールで [APIをデプロイ] を実行(Lambda テストは通るが本番 URL には反映されない)
    7監視体制

    本アプリの稼働状況は 3 つの手段で継続的に監視しています。それぞれ対象読者と目的が異なります。

    ① 業務活動ダッシュボード

    対象読者EJEC 管理職・人事担当
    URLactivity-dashboard-1ef.pages.dev
    更新頻度60 秒ごとに自動リロード
    目的現在のチーム稼働状況をリアルタイムで把握
    主な表示内容:
    • 現在アクティブな作業員一覧(名前・現在タスク・経過時間)
    • 日次アクティビティヒートマップ(過去30日)
    • CSV エクスポート(出勤記録・欠勤レポート)
    • タスク見積もり精度レポート

    ② 日次 Slack レポート

    対象読者EJEC IT 担当者・マリンスフィア
    配信先Slack #mobile-daily-monitor
    配信時刻毎日 08:00 JST(自動)
    目的前日の利用状況と Lambda エラーを朝一番に確認
    レポート内容:
    • アクティブユーザー数 / 全員数(例: 28 / 35 名)
    • 前日の活動記録件数・合計作業時間
    • 前日アプリ未使用ユーザー一覧
    • 12 重要 Lambda の 24 時間エラー件数(0 件なら ✅ 表示)

    ③ CloudWatch アラーム(即時通知)

    対象読者マリンスフィア 開発担当
    通知先Slack #mobile-lambda-alert + メール
    発火条件5分以内に Lambda エラー ≥ 3 件(認証系は ≥ 1 件)
    目的障害を発生後5分以内に検知し、即座に対応開始
    監視対象 Lambda(12 関数):
    • 認証系: appsyncAuth / BTPSSOLambda / SSOBTPIASLambda / ServiceNowSSOLoginLambda 他
    • 打刻系: SSORefreshToken / BTPTokenRefresherLambda / OTupdaterLambda
    • タスク系: ServiceNowLambda / ServiceNowUpdateStatusLambda / dailyActivityLogSaver
    使い分けまとめ
    📊 活動ダッシュボード — EJEC 管理職が「今日誰が稼働中か」を確認する日常ツール
    📨 日次 Slack レポート — EJEC IT 担当者が毎朝前日の利用率とシステム健全性を確認
    🚨 CloudWatch アラーム — 障害発生時にマリンスフィアへ即時通知。EJEC IT から連絡が来る前にマリンスフィアが把握
    1フロントエンドアーキテクチャ — 4層構造

    React Native(Expo Router)のレイヤー構成。画面層からバックエンドへの依存は一方向。各層は Context API 経由で疎結合に接続。

    画面層Expo Router 画面 — app/ ディレクトリ
    grey.tsx打刻前・時刻表示
    main.tsxアクティブタスク
    inbox.tsxタスク受信トレイ
    newClock.tsx打刻確認
    learning.tsx学習アクティビティ
    Login.tsxSSO認証
    activityLog.tsx日別ログ確認
    ↓ useContext() で読み書き(単方向データフロー)
    Context層14 グローバルプロバイダー — src/components/
    GlobalTimeContext打刻状態・BTPステータス
    TaskContextタスク一覧・活動記録
    OvertimeContext残業時間計算・表示
    UserProfileContext表示名・個人設定
    ToastContext通知トースト
    ErrorContextエラーモーダル制御
    SessionContainerセッション監視
    + 7 その他Auth / Favorites / Notification 等
    ↓ サービス関数・カスタムフックを呼び出し
    Service / Hook層ビジネスロジック — src/services/ + src/hooks/
    punchHandler打刻ロジック・レート制限
    clockOutService退勤処理オーケストレーション
    dailyActivityLogServiceログ生成・保存
    btpSsoAuthBTP SSO認証・再認証
    syncServiceServiceNow状態同期
    breakService休憩管理
    useModalStatesモーダル開閉制御
    useSwipeModalスワイプ操作
    useBreakTask休憩タスク判定
    ↓ AppSync GraphQL mutation / query(主要永続化経路)
    永続化層クラウド永続化 + セッションキャッシュ
    AppSync GraphQLクラウド永続化の主経路
    DynamoDB 5テーブル全重要データの保管先
    AsyncStorageセッションキャッシュのみ(ログアウト時クリア)
    ↕ バックエンドへ接続 — AppSync → Lambda → SAP BTP / ServiceNow「バックエンド」タブで詳細を確認
    2主要機能フロー — フロントエンド視点

    各機能で画面・Context・Service・バックエンドがどう連携するかをシーケンス図で表示。タブで切り替えてください。

    3データ永続化アーキテクチャ

    全ての重要データは AppSync GraphQL → Lambda → DynamoDB 経路で直接クラウドに保存されます。AsyncStorage はセッション中のUIキャッシュ用途に限定されており、ログアウト時にクリアされます。

    主要データフロー(AppSync 直接経路)
    操作AppSync Mutation / QueryLambda保存先
    出退勤打刻createTimeRecorderSSOBTPSSOLambdaSAP BTP
    退勤時ログ保存saveDailyActivityLogdailyActivityLogSaverDynamoDB: dailyActivityLog
    残業時間送信updateOvertimeOTupdaterLambdaDynamoDB: OvertimeSummary
    タスク状態更新updateWorkTaskStatusServiceNowUpdateStatusServiceNow
    活動ログ記録putActivityLogactivityLog LambdaDynamoDB: ActivityLog (TTL 30日)
    個人設定保存saveUserProfilePersonalConfigDB LambdaDynamoDB: PersonalConfigDB
    AsyncStorage — セッションキャッシュのみ
    キー用途スコープ
    @EmailStatusStorage受信トレイタスク一覧(セッション中の表示キャッシュ)ログアウト時クリア
    @TimeRecordsStorageアクティビティ時刻記録(退勤時にDynamoDBへ送信)退勤後クリア
    inbox_breakRecords休憩セグメント(退勤ログに統合して送信)退勤後クリア
    inbox_breakTaskId / _breakStartTime現在の休憩タスクID・開始時刻休憩終了時クリア
    ACTIVE_SESSION_IDデバイスセッション識別子(AppSync認証に使用)ログアウト時クリア
    lastBtpUserEmail前回ログインユーザー(SSO経路選択に使用)デバイス保持
    @TaskFavoritesお気に入りタスク一覧(PersonalConfigDB Lambdaとも同期)ユーザースコープ
    退勤時のデータ確定フロー
    1
    退勤ボタンタップ → BTPSSOLambda 経由で SAP BTP に退勤打刻(002)を直接送信。
    2
    セッション中の timeRecords + breakRecords を取得し、DailyActivityLog ペイロードを生成。
    dailyActivityLogService がローカルキャッシュを読み込んでログを構築。
    3
    AppSync saveDailyActivityLog mutation → dailyActivityLogSaver Lambda → DynamoDB に永続保存。
    4
    ローカルキャッシュをクリア、AsyncStorage を初期化してログイン前状態に戻す。
    4アプリ配布・OTA アップデート

    iOS Ad Hoc 配布と EAS OTA(Over The Air)アップデートにより、ストア審査なしで迅速な機能リリースを実現。

    現在の配布形態

    プロビジョニングAd Hoc(テスト配布)
    プロファイル名WTR-Internal-Adhoc-Testing
    有効期限2026年10月27日
    登録デバイス数26台(上限100台 / 年)
    OTAチャンネルpreview(クライアント向け)

    OTA 更新の仕組み

    配信プラットフォームEAS Update(Expo)
    チェックタイミングアプリ起動時に自動チェック
    適用タイミング次回起動時(バックグラウンドDL)
    適用条件JS・アセット変更のみ(ネイティブ変更は再ビルド必要)

    将来の配布計画

    配布方式Apple Business Manager
    メリットUDID登録制限なし(本番展開対応)
    対象全社員への展開
    テスト概要(詳細はバックエンドタブ 3 参照)  Jest ユニット / 統合テスト: 1,247件(62スイート) — サービス・Context・ユーティリティをカバー。  Maestro E2E テスト: 18フロー — 出退勤打刻・タスク操作・SSO認証等の主要フローを実機シミュレーターで検証。