メインコンテンツまでスキップ
バージョン: 最新 (develop)

BlackSwan レセプト連携 基本設計書(Phase 1)

文書情報

項目内容
文書名BlackSwan レセプト連携 基本設計書(Phase 1)
v1.3(2026-06-02 実装ステータス表記の整理=設計内容に集中)
作成日2026-05-30(v1.0)/ 2026-06-01(v1.1・v1.2)/ 2026-06-02(v1.3)
対象BlackSwan Web ⇄ ケア樹(外部レセプトシステム)連携の Phase 1 本番稼動範囲
想定読者開発者・PM・QA
関連ドキュメント要件定義書 receipt-requirements.md / ギャップ調査 caretree-missing-fields-investigation.md / API マッピング caretree-api-mapping.md / 見積 estimate.md
参照コードpackages/backend/src/modules/recept/(連携ドメイン)/packages/backend/src/modules/caretree/(汎用クライアント)/packages/backend/src/bff/web/recept-sync-page/(GraphQL)/packages/backend/schema.prismaReceptSyncJob ほか)

1. 目的・適用範囲

1.1 目的

BlackSwan が保持する入所・契約・記録データを、外部の介護レセプト計算サービスである ケア樹 へ連携し、ケア樹側で介護給付費請求書・利用者負担請求書を生成できる状態にする。本設計書は Phase 1(〜2026-06 末・本番稼動)の本番リリース範囲を対象とする。

1.2 対象範囲(Phase 1)

#機能概要
F1ケア樹 認証(事業所単位トークン)token-only(PW 非保存)/契約共通 ID・PW は Corporation 保管/事業所ごとに token を BusinessOffice 保管
F2連携対象 API クライアント(9 系統+認証)各系統 POST / PUT
F3ETL(既存スキーマ → ケア樹形式 mapper)9 系統ごとに converter
F4連携起動(Mutation)と非同期処理(ジョブキュー)SQS(DLQ / リトライ / SQS マネージド暗号化)+ Strategy パターン + Recovery(cron 5 分)
F5プレビュー一覧画面9 系統 × 利用者のセル マトリクス、ステータス別フィルタ、エラー詳細展開
F6事業所設定:ケア樹トークン取得セクションWeb UI 上で手動取得(無期限)
F7部屋/部屋グループの連携データ(2026-05-29 決定Bed/Team への必須項目追加+対応表(bedId↔roomId・teamId↔roomGroupId)+発番
F8入退所・転室の連携F7 の対応表をキーに roomId を解決して連携

1.3 対象外(Phase 2 以降)

  • 月初スケジューラ駆動の自動定期バッチ
  • ケア樹 → BlackSwan の双方向同期(更新の取り込み)
  • 差分検知(/master/updated API 活用)
  • 通所・ショート対応の事業所種別整合チェック
  • 不足項目 7 項目(給付率・部屋等)の BlackSwan 入力 UI 拡張は Phase 2 概要に織り込み済(Go/No-Go 後日判断)
  • 食事記録(04.02.02)/食事提供(02.04.08)/事業所食事提供(02.02.05)

1.4 連携対象 9 系統一覧

ReceptSyncType enum(schema.prisma:10879ALL_SYNC_TYPESrecept-preview.types.ts:15)を正源とする。

#系統 enumケア樹 API連携元 BS モデル備考
1USER_INFO(利用者情報)02.04.01User戻り値の riyoushaIdCaretreeUserMap に保存
2FAMILY_INFO(家族情報)02.04.02Family請求先フィールドは突合中(BS-4023)
3INSURANCE(介護保険)02.04.04InsuranceyoukaigoJoutaiKbnCdcareLevelId から変換
4SERVICE_PERIOD(サービス提供期間)02.04.03UserContractserviceKyuufuShubetsuCd 給付種別 CD は要マッピング
5ADMISSION(入退所)02.04.06BedAdmissionContract看取り加算は任意(API 仕様)
6MEAL_STOP(食止め)02.04.09ShiftReportMeal開始⇔終了のペアリング ETL(BS-4125)
7OUTING_OVERNIGHT(外出外泊)02.04.10OutingSchedule終了系フィールド既存・ペアリング ETL
8ROOM_TRANSFER(転室)02.04.07BedAdmissionContractroomId は対応表で解決、tenshitsuTmserviceStart 等から組立
9ROOM_BED(部屋・ベッド)02.02.04(部屋)/02.02.03(部屋グループ)BedTeam(5/29 決定:必須項目追加)BS発番+1:1分割(多床室 101_1)。BS が居室費単価等を保持

要件定義書では一時「11 系統」と表記していたが、コード/schema は 9 系統が正源(部屋+部屋グループを ROOM_BED に統合、食事系はすべて対象外)。本設計書は 9 系統で記述する。

🆕 v1.1 追記(2026-06-01):PR #1620 で modules/caretree/sync-strategy.interface.tsTypeScript 内部 enum SyncType(13 系統) が新規定義された(連携対象外の FACILITY_MEAL / MEAL_PROVISION / MEAL_RECORD も列挙)。これは Strategy パターン側で全 API 系統を網羅表現するもので、実際に Strategy が実装されるのは連携対象の 9 系統のみ。Prisma の ReceptSyncType(9 系統)は連携結果の状態管理に引き続き使用。両 enum は段階的整理(将来 Prisma 側を TS 内部 enum 寄せ)の方向。

1.5 用語

用語意味
ケア樹Goodtree 社の介護レセプト計算サービス(外部システム)
連携BlackSwan → ケア樹への一方向同期
系統連携対象 API のグループ(上記 9 種類)
連携ジョブReceptSyncJob の 1 レコード(対象月 × 利用者 × 事業所 × 系統)
プレビュー連携ジョブの一覧(マトリクス)画面
対応表BlackSwan ID とケア樹採番 ID(integer)の対応関係を保持する内部テーブル
1:1 分割BS のベッド 1 つ=ケア樹の部屋 1 つで対応させる方式(多床室は 101_1〜)

2. システム全体像

2.1 アーキテクチャ

2.2 主要コンポーネントと責務

コンポーネント場所責務
recept-sync-page.resolver.tsbff/web/recept-sync-pageGraphQL 入出力
ReceptServicemodules/recept連携の中心ロジック(sync() / listPreview() / processJob() / markMaxRetriesExceeded()
ReceptSyncConsumerServicelibs/sqsSQS Consumer(sqs-consumer v15)。Business/Temporary エラー別ハンドリング
ReceptSyncRecoveryServicemodules/receptCron 5 分。PENDING(未エンキュー)と IN_PROGRESS(固着)を復旧
SyncStrategyRegistrymodules/caretreeISyncStrategy 実装を SyncType で索引(登録順保持)
ISyncStrategy(系統別実装)modules/caretree/strategies/1 系統の Extract → Transform → Load を担う Strategy
ReceptSyncJobRepositorymodules/receptReceptSyncJob の CRUD・一覧取得・Recovery 用検索
ReceptTokenProvidermodules/receptケア樹 API トークン供給
SqsModule / SQSClient プロバイダlibs/sqsSQSClient を NestJS DI に登録するグローバルモジュール
CaretreeApiClientmodules/caretreeケア樹 REST 汎用 HTTP(post/put)。Business/Temporary 例外を投げる
CaretreeAuthClientServicemodules/caretreeケア樹 認証 /v1/token(取得・検証・削除)
CaretreeBusinessError / CaretreeTemporaryErrormodules/caretree/caretree-error.ts再試行不可(4xx 系)/再試行可(5xx 系)のエラー分類
対応表モデルschema.prismaBS ID ⇔ ケア樹採番 ID の対応
FE プレビュー画面apps/blackswan-web/src/sections/recept-sync/プレビュー一覧/ジョブ詳細
FE 事業所設定 トークン UI既存事業所設定ページに追加ケア樹トークン取得セクション
FE ベッド/チーム編集既存ベッド/チームフォーム拡張部屋必須項目入力(5/29 決定)

2.3 データフロー(連携 1 件の例)

2.4 トランザクション境界

  • 連携ジョブの起票(PENDING へ upsert):同期トランザクション。Mutation の即時応答に含める。
  • 連携の実行:1 ジョブ=1 トランザクション。IN_PROGRESS への遷移 → ケア樹 API 呼出 → 対応表更新 → SUCCESS/ERROR への遷移 を 1 単位に閉じる。ケア樹 API は外部呼出のため、DB 書込は API 成功後に行い、API 失敗時は対応表を更新しない(冪等性維持)。

3. データ設計

3.1 既存モデル(Phase 1 で参照)

モデル役割関係する系統
User利用者USER_INFO
Family家族FAMILY_INFO
Insurance介護保険情報INSURANCE
UserContractサービス提供期間SERVICE_PERIOD
BedAdmissionContract入退所・ベッド割当ADMISSION/ROOM_TRANSFER
BedベッドROOM_BED(部屋情報も保持=5/29 決定)/転室時の対応表参照
TeamチームROOM_BED(部屋グループ情報も保持=5/29 決定)
BusinessOffice事業所ケア樹トークン保管先(要追加)
Corporation法人マスタ ID/PW 保管先(要追加・連携時のみ使用)

3.2 新規・拡張モデル

3.2.1 ReceptSyncJob

連携 1 件(対象月 × 利用者 × 事業所 × 系統)。

フィールド説明
idUUID v7PK
targetYearMonthString対象月(yyyy-mm)
userIdUUID利用者(FK)
businessOfficeIdUUID事業所(FK)
syncTypeReceptSyncType9 系統のいずれか
statusReceptSyncStatusPENDING/IN_PROGRESS/SUCCESS/ERROR
executedByStaffIdUUID?実行者(バッチ時 null)
executedAtDateTime?最終実行日時
errorDetailsJson?ケア樹レスポンス等のエラー本文
recoveryCount 🆕Int (default 0)Recovery Service が IN_PROGRESS 固着ジョブを再試行した回数(無限ループ防止)
corporationIdUUIDRLS(app.corporation_id 自動設定)
制約@@unique([targetYearMonth, userId, businessOfficeId, syncType])再連携は同一行更新
インデックス@@index([corporationId, targetYearMonth])プレビュー検索
インデックス 🆕@@index([status, createdAt])Recovery Service の固着検出用

3.2.2 BusinessOffice 拡張

追加フィールド説明
caretreeTokenString?ケア樹アクセストークン(暗号化保管)
caretreeTokenAcquiredAtDateTime?トークン取得日時
caretreeJigyoushoIdString?ケア樹側の事業所 ID(連携 path 用)

3.2.3 Corporation 拡張

追加フィールド説明
caretreeMasterUserIdString?ケア樹マスタ ID(連携時のみ使用・暗号化保管)
caretreeMasterPasswordString?ケア樹マスタ PW(PW 非保存方針との整合は 7.3 で確定

実装時は token-only に寄せ、PW を BS DB に永続化しない方式を最優先で検討する(操作画面で都度入力 → トークン取得後破棄/Secrets Manager 等)。

3.2.4 Bed 拡張(5/29 決定)

ケア樹 RoomModel の ★必須項目を Bed に追加し、Bed = 部屋(兼)として扱う。

追加フィールド説明
roomNoInt部屋番号(ケア樹 0〜999)
roomNmString部屋名(多床室は 101_1 等)
kaiInt階数
teiinInt定員(1:1 分割では 1)
typeString居室形態(CD)
kyoshitsuTypeString居室タイプ(CD:個室/多床室/ユニット 等)
kyoshitsuhiTankaInt居室費単価
startDtDate開始日
sortNoInt?並び順

3.2.5 Team 拡張(5/29 決定)

ケア樹 RoomGroupModel の ★必須項目を Team に追加し、Team = 部屋グループ(兼)として扱う。

追加フィールド説明
roomGroupNoInt部屋グループ番号
sortNoInt?並び順

既存の teamNameteamDisplayName をケア樹 roomGroupNm にマッピング。

3.2.6 対応表モデル

BS の内部 ID と ケア樹採番 ID(integer)を対応づける。

モデルキー用途
CaretreeBedRoomMapbedId(FK)/caretreeRoomId Int/businessOfficeId転室 API の roomId 解決
CaretreeTeamRoomGroupMapteamId(FK)/caretreeRoomGroupId Int/businessOfficeId部屋グループ参照
CaretreeUserMapuserId(FK)/caretreeRiyoushaId Int/businessOfficeIdpath の riyoushaId 解決
CaretreeFamilyMapfamilyId(FK)/caretreeKazokuId Int/businessOfficeId家族 API
CaretreeInsuranceMapinsuranceIdcaretreeKaigoHokenshouIdbusinessOfficeId介護保険 API(更新時)

全モデルとも corporationId(RLS)・createdAtupdatedAt を持ち、@@unique([businessOfficeId, <bsId>]) で多重発番を防ぐ。

3.3 ER 関係(要約)


4. 機能設計

4.1 機能一覧

ID機能主要トリガ/呼出元
FN-01連携起動(プレビューから対象を選んで連携)FE → Mutation startReceptSync
FN-02プレビュー一覧表示(9 系統 × 利用者)FE → Query listReceptSyncPreview
FN-03エラー詳細表示(行クリック → アコーディオン展開)FE のローカル展開(追加クエリなし)
FN-04ケア樹トークン取得(事業所単位)FE → CaretreeAuthClientService.getToken
FN-059 系統 ETL(BS → ケア樹ペイロード変換)ReceptService.sync 内部
FN-06対応表 ID 解決(bedId → caretreeRoomId 等)ReceptService.sync 内部
FN-07GET → merge → PUT 2026-06-01 廃止(完全一方向)
FN-08ダミー値発番(POST/PUT 双方の全項目送信ReceptService.sync 内部
FN-09エラー記録(status=ERROR + errorDetails)ReceptService.sync 内部
FN-10ジョブ再連携(同一キーで status を更新)FN-01 と同じ(@@unique キーで update)

4.2 FN-01: 連携起動

入力:StartReceptSyncInputrecept-sync-page.type.ts:50

フィールド必須既定値
userIds[ID!]!
businessOfficeIdID!
targetMonthString!(yyyy-mm)
syncTypes[ReceptSyncType!]未指定時は全 9 系統

処理(ReceptService.sync line 117〜):

  1. ReceptSyncJob を upsert(status=PENDING)— @@unique([targetYearMonth, userId, businessOfficeId, syncType]) で再連携は同一行更新。
  2. RECEPT_SYNC_REQUESTED を emit(受付応答を即時返却)。
  3. Listener が非同期で sync() を実行。
  4. sync() 内:トークン取得 → Extract(既存 Repository 再利用)→ Transform(ETL)→ Load(ケア樹 API)→ 対応表更新 → status 更新。

4.3 FN-02: プレビュー一覧

入力:ListReceptSyncPreviewInputrecept-sync-page.type.ts:129

フィールド必須既定値
businessOfficeIdID!
targetMonthString!
filter.statusReceptSyncPreviewStatus?全件
filter.syncTypes[ReceptSyncType!]?全 9 系統
sortByenumUSER_NAME_KANA_ASC
pagination.offset / limitInt

出力:ListReceptSyncPreviewOutputrecept-sync-page.type.ts:243

  • summary:ステータス別件数(タブ件数表示用、母数=利用者数 × 9)
  • totalCount:フィルタ後件数(ページャ用)
  • users[]:(利用者 × 系統) の 1 セルを表す行。syncJob: null の場合は未連携(NOT_SYNCED 派生ステータス)。

ReceptSyncPreviewStatus enum(フィルタ専用):NOT_SYNCEDPENDINGIN_PROGRESSSUCCESSERRORrecept-preview.types.ts:89)。

4.4 FN-05: ETL(9 系統 Strategy)

🆕 v1.1 反映(PR #1620):系統別の処理は Strategy パターンで実装する。各 Strategy は ISyncStrategy を実装し、SyncStrategyRegistry に DI 登録されることで ReceptService.processJob() から系統別呼出される。

// modules/caretree/sync-strategy.interface.ts
export interface ISyncStrategy {
readonly syncType: SyncType; // 13 系統の TypeScript 内部 enum
execute(context: SyncContext): Promise<void>;
}
export type SyncContext = {
receptSyncJobId: string;
userId: string;
businessOfficeId: string;
targetYearMonth: string; // "yyyy-mm"
token: string;
};

modules/caretree/strategies/(未配置)配下に系統ごとの Strategy を配置する。

系統Strategy クラス(提案)入力出力
USERUserSyncStrategyUser + 対応表利用者ペイロード POST/PUT
FAMILYFamilySyncStrategyFamily家族ペイロード POST/PUT
INSURANCEInsuranceSyncStrategyInsurance介護保険ペイロード POST/PUT
SERVICE_PERIODServicePeriodSyncStrategyUserContractサービス提供期間 POST/PUT
ADMISSIONAdmissionSyncStrategyBedAdmissionContract入退所 POST/PUT
MEAL_STOPMealStopSyncStrategy食止め記録開始⇔終了をペア化
ABSENCEAbsenceSyncStrategy外出/帰所記録開始⇔終了をペア化
ROOM_TRANSFERRoomTransferSyncStrategy同上+対応表roomId を対応表で解決・tenshitsuTm を組立
ROOM / ROOM_GROUPRoomSyncStrategy / RoomGroupSyncStrategyBed / Team5/29 決定の必須項目から組立

各 Strategy は副作用なしで Extract → Transform → Load を内包し、テスト時は対応する Repository / CaretreeApiClient をスタブで差し替える。

連携対象外の系統FACILITY_MEAL / MEAL_PROVISION / MEAL_RECORD)は SyncType 列挙には含まれるが、対応する Strategy は実装しない(SyncStrategyRegistry.get()未対応の連携種別 例外)。

v1.0 では modules/caretree/converters/ に純粋関数(toRiyoushaPayload 等)として実装する案だったが、PR #1620 で Strategy パターンに切り替え(Extract / Transform / Load を 1 つの Strategy に閉じ込めるため、依存と境界が明確化される)。

4.5 FN-06: 対応表による ID 解決(2026-06-01 改訂:BS発番+対応表のみ・名寄せ廃止

  • GET(名寄せ)は使わない。対応表に無ければ即 POST 発番。発番後の採番 ID を対応表に保存。
  • 同じく userId → caretreeRiyoushaIdteamId → caretreeRoomGroupIdfamilyId → caretreeKazokuId を対応表で保持。

🆕 v1.2 変更点(PR #?? で別途反映):v1.1 までの「名寄せ(GET /master/room → room.bikou 優先 → bedName == roomNm)」フローは廃止した。理由は完全一方向化(GET 一切不使用)。代償としてケア樹側に手動登録された部屋との 重複リスクを受容する(Phase 1 運用前提:ケア樹マスタは BS 経由のみで管理)。

4.6 FN-07: GET → merge → PUT2026-06-01 廃止

🚫 本機能は採用しません完全一方向(BS → ケア樹のみ) の方針で、PUT 更新時の GET 取得・merge は行わない。代わりに FN-08 のダミー値発番ルールに従い PUT も全項目送信(BS が持たない必須はダミー値で送る)。

影響:

  • ケア樹側で BS が知らないフィールド に値が入っていた場合、PUT で その値は上書きされる(partial-update は前提にしない)。
  • これを受容する条件として、ケア樹マスタ(部屋・部屋グループ等)は BS 経由のみで管理する運用前提を置く(手動編集禁止)。
  • 共通ヘルパー mergeAndPut<T> は実装しない(BS-4122 の対応範囲から外れる)。

4.7 FN-08: ダミー値発番(POST/PUT 双方に適用

🆕 v1.2 改訂:完全一方向化(FN-07 廃止)に伴い、新規 POST だけでなく PUT 更新でも全項目送信する。BS が値を持たない ★必須項目はダミー値を使う(BS-4122)。

既定値
integer(金額・番号・階数・定員)0kyoshitsuhiTanka=0
string(名称)""
string(CD:項目種別)要 Goodtree 確認「未設定」CD or 代表値
date1900-01-01 または当日センチネル運用
time00:00:00

5/29 決定の影響:部屋・部屋グループの ★必須項目は BedTeam に追加され BS が実値を保持するため、本表の対象から外れる(残るのは住所カナ・CD 系・日付・時刻 など部屋系以外)。

4.8 FN-09: エラー処理

🆕 v1.1 反映(PR #1620):ケア樹 API エラーは modules/caretree/caretree-error.ts2 種類に明示分類して投げる。Consumer 側で分類に応じた処理を分岐させる。

例外クラス想定 HTTPConsumer ハンドリングジョブ状態
CaretreeBusinessError4xx(必須不足・バリデーション・重複等)再試行せずメッセージ削除errorDetails 保存ERROR(要画面からの再連携)
CaretreeTemporaryError5xx・タイムアウトVisibilityTimeout を指数バックオフで延長してキューに戻すmaxReceiveCount=5 で DLQERROR(DLQ 滞留時)
不正なメッセージ形式再試行せずメッセージ削除
BS 側例外(DB/コード不具合)Sentry へ送信、errorDetails に概要保存ERROR
トークン失効401/403CaretreeBusinessError 扱い。事業所設定画面で再取得を促す(自動再認証はしない)ERROR

最大試行回数到達時は ReceptService.markMaxRetriesExceeded() を呼び出してメッセージを削除し、ジョブを ERROR に確定させる(PR #1620・実装スタブのみ)。

4.10 Recovery(回復ポーラー)

🆕 v1.1 追記(PR #1620)ReceptSyncRecoveryServicemodules/recept/recept-sync-recovery.service.ts)が NestJS Cron 5 分間隔で固着ジョブを回復する。

@Cron('*/5 * * * *')
async recoverStuckJobs(): Promise<void> {
await this.recoverPending(queueUrl); // 未エンキューの PENDING を再送
await this.recoverInProgress(queueUrl); // 古い IN_PROGRESS をリセット
}
対象検出条件復旧アクション無限ループ防止
PENDING のまま再送漏れstatus=PENDING かつ作成から N 分経過SQS へ enqueue
IN_PROGRESS で固着status=IN_PROGRESS かつ最終更新から N 分経過status=PENDING に戻し再送recoveryCount をインクリメント。上限到達で ERROR に確定

検出には @@index([status, createdAt])(PR #1620 で追加)を利用。


4.9 FN-10: 再連携・冪等性(2026-06-01 改訂

  • ジョブの一意性:ReceptSyncJob@@unique キー。再連携は status/errorDetails/executedAt の更新で表現。
  • ケア樹側:BS発番+対応表(FN-06) で多重発番を防ぐ。SQS at-least-once 配信下でも、対応表に既存なら PUT 経路へ分岐。
  • 名寄せ(旧 GET ベース)は廃止したため、ケア樹側に手動登録された部屋との衝突は検知できない。運用前提:ケア樹マスタは BS 経由のみで管理する。

5. 画面設計

5.1 画面一覧

画面 ID画面名場所
SC-01レセプト連携 プレビュー一覧/recept/sync(新規)
SC-02連携ジョブ詳細(エラー含む)SC-01 のアコーディオン展開
SC-03事業所設定/ケア樹トークン取得既存事業所設定ページに追加
SC-04ベッド編集(部屋必須項目入力)既存ベッドフォーム拡張
SC-05チーム編集(部屋グループ必須項目入力)既存チームフォーム拡張

詳細ワイヤーは docs/receipt/wireframes/ を参照。

5.2 SC-01:プレビュー一覧

主要要素:

  • 対象月セレクタ(yyyy-mm、当月既定)
  • 事業所セレクタ(権限のある事業所のみ)
  • タブ:全件/未連携/連携待ち/連携中/成功/エラー(summary の各件数を表示)
  • :利用者 × 系統(9 系統横並びのセル マトリクス)
  • セル:ステータスアイコン+実行日時。クリックで該当行アコーディオン展開(SC-02)
  • 一括連携ボタン:チェックボックス選択行を startReceptSync へ送信
  • 並び替え:利用者カナ昇/降順/実行日時降順
  • ページャ:offset/limit

5.3 SC-02:ジョブ詳細

アコーディオン内:

  • 該当ジョブの最終実行日時・実行者・エラー詳細 JSON
  • 「再連携」ボタン(同一行を更新)
  • ケア樹側採番 ID(対応表があれば表示)

5.4 SC-03:ケア樹トークン取得

  • 事業所設定ページの 1 セクション
  • マスタ ID/PW 入力欄(Corporation スコープ・連携時のみ使用・PW 非保存方針との整合は 7.3 参照)
  • 「トークン取得」ボタン → CaretreeAuthClientService.getToken() 呼出 → 取得結果を BusinessOffice.caretreeToken に暗号化保管
  • 取得日時・トークン状態(未取得/取得済み)を表示

5.5 SC-04/SC-05:ベッド・チーム編集

5/29 決定の追加項目を入力可能にする:

  • ベッド:部屋番号・部屋名・階数・定員・居室形態・居室タイプ・居室費単価・開始日
  • チーム:部屋グループ番号・並び順

入力 UI のバリデーション(必須/数値範囲)は Zod スキーマで定義。bed-schema.ts の既存 roomNumberbedNumber 層間ドリフトもこのタイミングで解消する。


6. 外部 IF 設計(ケア樹 REST API)

6.1 API ベース

環境URL
本番https://api.caretree.jp
開発/検証Goodtree 提供環境

getCaretreeApiBaseUrl()caretree-env.ts)で環境変数 CARETREE_API_BASE_URL を解決。

6.2 認証 API

メソッドpath用途対応メソッド
POST/v1/tokenトークン取得(マスタ ID/PW から)getToken()
GET/v1/authorizeトークン検証verifyToken()
PUT/v1/tokenトークン再生成
DELETE/v1/tokenトークン削除deleteToken()(運用上未使用予定)

方針:事業所単位トークン・無期限・契約共通マスタ ID/PW。token-only(PW 非保存)。 取得は事業所設定画面で手動。失効時は再取得(再認証)し、自動の連携解除は実装しない。

6.3 業務 API(9 系統)

すべて事業所スコープ(/v1/jigyousho/{jigyoushoId}/...)。jigyoushoIdBusinessOffice.caretreeJigyoushoId から解決。

系統path(代表)メソッド備考
利用者(02.04.01)/v1/jigyousho/{jigyoushoId}/riyoushaPOST/PUT/GET戻り値 riyoushaIdCaretreeUserMap に保存
家族(02.04.02)/v1/jigyousho/{jigyoushoId}/kazokuPOST/PUT/GET同上
介護保険(02.04.04)/v1/jigyousho/{jigyoushoId}/kaigo-hokenshouPOST/PUT/GET
サービス提供期間(02.04.03)/v1/jigyousho/{jigyoushoId}/teikyou-kikanPOST/PUT/GET
入退所(02.04.06)/v1/jigyousho/{jigyoushoId}/nyuutaishoPOST/PUT/GET
食止め(02.04.09)/v1/jigyousho/{jigyoushoId}/shokudomePOST/PUT/GETペアリング ETL
外出外泊(02.04.10)/v1/jigyousho/{jigyoushoId}/gaishutsu-gaihakuPOST/PUT/GETペアリング ETL
転室(02.04.07)/v1/jigyousho/{jigyoushoId}/riyousha/{riyoushaId}/tenshitsuPOST/PUT/GETpath に riyoushaId 必須・roomId 必須・tenshitsuTm 必須
部屋(02.02.04)/v1/jigyousho/{jigyoushoId}/master/roomPOST/PUT/GET戻り値 roomId を対応表に保存
部屋グループ(02.02.03)/v1/jigyousho/{jigyoushoId}/master/room-groupPOST/PUT/GET戻り値 roomGroupId を対応表に保存

詳細パス・パラメータは docs/receipt/caretree-api-v1.swagger.json、マッピングは caretree-api-mapping.md を正とする。

6.4 共通リクエスト/レスポンス

  • 認証:Authorization: Bearer <token>CaretreeApiClient.authHeader 参照)
  • Content-Type:application/json
  • 文字コード:UTF-8
  • タイムアウト:5000ms(CaretreeModuleHttpModule 設定)
  • エラーレスポンス:4xx/5xx の本文を ReceptSyncJob.errorDetails に保存

7. 共通機能・非機能

7.1 ロギング

  • nestjs-pino を全モジュールで使用
  • ReceptServicecorporationIdbusinessOfficeIdtargetMonthuserIdCountsyncTypeCount を構造化フィールドで出力
  • 連携 1 件ごとに開始/成功/失敗ログを残す(CloudWatch Logs 経由で検索)

7.2 エラー監視

  • @sentry/node。Listener で try-catch して未処理 Promise reject を防止(プロセス停止回避)
  • Sentry の breadcrumb で連携対象月・ジョブ ID を残す

7.3 セキュリティ

観点方針
トークン保管DB 列レベル暗号化(AES-256)。BusinessOffice.caretreeToken 列に保存し、復号は ReceptTokenProvider に閉じる
マスタ ID/PWPW 非保存方針を最優先。実装案:(A) 操作時のみ画面入力 → トークン取得後破棄、(B) Secrets Manager 経由で取得時のみ復号、(C) 暗号化保管+アクセス制限。決定は Phase 1 早期に確定(BS-4107)
RLS全モデルで corporationId の RLS(current_setting('app.corporation_id')
通信HTTPS(TLS 1.2 以上)
認可プレビュー一覧/連携起動は施設管理者ロールに限定(FE/BFF 双方でチェック)
監査ReceptSyncJob.executedByStaffId に実行者を記録

7.4 ジョブキュー

項目設定/実装
キュー${env}-billing-sync-queue(SQS 標準キュー)/${env}-billing-sync-dlq(DLQ)
暗号化SQS マネージド暗号化(メイン・DLQ 共に QueueEncryption.SQS_MANAGED
visibility timeout300 秒(5 分)
retentionメイン 1 日/DLQ 14 日
maxReceiveCount5(5 回失敗で DLQ)
ConsumerReceptSyncConsumerServicelibs/sqs/sqs-consumer v15)
エラー分類CaretreeBusinessError(再試行せず削除)/CaretreeTemporaryError(指数バックオフで再キュー)
回復ポーラーReceptSyncRecoveryService(cron 5 分、PENDING/IN_PROGRESS 復旧、recoveryCount でループ防止)
インフラ定義packages/infra/lib/billing-sync-queue.tsBillingSyncQueue Construct)
NestJS 配線libs/sqs/sqs.module.ts(グローバル)/ libs/sqs/sqs-client.provider.tsSQSClient DI)

EventEmitter は段階的削除対象recept-sync.listener.tsrecept-sync.event.ts は残存しており、Strategy 実装と並行して削除予定。

設計の詳細は PR #1620 で追加された ADR / 設計ドキュメントを参照:

  • docs/backend/caretree/ADR-001-job-queue-selection.md
  • docs/backend/caretree/bs-3970-implementation-plan.md
  • docs/backend/caretree/bs-3970-infra-update.md
  • docs/backend/caretree/nestjs-integration-design.md

7.5 冪等性

  • ジョブの一意性:ReceptSyncJob @@unique
  • ケア樹側:名寄せ+bikou 相互参照(FN-06)+対応表で多重発番を防ぐ
  • SQS at-least-once 配信下でも、対応表の存在確認 → PUT 経路に切替で安全

7.6 性能・可用性

観点要件
同時実行数1 事業所あたり 1 並列(ケア樹 API のレート制限考慮・要確認)
1 件当たり処理時間1〜3 秒(ケア樹 API レスポンス依存)
1 月次連携の総時間1 事業所 100 利用者 × 9 系統 = 900 ジョブ → 約 30〜60 分(並列度 4 想定)
可用性BlackSwan SLO に準拠(99.5%)
復旧SQS DLQ にあるジョブは運用画面から再連携可能
データ保持ReceptSyncJob は 12 か月保管 → 以降アーカイブ(運用合意要)
監視プレビュー一覧の ERROR 件数を CloudWatch メトリクス化(運用画面に件数表示)
障害通知DLQ 投入時に Slack 通知(運用チャンネル)
性能試験Phase 1 リリース前に 1 事業所 100 利用者 × 9 系統で実測

8. 移行(Phase 1 リリース時)

#作業担当タイミング
M1BusinessOfficeCorporation への新規列追加マイグレーションBEリリース前
M2BedTeam への部屋必須項目追加マイグレーションBE同上(既存行は NULL/既定値で初期化)
M3対応表モデル追加マイグレーションBE同上
M4ReceptSyncJob は既存(追加マイグレーション不要)
M5初回ケア樹トークン取得(事業所単位)施設管理者本番切替直後
M6既存ベッドの部屋情報初回入力(または ケア樹からの取り込み)施設管理者本番切替後 1〜2 日以内
M7対応表の初回ブートストラップ(既存ベッド → ケア樹発番)BE バッチM6 完了後

9. 制約・前提・残課題

9.1 前提

  • ケア樹本番 URL:https://api.caretree.jp(Goodtree 確定)
  • ケア樹トークンは無期限(取得時点の手動運用)
  • BS 認証ロールは施設管理者のみ操作可能

9.2 残決定(次回確定要)

#項目概要
Q1居室費単価などの実値の入力主体2026-06-01 確定:BS で入力(完全一方向=ケア樹取り込み不可。実値は BS 側で管理)
Q2マスタ ID/PW の保管方式7.3 セキュリティの A/B/C 案から選択
Q3BS-3914(部屋非連携 Done)の顧客再合意5/29 方針で覆る前提
Q4POST /master/room の実必須項目(Goodtree 確認)ダミー値の確定に必要
Q5teiin=1 のレセプト金額影響(Goodtree 確認)多床室 1:1 分割の妥当性検証
Q6CD 系の「未設定」CD 有無(Goodtree 確認)FN-08 ダミー値の確定に必要
Q7フェーズ配置(部屋/部屋グループ・転室 ≈ 46h)Phase 1 本体に繰入か/別フェーズか

9.3 経緯(参考)

  • 2026-05-12:同期のみ方針(BS-3886)
  • 2026-05-19:認証は事業所単位トークン(BS-4061)
  • 2026-05-22:給付率(負担率変換)、家族連携、食事提供系を整理(11 系統)
  • 2026-05-25:転室・部屋連携の方式を BS発番+1:1分割で確定(BS-4098)
  • 2026-05-27:シューペルブリアン様定例で部屋連携方式の再議論(案 B 提案)
  • 2026-05-29:部屋・部屋グループは BedTeam へ必須項目追加(新モデルなし)で確定(案 C 4 概念分離・案 B マッピング UI ともに不採用)
  • 2026-05-29:PR #1620 で SQS 基盤・Strategy パターン・Recovery Service を実装(BS-3970)。EventEmitter walking skeleton から SQS Consumer へ移行(旧 listener は段階的削除)
  • 2026-06-01:本基本設計書を v1.1 に改訂し PR #1620 実装を反映(PR #1664 で v1.0 初版、PR #1665 で v1.1)
  • 2026-06-01:完全一方向化を確定(v1.2)。GET 一切不使用(名寄せ廃止)・BS発番+対応表のみ・PUT 全項目送信(ダミー含む)。FN-07 GET-merge-PUT 廃止、Q1(実値の入力主体)は BS 入力で確定。ケア樹マスタは BS 経由のみで管理する運用前提。

付録 A. 参照ファイル一覧

区分ファイル行数
BE モジュールpackages/backend/src/modules/recept/recept.module.ts27
BEpackages/backend/src/modules/recept/recept.service.ts498
BEpackages/backend/src/modules/recept/recept-sync-job.repository.ts220
BEpackages/backend/src/modules/recept/recept-preview.types.ts169
BEpackages/backend/src/modules/recept/recept-sync.event.ts31
BEpackages/backend/src/modules/recept/recept-sync.listener.ts53
BEpackages/backend/src/modules/recept/recept-sync.mock.ts51
BEpackages/backend/src/modules/recept/recept-token.provider.ts33
BEpackages/backend/src/modules/caretree/caretree.module.ts
BEpackages/backend/src/modules/caretree/caretree-api.client.ts
BEpackages/backend/src/modules/caretree/caretree-auth-client.service.ts72
BEpackages/backend/src/modules/caretree/caretree-env.ts16
BE 🆕packages/backend/src/modules/caretree/caretree-error.ts17
BE 🆕packages/backend/src/modules/caretree/sync-strategy.interface.ts34
BE 🆕packages/backend/src/modules/caretree/sync-strategy.registry.ts28
BE 🆕packages/backend/src/modules/recept/recept-sync-recovery.service.ts116
BE 🆕packages/backend/src/libs/sqs/recept-sync-consumer.service.ts142
BE 🆕packages/backend/src/libs/sqs/sqs-client.provider.ts12
BE 🆕packages/backend/src/libs/sqs/sqs.module.ts10
Infra 🆕packages/infra/lib/billing-sync-queue.ts40
Migration 🆕packages/backend/migrations/20260523000000_add_recovery_count_to_recept_sync_job/migration.sql
設計 ADR 🆕docs/backend/caretree/ADR-001-job-queue-selection.md
設計 🆕docs/backend/caretree/bs-3970-implementation-plan.md
設計 🆕docs/backend/caretree/bs-3970-infra-update.md
設計 🆕docs/backend/caretree/nestjs-integration-design.md
BFFpackages/backend/src/bff/web/recept-sync-page/recept-sync-page.resolver.ts
BFFpackages/backend/src/bff/web/recept-sync-page/recept-sync-page.type.ts255
BFFpackages/backend/src/bff/web/recept-sync-page/recept-sync-page.module.ts
BFFpackages/backend/src/bff/web/recept-sync-page/recept-sync-page.e2e-spec.ts
Schemapackages/backend/schema.prisma:10829-10889ReceptSyncJob + enum)