mcpField
V
vendure-developing

vendure-developing

github.com/meriley開発41 回インストール
リポジトリ

vendure-developing について

Vendure Developmentは、Vendureプロジェクトの開発やレビューを行う開発者向けの入口スキルです。アーキテクチャの資料や実装パターンを示し、vendure-expertエージェントを通じた専門スキルの連携を案内します。

主な機能

  1. 01Vendureの6領域に関するクイックリファレンス
  2. 02プラグインとGraphQLの実装パターン
  3. 03エンティティとデータベースの実装ガイド
  4. 04Admin UI拡張パターン
  5. 05vendure-expertによる専門スキルの連携

活用シーン

  1. 01Vendureプラグインの実装を開始
  2. 02ShopまたはAdmin GraphQL APIを拡張
  3. 03エンティティとデータベースマイグレーションを作成
  4. 04セキュリティと規約に沿ってプラグインコードをレビュー

MCP 対応

READMEにはMCP風のツール名を使ったContext7ドキュメントへのアクセスが記載されていますが、このスキルをMCPサーバーまたはクライアントとは説明していません。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/meriley/claude-code-skills --skill vendure-developing

インストール後、Claude Code で/vendure-developingを入力して読み込まれたか確認します。

詳細

Vendure 開発

目的

Vendure 開発タスクすべてのエントリーポイントです。vendure-expert エージェントによる複数ドメインにわたる協調的なガイダンスのための、クイックリファレンスとガイドを提供します。

使用しない場合

  • Vendure 以外の EC プラットフォーム(Shopify、Magento など)
  • Vendure のコンテキストを伴わない基本的な TypeScript/NestJS
  • Vendure Admin UI を使用しない、フロントエンドのみの React

クイックスタート:エージェントを使用する

Vendure に関する包括的なガイダンスには、vendure-expert エージェントを使用してください。

Task(subagent_type: "vendure-expert", prompt: "Your Vendure task here")

このエージェントは、9 つの専門スキルを統括します。

  • プラグイン開発(作成+レビュー)
  • GraphQL API(作成+レビュー)
  • エンティティ/データベース(作成+レビュー)
  • Admin UI(作成+レビュー)
  • 配送/出荷機能(専門)

Vendure アーキテクチャのクイックリファレンス

6 つのコアドメイン
ドメイン主な概念
プラグイン@VendurePlugin、NestJS DI、ライフサイクルフック
GraphQL2 つの API(Shop/Admin)、RequestContext、gql テンプレート
エンティティVendureEntity、TypeORM、マイグレーション、カスタムフィールド
Admin UIReact/Angular、UI DevKit、遅延読み込み
ストラテジーInjectableStrategy、カスタムロジック
イベントEventBus、トランザクションセーフなサブスクリプション
プラグインのスキャフォールド
import { PluginCommonModule, VendurePlugin } from "@vendure/core";

@VendurePlugin({
  imports: [PluginCommonModule],
  providers: [MyService],
  entities: [MyEntity],
  adminApiExtensions: {
    schema: gql`...`,
    resolvers: [MyResolver],
  },
})
export class MyPlugin {
  static init(options: MyPluginOptions) {
    this.options = options;
    return MyPlugin;
  }
}
GraphQL リゾルバーパターン
import { Ctx, RequestContext, Query, Resolver } from "@vendure/core";
import { Allow, Permission } from "@vendure/core";

@Resolver()
export class MyResolver {
  constructor(private myService: MyService) {}

  @Query()
  @Allow(Permission.ReadSettings)
  async myQuery(@Ctx() ctx: RequestContext): Promise<MyType[]> {
    return this.myService.findAll(ctx);
  }
}
エンティティパターン
import { VendureEntity, DeepPartial } from "@vendure/core";
import { Entity, Column, ManyToOne } from "typeorm";

@Entity()
export class MyEntity extends VendureEntity {
  constructor(input?: DeepPartial<MyEntity>) {
    super(input);
  }

  @Column()
  name: string;

  @ManyToOne(() => OtherEntity)
  relation: OtherEntity;
}
Admin UI 拡張
// providers.ts
import { addNavMenuSection } from "@vendure/admin-ui/react";

export default [
  addNavMenuSection(
    {
      id: "my-section",
      label: "My Feature",
      items: [
        {
          id: "my-page",
          label: "My Page",
          routerLink: ["/extensions/my-feature"],
          icon: "cog",
        },
      ],
    },
    "settings",
  ),
];

禁止パターン

プラグイン開発
  • @VendurePlugin デコレーターがない
  • NestJS DI(@Injectable)を使用していない
  • プラグイン設定を使わず、値をハードコードしている
  • サービスを迂回してデータベースに直接アクセスしている
GraphQL
  • @Ctx() RequestContext パラメーターがない
  • @Allow() 権限デコレーターを迂回している
  • Shop/Admin のスキーマ型を混在させている
  • gql テンプレートリテラルを使用していない
エンティティ
  • VendureEntity を継承していない
  • @Entity() デコレーターがない
  • マイグレーションファイルが作成されていない
  • any 型を使用している
Admin UI
  • ルートを遅延読み込みしていない
  • 文字列をハードコードしている(i18n を使用していない)
  • 読み込み中/エラー状態がない
  • 権限を処理していない

必須パターン

RequestContext の受け渡し
// ALWAYS pass ctx through service calls
async myResolver(@Ctx() ctx: RequestContext) {
  return this.service.findAll(ctx);  // Pass ctx!
}
権限デコレーター
@Query()
@Allow(Permission.ReadCatalog)  // ALWAYS specify permissions
async products(@Ctx() ctx: RequestContext) { }
エンティティ入力型
// Use DeepPartial for constructor input
constructor(input?: DeepPartial<MyEntity>) {
  super(input);
}
InputMaybe の処理
// Check BOTH undefined AND null for GraphQL inputs
if (input.field !== undefined && input.field !== null) {
  entity.field = input.field;
}

ドメインスキルの判断ツリー

Task Type
    │
    ├─> Creating/modifying plugin structure
    │   └─> vendure-plugin-writing
    │
    ├─> Reviewing plugin code
    │   └─> vendure-plugin-reviewing
    │
    ├─> Extending GraphQL schema or resolvers
    │   └─> vendure-graphql-writing
    │
    ├─> Reviewing GraphQL code
    │   └─> vendure-graphql-reviewing
    │
    ├─> Creating/modifying entities
    │   └─> vendure-entity-writing
    │
    ├─> Reviewing entity definitions
    │   └─> vendure-entity-reviewing
    │
    ├─> Building Admin UI components
    │   └─> vendure-admin-ui-writing
    │
    ├─> Reviewing Admin UI code
    │   └─> vendure-admin-ui-reviewing
    │
    └─> Delivery/shipping features
        └─> vendure-delivery-plugin

一般的なパターン

2 つの API の分離
// Admin API - full access
export const graphqlAdminSchema = gql`
  extend type Query {
    myAdminQuery: [MyType!]!
  }
  extend type Mutation {
    updateMyType(input: UpdateInput!): MyType!
  }
`;

// Shop API - customer-facing, read-only or limited
export const graphqlShopSchema = gql`
  extend type Query {
    myPublicQuery: [MyType!]!
  }
`;
RequestContext を使用するサービスパターン
@Injectable()
export class MyService {
  constructor(private connection: TransactionalConnection) {}

  async findAll(ctx: RequestContext): Promise<MyEntity[]> {
    return this.connection.getRepository(ctx, MyEntity).find();
  }

  async create(ctx: RequestContext, input: CreateInput): Promise<MyEntity> {
    const entity = new MyEntity(input);
    return this.connection.getRepository(ctx, MyEntity).save(entity);
  }
}
トランザクションデコレーター
@Mutation()
@Transaction()  // Wrap in database transaction
@Allow(Permission.UpdateSettings)
async updateMyEntity(
  @Ctx() ctx: RequestContext,
  @Args() { input }: { input: UpdateInput }
): Promise<MyEntity> {
  return this.service.update(ctx, input);
}

例

例 1:シンプルなプラグインを作成する

タスク: 商品の閲覧数を記録するプラグインを作成します。

アプローチ:

  1. プラグインのスキャフォールドには vendure-plugin-writing を使用します
  2. ProductView エンティティには vendure-entity-writing を使用します
  3. クエリ拡張には vendure-graphql-writing を使用します

結果:

@VendurePlugin({
  imports: [PluginCommonModule],
  entities: [ProductViewEntity],
  providers: [ProductViewService],
  shopApiExtensions: {
    schema: gql`
      extend type Query {
        productViews(productId: ID!): Int!
      }
    `,
    resolvers: [ProductViewResolver],
  },
})
export class ProductViewsPlugin {}
例 2:Admin UI ページを追加する

タスク: プラグイン設定を管理する設定ページを追加します。

アプローチ:

  1. React コンポーネントには vendure-admin-ui-writing を使用します
  2. ルートとナビゲーション項目を登録します
  3. API 呼び出しには DataService を使用します

結果:

// pages/SettingsPage.tsx
export function SettingsPage() {
  const dataService = useInjector(DataService);
  const [settings, setSettings] = useState<Settings>();

  useEffect(() => {
    dataService
      .query(GetSettingsDocument)
      .stream$.subscribe((result) => setSettings(result.mySettings));
  }, []);

  return <SettingsForm settings={settings} />;
}
例 3:プラグインコードをレビューする

タスク: セキュリティとベストプラクティスについてプラグインを監査します。

アプローチ:

  1. プラグイン構造には vendure-plugin-reviewing を使用します
  2. リゾルバーパターンには vendure-graphql-reviewing を使用します
  3. データベースパターンには vendure-entity-reviewing を使用します

確認項目:

  • すべてのサービス呼び出しで RequestContext が渡されている
  • すべてのリゾルバーに権限が宣言されている
  • データベースへの直接クエリがない(TransactionalConnection を使用する)
  • 適切なエラー処理が行われている

トラブルシューティング

問題原因解決策
エンティティが見つからないプラグインのエンティティ配列に含まれていない@VendurePlugin({ entities: [] }) に追加します
リゾルバーが呼び出されないresolvers 配列に含まれていないapiExtensions.resolvers に追加します
権限が拒否される@Allow デコレーターが不足しています@Allow(Permission.X) を追加します
TypeScript エラーインポートパスが間違っています@vendure/core からインポートします
Admin UI が読み込まれない遅延読み込みされていませんルートに React.lazy() を使用します

外部ドキュメント

Context7(推奨)
mcp__context7__get-library-docs
context7CompatibleLibraryID: "/vendure-ecommerce/vendure"
topic: "plugins" or "entities" or "graphql" etc.
公式ドキュメント

関連するエージェント

Vendure を複数のドメインにわたって包括的にガイドするには、vendure-expert エージェントを使用してください。

このエージェントは、Vendure の 9 つすべてのスキルを連携させ、以下を提供します。

  • プラグインのライフサイクルに関する包括的なガイダンス
  • セキュリティと品質の監査
  • ベストプラクティスの徹底
  • ドメイン固有のパターン

コメント