メインコンテンツまでスキップ

マイグレーションガイド: v1.8.0

このガイドは v1.7.x から v1.8.0 へのアップグレードを支援します。バージョン 1.8.0 で変更されるのは master と survey-template パッケージのみです。マスターデータに対するオプトインのアクセス制御(controllerAuth ガードとシステム単位のアクセスリゾルバー)を追加し、master パッケージを使用するすべてのアプリケーションに対して、キーの検証、マスターコピー、統合バルクエンドポイント、タスク親ルートの動作を一部変更します。

リリース日​

2026-11-15

変更の概要​

変更内容影響必要なアクション
すべてのキーセグメントで # と @ を拒否すべてのアプリ。そのようなコード、ユーザー ID、グループ ID を含むリクエストは 400 で失敗します。キーに @ を含む既存の行には API から到達できなくなります連携処理を確認し、影響を受ける行を見つけて再作成する
設定行とデータ行はそれぞれ専用のルートでのみ変更pk/sk で行を更新または削除するすべてのアプリ設定行には /api/master-setting、データ行には /api/master-data を使用する
マスターコピーがコピー元テナントを読み取り、シーケンスもコピーマスターコピーを使用するすべてのアプリコピー前にコピー先のシーケンスを確認する
マスターコピーに system_admin が必要controllerAuth を設定しているか、リゾルバーを登録しているアプリコピーを行うユーザーの custom:roles クレームに system_admin を付与する
POST /api/master-bulk は設定をデータより先に upsert統合バルクエンドポイントを使用するすべてのアプリリクエストがアトミックであることを前提にしない
GET /api/tasks/sfn-task-parent は custom:tenant クレームを優先x-tenant-code で別のテナントを送信していたクライアント呼び出し元自身のテナントに対してリクエストを送信する
settingValue、name、seq を省略した更新すべてのアプリなし。省略したフィールドは保持されるようになりました
MySQL の検索修正と databaseProvider オプションMySQL を使用するアプリローカルのパッチを削除し、検出に失敗する場合は databaseProvider を設定する
controllerAuth、systemId、@MasterAccessResolver() (オプトイン)有効にしない限りなし任意: アクセス制御の導入 に従う
プロジェクトテンプレート: 空の controllerAuth オブジェクト新規プロジェクトのみマスターの書き込みに必要なロールを設定する

移行前チェックリスト​

  • プロジェクトがすでに v1.7.x と Node.js 22 で動作している(v1.7.0 移行ガイド を参照)
  • マスター設定、マスターデータ、ユーザー設定・グループ設定を作成する連携処理と、それらがコード、ユーザー ID、グループ ID として使用する値を把握している
  • アプリケーションがマスターコピーまたは POST /api/master-bulk を呼び出しているかを把握している

ステップ1:依存関係の更新​

npm install \
@mbc-cqrs-serverless/core@^1.8.0 \
@mbc-cqrs-serverless/tenant@^1.8.0 \
@mbc-cqrs-serverless/master@^1.8.0 \
@mbc-cqrs-serverless/sequence@^1.8.0 \
@mbc-cqrs-serverless/task@^1.8.0 \
@mbc-cqrs-serverless/cli@^1.8.0

サーベイテンプレートパッケージを使用している場合は、@mbc-cqrs-serverless/survey-template も ^1.8.0 に更新してください。

ステップ 2: キーセグメントを確認する​

すべてのキーセグメントが検証されるようになりました。空の値、または # や @ を含む値は 400 で拒否されます:

値チェックされる箇所
設定の codeすべての設定の作成と upsert(共通、テナント、グループ、ユーザー、バルク)、および getSetting(GET /api/master-setting/:code)。MASTER_SETTING も拒否されます
マスターデータの settingCodeデータの作成、upsert、両方のバルクエンドポイント、MasterDataService.list(GET /api/master-data)。MASTER_SETTING も拒否されます
マスターデータの codeデータの作成、upsert、バルク
userId / groupIdグループ設定とユーザー設定(グループまたはユーザーを対象とする POST /api/master-setting)
@ を含むソートキーPATCH/DELETE /api/master-setting/:pk/:sk と PUT/DELETE /api/master-data/:pk/:sk

@ を拒否する理由: コマンドサービスは @ をソートキーのバージョン区切り文字として扱います。1.7.0 では core がソートキーを最後の @ で切り詰めていたため:

  • e-mail アドレスを userId やコードに使うなど、@ を 1 つ含む値は、切り詰められた別のキーに黙って保存されていました。
  • @ を 2 つ以上含むコード(例: X@Y@Z)では、キーに @ が残ったままの行(例: MASTER_SETTING#X@Y)が保存される可能性がありました。

# を拒否する理由: # はキーセグメントを区切るため、USER#u1#S1 のようなコードは別の行のキー(この例ではユーザーの個人設定)を構成していました。

キーに @ を含む既存の行

ソートキーに @ を含む形ですでに保存されている行は、マスター API から読み取り・更新・削除できなくなります。該当する行を見つけて、有効なキーで再作成してください:

  • DynamoDB: マスターのデータテーブル(ソートキーがバージョンサフィックスで終わるコマンドテーブルではない)をスキャンし、sk に @ を含む項目を探します。
  • RDS: マスターテーブルで sk に @ を含む行をクエリします。

有効なコードで新しい設定行またはデータ行を作成して値を移し、不要になった古い行はデータベース上で直接論理削除または削除してください。切り詰められたキーで書き込まれた行(例: e-mail アドレスの最後の @ より前の部分に対して保存されたユーザー設定)も確認してください。

code に # を含む形ですでに保存されているマスターデータ行は引き続き読み取り可能で、/api/master-data/:pk/:sk からキー指定で更新・削除もできますが、そのようなコードを送信する作成や upsert は拒否されます。

# や @ を含むコード、ユーザー ID、グループ ID を生成する連携処理を変更してください。たとえば userId には e-mail アドレスではなく Cognito の sub を使用します。

ステップ 3: 更新と削除に正しいルートを使用する​

設定行とデータ行は、それぞれ専用のルートでのみ変更されるようになりました:

ルート受け付けるキー400 で拒否するキー
PATCH/DELETE /api/master-setting/:pk/:skMASTER_SETTING#<code>、および MASTER_SETTING#USER#u1#S1 のようなグループ・ユーザーのキーデータのキー
PUT/DELETE /api/master-data/:pk/:skデータのキー <settingCode>#<code>MASTER_SETTING#... のキー

同じルールが MasterSettingService.updateSetting/deleteSetting と MasterDataService.update/delete にも適用されます。

ステップ 4: マスターコピーを確認する​

2 つの修正により、すべてのアプリケーションでマスターコピーの結果が変わります:

  • コピーはコピー元の設定のテナントからデータを読み取るようになりました。以前はハードコードされた meltec テナントから読み取っていました。
  • コピーはシーケンスもコピーするようになりました。コピー元より遅れているコピー先のシーケンスは、コピー元の値まで進みます。書き込みは条件付きのため、その間に採番したコピー先が巻き戻されることはありません。

コピーには次の制限も加わりました:

  • controllerAuth を設定している場合、POST /api/master-setting/copy には controllerAuth.write に関係なく system_admin が必要です。
  • リゾルバーを登録している場合、MasterSettingService.copy には system_admin と、systemId と settingCode がともに * の書き込み権限(grant)が必要です。system_admin により狭い grant を返すリゾルバーではコピーできません。
  • コピーでは、system_admin は custom:roles クレームから得られる必要があります。グループから導出されたロールは対象外です。

ステップ 5: バルクのアトミック性を前提にしない​

POST /api/master-bulk は設定を先に、データ行を後に upsert するようになったため、データ行は同じリクエストで作成された設定を使用できます。すべての項目のキーは最初の書き込みの前に検証されます。

アトミックではありません

リゾルバーを登録している場合、データ項目のアクセスチェックは設定が書き込まれた後に実行されます。呼び出し元が書き込めないデータ項目があるとリクエストは 403 で失敗しますが、同じリクエストの設定は書き込まれたまま残ります。書き込まれた内容を正確に把握する必要がある場合は設定とデータを別々のリクエストに分け、リトライを冪等にしてください(このエンドポイントは upsert です)。

ステップ 6: その他の動作変更を確認する​

  • タスク親ルート: GET /api/tasks/sfn-task-parent は、まず custom:tenant クレームから、次に x-tenant-code からテナントを取得するようになりました。以前は誰も設定しない custom:tenant_code クレームを読み取っていたため、常にヘッダーの値を使用していました。
  • 部分更新: settingValue を省略した設定の更新で設定の attributes がクリアされなくなり、name を省略した更新では名前が保持され、seq を省略したデータの更新では seq が保持されます。
  • 予約属性: クライアントが attributes で送信した __systemId キーは常に削除されます。レスポンスは toPublicRow を通るため、クライアントが埋め込んだ __systemId を持つ以前に保存された行は、その値をトップレベルの systemId として返します。
  • 新しいルートとフィールド: コントローラーが有効な場合は GET /api/master-access が追加され、DTO は systemId と includeCommon を受け付けます。リゾルバーがない場合、systemId は無視されます。
  • MySQL: 一覧検索が MySQL で動作するようになりました。dist ファイルから mode: 'insensitive' を取り除くパッチ(例: patch-package によるもの)は削除してください。データベースは Prisma クライアントから検出されます。検出できなかったという起動時の警告が出る場合は、MasterModule.register または SurveyTemplateModule.register(またはそれらの registerAsync)で databaseProvider を設定してください。データベースプロバイダー を参照してください。

アクセス制御の導入(任意)​

controllerAuth もリゾルバーも設定しないアプリケーションは、ステップ 6 で完了です。組み込みルートを保護し、マスターデータをシステム単位にスコープするには、以下の展開順序に従ってください。マスター: アクセス制御 と、フレームワークガイド Master data access control and per-system sync を参照してください。

  1. MasterModule に controllerAuth を設定します。空のオブジェクトでもガードが有効になり、読み取りにはログインが、書き込みには system_admin が必要になります。コントローラー認可 を参照してください。
  2. RDS カラムを追加します: Prisma の Master モデルに NULL 許容の system_id カラムを追加し、RDS ハンドラーの create と update の両方で systemId: getSystemId(cmd) を書き込んでから、マイグレーションを実行してデプロイします。update-scheme.ts は既存のスキーマやハンドラーを変更しません。RDS system_id カラム を参照してください。
  3. フロントエンドパッケージをアップグレードしてから、@MasterAccessResolver() でリゾルバーを登録します。リゾルバーを登録した状態で Prisma の Master モデルに systemId フィールドがないと、アプリケーションは起動しません。
  4. マスターサービスを呼び出すサーバー側コードから invokeContext を渡すか、信頼できる内部処理では skipAccessCheck: true を渡します。リゾルバーを登録している場合、invokeContext のない呼び出しは読み取りも含めて拒否されます。
  5. MasterSettingService.assignSystem で既存データにタグ付けします。タグのない行は shared として扱われます。

また、リゾルバーを登録している場合は次の点にも注意してください:

  • systemId を持たない共通設定に対してテナントレベルのオーバーライドを作成すると、その設定は shared として扱われます。shared 以外の systemId を指定すると 400 で拒否され、shared への書き込み権限が必要で、オーバーライドには systemId が保存されません。
  • includeCommon には上限があります: includeCommon を指定したマスターデータ一覧は、呼び出し元が共通テナントでない限り settingCode が必須で、一致する行を 10,000 件より多く持つテナントには 400 が返ります。共通テナントの行を含める を参照してください。

registerAsync では、commonTenantCode、databaseProvider、controllerAuth を静的に渡してください。静的な値は、値が undefined であってもファクトリーが返す値を上書きします。

ヘッダーで共通テナントを指定した場合に 403 になる可能性

controllerAuth を設定している場合、トークンに custom:tenant クレームがなく x-tenant-code で共通テナントを指定した呼び出し元は、commonTenantCode が環境変数 COMMON_TENANT_CODES に含まれていないと 403 になる可能性があります。基底ガードのテナント上書きチェックが、モジュールオプションではなくこの環境変数を読み取るためです。commonTenantCode を変更する場合は、同じ値を COMMON_TENANT_CODES にも追加してください。

プロジェクトテンプレート(新規プロジェクトのみ)​

ファイル変更前変更後(v1.8.0)
src/master/master.module.tscontrollerAuth なし空の controllerAuth オブジェクト: マスターの書き込みに system_admin が必要
prisma/schema.prisma (Master モデル)-system_id にマッピングされた NULL 許容の systemId と、tenantCode と systemId のインデックス
src/master/handler/master-rds.handler.ts-systemId: getSystemId(cmd) を書き込む

既存のプロジェクトは変更されません。

ステップ 7: テストを実行してデプロイする​

npm run test:cov

サポート​

移行中に問題が発生した場合:

関連ドキュメント​