fitness-functions について
EventCatalog Fitness Functions は、EventCatalog のカタログに対するアーキテクチャルールを TypeScript のチェックとして定義するスキルです。違反を報告し、CLI の終了コードでプルリクエストを制御できます。対象はカタログに記録された情報で、稼働中のシステムではありません。
主な機能
- 01TypeScript によるアーキテクチャルール
- 02読み取り専用カタログ SDK のクエリ
- 03リソース参照付き違反レポート
- 04エラーと警告の重大度
- 05プルリクエスト制御用 CLI チェック
活用シーン
- 01ドメイン所有権の境界ルールの適用
- 02カタログリソース間の依存関係の確認
- 03所有者やメッセージチャネルの不足検出
- 04CI でのカタログ変更の制御
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ event-catalog/ skills --skill fitness-functionsインストール後、Claude Code で/fitness-functionsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api.mdci.mdexamples.md詳細
EventCatalog フィットネス関数
フィットネス関数は、コードで記述されたアーキテクチャルールです。それぞれの関数は、読み取り専用 SDK を通じてカタログを読み取る TypeScript ファイルで、見つかった違反を返します。eventcatalog fitness check はすべての関数を実行し、結果を出力して JSON レポートを書き込み、ルールに違反がある場合はゼロ以外の終了コードを返すため、プルリクエストのチェックに使用できます。
健全なアーキテクチャの定義はチームが決め、EventCatalog はルールを実行して結果を報告します。
フィットネス関数がチェックするのは、カタログに記述されたアーキテクチャであり、実行中のシステムではありません。ルールの精度は、読み取るカタログデータの精度に左右されます。
要件(最初に確認してください)
- バージョン —
@eventcatalog/core5.4.0 以降(カタログのpackage.jsonを確認してください)。代わりに@eventcatalog/cli1.4.0 以降を使えば、core なしで同じチェックを実行できます(npx @eventcatalog/cli fitness check)。Node.js 20 以降が必要です。 - エディターの型情報(任意) — フィットネス関数はほかに何もインストールせずに実行できますが、型情報と自動補完を利用するには、開発用依存関係として
@eventcatalog/fitnessをインストールしてください。create-eventcatalogで作成したカタログには、すでにこれが含まれており、fitness/内にスターター関数が 2 つ、npm run fitnessスクリプトも用意されています。
フィットネス関数、リンター、それともガバナンス?
コードを書く前に、適切なツールを選んでください。
| ルールの対象… | 使用するもの |
|---|---|
| 単一ファイルの妥当性:frontmatter のフィールド、必須プロパティ、参照切れ、ファイルレイアウト | @eventcatalog/linter |
| プルリクエストで変更された内容(新しいコンシューマー、スキーマの変更、非推奨化)と通知 | eventcatalog governance check(governance.yaml) |
| アーキテクチャの構造:所有権、命名、境界、依存関係、アクセス権限など、複数のリソースにまたがるもの | フィットネス関数(このスキル) |
手順
ステップ 1:カタログと既存の内容を確認する
カタログ(eventcatalog.config.js があるフォルダー)を探し、以下を確認してください。
- ルートに
fitness/フォルダーがあるか、またはリソースフォルダー内にfitness/フォルダーがあるか。既存の関数を読み、ヘルパーを再利用してスタイルを合わせ、重複するルールを作成しないでください。 - フィットネス関数の ID は、カタログ全体で一意でなければなりません。すでに使われている ID を一覧にしてください。
package.jsonにfitnessスクリプトがあるか。@eventcatalog/fitnessがインストールされているか。.eventcatalog/fitness/が.gitignoreに含まれているか。このフォルダーにはチェック結果のレポートが書き込まれるため、コミットしないようにしてください。
ステップ 2:ルールを具体的なチェックにする
「サービスは自分のデータを所有するべき」といったルールは曖昧すぎて、コードにできません。明確でない場合はユーザーに確認し、以下を具体化してください。
- 何が違反にあたりますか?(「サービスが、別のドメインに属するシステムのデータストアに書き込んでいる。」)
- どのリソースに適用しますか? すべて、1 つのドメイン、1 つのシステム、または 1 つのサービスですか?
- 最新バージョンのみですか、それともすべてのバージョンですか? ほとんどの場合、最新バージョンのみです(
{ latestOnly: true })。 - 重要度 —
errorはチェックを失敗させます(CI も失敗します)。warningは報告されますが、チェックは失敗しません。違反が多数見つかりそうな既存のカタログに新しいルールを導入する場合は、まずwarningに設定し、後から厳格化してください。 - 各違反の対象を何にし、どのように修正すべきですか? 各違反では、関係するリソースを明示し、修正方法を提案してください。
カタログデータでルールをチェックできることを確認してください。ルールで writesTo、owners、sends.to が必要なのにカタログに記載されていない場合は、その旨を伝えてください。その場合、ルールは実質的に何もチェックせずに合格してしまいます。
ステップ 3:ファイルの配置場所を選ぶ
ファイルの配置場所によって、割り当てられる resource が決まります。参照できる内容が制限されるわけではありません。すべての関数がカタログ全体を照会できます。
| ルールの適用対象 | 配置先 | resource の値 |
|---|---|---|
| カタログ全体 | fitness/<name>.fitness.ts(サブフォルダー可) | undefined |
| 1 つのドメイン | domains/Orders/fitness/<name>.fitness.ts | Orders ドメイン |
| 1 つのシステム | …/systems/checkout-system/fitness/<name>.fitness.ts | そのシステム |
| 1 つのサービス | …/services/OrderService/fitness/<name>.fitness.ts | そのサービス |
| 1 つのイベント、コマンド、またはクエリ | …/events/OrderCreated/fitness/<name>.fitness.ts | そのメッセージ |
| 1 つのデータストア | …/containers/payment-database/fitness/<name>.fitness.ts | そのデータストア(type: 'container') |
| 1 つの特定のバージョン | …/versioned/1.0.0/fitness/<name>.fitness.ts | そのバージョン |
チャネル、フロー、エンティティ、データプロダクト、ADR、図も同じように機能します。ルールは次のとおりです。
.fitness.tsで終わるファイルのみが実行されます。その他の.tsファイル(共有ヘルパー)は実行されないため、フィットネス関数からインポートできます。fitness/フォルダーは、リソースのフォルダー内に直接配置する必要があります(index.mdxと同じ階層)。それ以外の場所にある.fitness.tsファイルは実行されず、診断として報告されます。- フェデレーションカタログ(
federated/…)内のフィットネス関数は実行されず、フェデレーションによってfitness/フォルダーがコピーされることもありません。
ステップ 4:フィットネス関数を書く
// domains/Orders/fitness/no-shared-data-stores.fitness.ts
import { defineFitnessFunction } from '@eventcatalog/fitness';
export default defineFitnessFunction({
id: 'orders-no-shared-data-stores', // unique across the catalog
name: 'Orders services only use Orders data stores',
description: 'Reaching into another domain’s database couples the domains together.',
severity: 'error', // or 'warning'; defaults to 'error'
async run({ resource, catalog }) {
if (resource?.type !== 'domain') throw new Error('Expected to run beside a domain');
// ...read what you need from `catalog`, decide what's wrong...
return [
{
message: 'Order Service writes to payment-database, which is outside the Orders domain',
resources: [
{ type: 'service', id: 'order-service', version: '1.0.0' },
{ type: 'container', id: 'payment-database' },
],
details: 'Optional extra context',
suggestion: 'Get payment data through the Payments API or its events.',
},
]; // [] means the rule passed
},
});
フィットネス関数を作成する際の規約:
export default defineFitnessFunction({ ... })— 1 ファイルにつき関数は 1 つです。runは同期でも非同期でもかまいません。- 違反をスローせず、返します。 空の配列は合格を意味します。スローした場合、または
{ message, resources?, details?, suggestion? }の配列以外を返した場合、関数はerrorとなり、チェックも失敗します。ただしこれは「アーキテクチャに問題がある」ではなく、「評価できなかった」ことを意味します。 typeでresourceを絞り込みます(resource?.type === 'domain'によって型付きの Domain が得られます)。ファイルの配置場所が間違っている場合は、明確なエラーをスローします。catalogの読み取りメソッドを使用します — 名前と引数は@eventcatalog/sdkと同じです。例:getDomains、getServices、getEvents、getDataStores、getTeams、getGraph、getOwnersForResource、getSchemaForMessage、getResourcesByProperty、… コレクションを取得するメソッドは、該当するものがない場合undefinedを返すため、(await catalog.getEvents({ latestOnly: true })) ?? []のように記述します。書き込みメソッドはありません。また、呼び出すたびにコピーが返されるため、結果を変更しても問題ありません。全一覧はreferences/api.mdを参照してください。- コレクションは一度だけ読み込み、ルックアップを作成します(マップまたはセットを使用)。ループ内でカタログを呼び出すのは避けてください。たとえば、メッセージごとに
getProducersAndConsumersForMessageを呼び出すのではなく、すべてのサービスのsendsを一度に収集します。 - 各違反でリソースを参照します。
{ type, id, version? }を指定してください。EventCatalog では違反からリソースへのリンクが設定されます。型:domain、system、service、agent、event、command、query、flow、channel、entity、container(dataStoreも指定できます)、data-product、adr、diagram、team、user。 - 読んだ人が行動に移せるメッセージを書きます:リソース名を含め(
Order Service sends Order Amended without a channel)、修正方法はsuggestionに記載します。 - 共有ロジックはヘルパーファイルに記述します(例:
fitness/helpers/catalog.ts)。相対パスでインポートしてください。型はimport type { ReadOnlyCatalog } from '@eventcatalog/fitness'でインポートします。 - 決定性を保ちます:ネットワーク呼び出し、ファイルへの書き込み、現在の日付への依存は禁止です。
一般的なルール(所有権、命名、プロデューサー、循環依存、ドメイン境界、ファンアウト、チャネル、スキーマ、データアクセス)の実例は、references/examples.mdを参照してください。
ステップ 5:実行して検証する
npx eventcatalog fitness check # or: npm run fitness
npx eventcatalog fitness check --format json
出力には、すべての関数とその結果が一覧表示され、その下に違反とエラーが表示されます。
EventCatalog Fitness
✓ Every message has an owner Passed
✗ orders / Orders services only use Orders data… 1 violation
• Order Service writes to payment-database, which is outside the Orders domain
Resources: order-service (service), payment-database (container)
Suggestion: Get payment data through the Payments API or its events.
! Every event has a producer 3 warnings
3 fitness functions evaluated
引き渡す前に検証してください。決して失敗しないルールは、ルールがないよりも悪いものです。
- 新しい関数が実行されたことと、想定どおりのステータスであることを確認します。
Errorと表示された場合は修正してください(「トラブルシューティング」を参照)。 - 結果が正しいことを確認します。カタログファイルを手作業で確認し、違反と合格の両方をいくつか照合します。
- 失敗する可能性があることを確認します。現在のカタログで合格する場合は、実際の違反を検出できることを確認します。ユーザーと一緒に考えるか、カタログのスクラッチコピー内でリソースを壊し、そのコピーでチェックを実行してください。テストによる編集をユーザーのカタログに残さないでください。
- 参照が解決されることを確認します。
(…, not found in the catalog)と表示される参照は、型または ID が誤っています。
終了コード:0 すべて合格、または警告のみ、1 関数が失敗したか評価できなかった、2 チェック自体を実行できなかった
ステップ 6:CI で実行する
依存関係をインストールした後、カタログの変更をチェックするパイプラインで npx eventcatalog fitness check を実行します。ルールが失敗すると 1 で終了し、ジョブが失敗します。GitHub Actions、GitLab、レポート公開の例については、references/ci.md を参照してください。
トラブルシューティング
| 症状 | 原因/修正方法 |
|---|---|
| 関数がまったく一覧に表示されない | ファイル名が .fitness.ts で終わっていない、fitness/ フォルダー内にない、または federated/、node_modules、dist、ドットフォルダーの下にある |
! <file>: Not run: fitness functions must be in a fitness/ folder | ファイルをルート、またはリソースのフォルダー直下にある fitness/ フォルダーへ移動します |
No resource found for this fitness function: '<folder>' has no index.mdx or index.md | fitness/ フォルダーがリソースのフォルダー直下にありません |
… is not in a resource folder (such as domains/ or services/) | fitness/ を含むフォルダーが、認識されたリソースフォルダーではありません |
The file has no default export | export default defineFitnessFunction({ ... }) を追加します |
Invalid fitness function: \id` must be a non-empty string, …` | id/name/run がないか、severity が 'error' または 'warning' ではありません |
Another fitness function already has the id '<id>' | ID は一意である必要があります。最初のファイル(パス順)が実行され、それ以降のファイルはエラーになります |
run() must return an array of violations … / Violation 0: … | run が別の値を返したか、違反に message がない、または resources のエントリーに誤りがあります |
Cannot find module './helpers/…' | ヘルパーへの相対パスが誤っています。カタログルートまで何階層上がるか数えてください |
リソースの後に (…, not found in the catalog) と表示される | 参照の type または id がリソースと一致しません。参照は保持されますが、リンクされません |
エディター内だけで Cannot find module '@eventcatalog/fitness' と表示される | @eventcatalog/fitness を開発用依存関係としてインストールします。チェック自体はインストールなしで動作します |
fitness is not a command | @eventcatalog/core が 5.4.0 より古い状態です。アップグレードするか、npx @eventcatalog/cli fitness check を使用してください |
信頼性
Fitness 関数はカタログ内のコードであり、プロジェクト内の他のスクリプトと同じアクセス権で実行されます。ローカルでも CI でも、信頼できる Fitness 関数だけを実行してください。EventCatalog は、ブラウザー内、ページリクエスト時、またはフェデレーションされたカタログから関数を実行することはありません。
リファレンスファイル
- references/api.md —
defineFitnessFunction、コンテキスト、すべてのcatalogメソッド、違反、ステータス、JSON レポート、CLI オプション、検出ルール - references/examples.md — 共通ルールに対応する、共有ヘルパーを使ったグローバルおよびスコープ指定の Fitness 関数の完全な例
- references/ci.md — GitHub Actions と GitLab でのチェック実行、レポート公開、JSON 出力の読み取り