> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 50 ファイルを REST から GraphQL へ移行する

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="50ファイルをRESTからGraphQLへ移行する" description="50ファイル分のRESTからGraphQLへの移行範囲を決め、競合のない作業パッケージに分割し、管理対象のDevinで一括実行します。" prompt="コードベース全体を解析し、レガシーRESTクライアントを使用しているすべてのファイルを特定してください。互いに競合しないように、それらを独立した作業パッケージにグループ化し、その後、各パッケージごとに並列のDevinセッションを開始して、新しいGraphQLクライアントへの移行を行ってください。" category="移行" features="高度, プレイブック" agent="advanced" intent="batch" />

<div className="uc-detail-wrapper">
  <Tip>手動でのセットアップが面倒ですか？このページのリンクを Devin のセッションに貼り付けて、すべてのセットアップを依頼してください。</Tip>

  <Steps>
    <Step title="Ask Devin で移行範囲を定義する">
      `src/lib/restClient.ts` からインポートしているファイルが 50 個あり、それらを新しい `graphqlClient` に移行する必要があります。作業を分担して進める前に、これらのファイル同士がどうつながっているかを把握する必要があります。[Ask Devin](/ja/work-with-devin/ask-devin) を使ってマイグレーションの対象範囲をマッピングします。どのファイルがレガシークライアントをインポートしているか、それらがドメインごとにどうグルーピングされているか、リスクの高い結合がどこにあるかを洗い出します。Devin は内部で [DeepWiki](/ja/work-with-devin/deepwiki) とセマンティック検索を使っているため、実際のコードに基づいてこうした質問に答えることができます。

      <Tip>Ask Devin を利用するには、リポジトリが[インデックス済み](/ja/onboard-devin/index-repo)である必要があります。[**Settings > Repositories**](https://app.devin.ai/settings/repositories?utm_source=docs\&utm_medium=use-case-gallery) に移動してインデックス状況を確認するか、新しいリポジトリをインデックスしてください。</Tip>

      [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) を開き、次のように依頼します:

      <PromptBlock agent="ada">
        ```txt Scope the REST-to-GraphQL migration theme={null}
        How many files import from src/lib/restClient.ts? Group them by
        domain (user management, billing, analytics, notifications, auth,
        admin, search, onboarding, etc.) and flag any files that share
        state or have tight coupling across domains.
        Note which files have existing test coverage.
        ```
      </PromptBlock>

      Ask Devin は次のような内訳を返します:

      ```
      50個のファイルが8つのドメインにわたってrestClientをインポートしています:

        User Management  (7ファイル) — 独立、テストカバレッジ完全
        Billing          (9ファイル) — 独立、6/9テスト済み
        Analytics        (5ファイル) — 独立、3/5テスト済み
        Auth             (6ファイル) — 共有ミドルウェア、テストカバレッジ完全
        Notifications    (8ファイル) — 独立、5/8テスト済み
        Admin            (5ファイル) — Authミドルウェアに依存
        Search           (4ファイル) — 独立、2/4テスト済み
        Onboarding       (6ファイル) — 独立、4/6テスト済み

      結合に関する注意: AdminはAuthからrequireAuthをインポートしています。
      まずAuthを移行し、次にAdminを移行してください。他のドメインはすべて独立しています。
      ```

      これは、並列化する意味があるかどうかを判断するのに役立ちます。ほとんどのファイルがドメイン間で密結合されている場合は、順次マイグレーションの方が安全です。ここでは、8個のドメインのうち6個が完全に独立しているため、それらを並列に実行できます。
    </Step>

    <Step title="移行プレイブックを作成する">
      すべての並列セッションで同じ移行パターンに従うことで、最終的なPRが一貫したものになり、レビューしやすくなります。各ファイルをどのように移行するかを正確に定義した[プレイブック](/ja/product-guides/creating-playbooks)を作成してください。

      [**Settings > Playbooks > Create Playbook**](https://app.devin.ai/settings/playbooks/create?utm_source=docs\&utm_medium=use-case-gallery) に移動し、次の手順を定義します:

      <PromptBlock type="playbook">
        ```txt REST to GraphQL Migration theme={null}
        For each file assigned to you:

        1. Replace `import { restClient } from 'src/lib/restClient'`
           with `import { graphqlClient } from 'src/lib/graphqlClient'`
        2. Rewrite each API call to use the corresponding GraphQL
           query or mutation defined in src/graphql/operations/
        3. Update error handling from HTTP status codes to GraphQL
           error types (see src/lib/graphqlClient.ts for the error map)
        4. Update the corresponding test file:
           - Replace REST endpoint mocks with GraphQL mocks using msw
           - Assert on the GraphQL operation name, not the URL
        5. Run `npm run typecheck && npm test -- --related` to verify
        6. Open a PR titled: "migrate: [domain] REST → GraphQL"
        ```
      </PromptBlock>

      または Devin にプレイブックを生成させることもできます。移行パターンを説明すると、その内容に基づいて完全なプレイブックを生成します:

      <PromptBlock agent="advanced">
        ```txt Generate a REST-to-GraphQL migration playbook theme={null}
        Create a playbook for migrating files from our REST client
        (src/lib/restClient.ts) to our new GraphQL client
        (src/lib/graphqlClient.ts). Look at src/graphql/operations/ for
        the available queries and mutations. Include steps for updating
        imports, rewriting API calls, converting error handling from HTTP
        status codes to GraphQL error types, updating tests to use msw
        GraphQL mocks, and running typecheck + tests.
        ```
      </PromptBlock>

      このプレイブックをオーケストレーション用プロンプト内で参照することで、すべての並列セッションが、同じ開発者が作成したかのように見えるPRを生成できるようになります。
    </Step>

    <Step title="Devin で並列セッションを開始する">
      [Devin home page](https://app.devin.ai/?utm_source=docs\&utm_medium=use-case-gallery) から新しい Devin セッションを開き、オーケストレーション用のプロンプトを入力します。Devin はコードベースの依存関係グラフを解析し、独立した作業パッケージを作成して、パッケージごとに 1 つのセッションを起動し、それらをすべて同時に実行します。

      <PromptBlock agent="advanced" intent="batch">
        ```txt Parallelize REST-to-GraphQL migration across 50 files theme={null}
        Analyze our codebase and find every file that imports from
        src/lib/restClient.ts. Map the dependency graph between these
        files to identify groups that can be migrated independently —
        no two groups should modify the same file or share mutable state.

        For each independent group, start a parallel Devin session using
        the "REST to GraphQL Migration" playbook. Each session should:
        - Migrate only its assigned files
        - Run typecheck and tests for its scope
        - Open a separate PR

        Before starting sessions, show me the proposed grouping so I can
        approve it. Include file counts and estimated complexity per group.
        ```
      </PromptBlock>

      Devin は、何かを起動する前に、承認のためのグルーピング案を提示します:

      ```
      提案された作業パッケージ（8グループ、合計50ファイル）:

      グループ1 — ユーザー管理（7ファイル、複雑度: M）
        src/services/UserService.ts, src/pages/Profile.tsx,
        src/pages/Settings.tsx, src/hooks/useCurrentUser.ts,
        src/pages/UserDirectory.tsx, src/services/AvatarService.ts,
        src/components/UserCard.tsx

      グループ2 — 請求（9ファイル、複雑度: L）
        src/services/BillingService.ts, src/services/InvoiceService.ts,
        src/services/SubscriptionService.ts, src/pages/Checkout.tsx,
        src/pages/PlanSelector.tsx, src/pages/InvoiceHistory.tsx,
        src/components/PaymentForm.tsx, src/hooks/useSubscription.ts,
        src/components/PricingTable.tsx

      グループ3 — 分析（5ファイル、複雑度: S）
        src/services/AnalyticsService.ts, src/pages/Dashboard.tsx,
        src/components/MetricsCard.tsx, src/hooks/useMetrics.ts,
        src/components/ChartPanel.tsx

      グループ4 — 認証（6ファイル、複雑度: L）⚠ 最初に移行
        src/services/AuthService.ts, src/middleware/requireAuth.ts,
        src/middleware/refreshToken.ts, src/pages/Login.tsx,
        src/pages/Signup.tsx, src/services/SessionService.ts

      グループ5 — 通知（8ファイル、複雑度: M）
        src/services/NotificationService.ts, src/services/EmailService.ts,
        src/services/PushService.ts, src/pages/NotificationPreferences.tsx,
        src/components/NotificationBell.tsx, src/hooks/useNotifications.ts,
        src/components/NotificationToast.tsx, src/services/WebhookService.ts

      グループ6 — 管理（5ファイル、複雑度: M）⚠ 認証に依存
        src/pages/AdminDashboard.tsx, src/pages/AdminUsers.tsx,
        src/services/AdminService.ts, src/components/AdminSidebar.tsx,
        src/middleware/requireAdmin.ts

      グループ7 — 検索（4ファイル、複雑度: S）
        src/services/SearchService.ts, src/pages/SearchResults.tsx,
        src/components/SearchBar.tsx, src/hooks/useSearch.ts

      グループ8 — オンボーディング（6ファイル、複雑度: M）
        src/services/OnboardingService.ts, src/pages/Welcome.tsx,
        src/pages/SetupWizard.tsx, src/components/ProgressTracker.tsx,
        src/hooks/useOnboardingState.ts, src/services/ChecklistService.ts

      依存関係の注記: グループ6（管理）はグループ4（認証）からミドルウェアをインポートします。
      認証を最初に起動し、認証のPRがマージされた後に管理を起動します。
      残り6グループは直ちに並列で起動します。

      6つの並列セッションを今すぐ開始 + 2つを順次実行しますか？（y/n）
      ```

      グルーピングと 6 セッションの一括起動を承認してください。最初に Auth が実行され、Auth がマージされ次第 Admin が続きます。
    </Step>

    <Step title="結果をレビューしてマージする">
      各セッションはそれぞれ専用のPRを開きます。パッケージ同士は独立しているので、任意の順序でレビューとマージができますが、Admin が Auth に依存しているため、Auth を先にマージしてください。また、予期しない影響を検知するために、各マージ後には必ずフル CI を実行してください。

      8つすべての移行PRがマージされたら、後続のセッションでデッドコードをクリーンアップしてください:

      <PromptBlock>
        ```txt 移行後クリーンアップ theme={null}
        すべての REST から GraphQL への移行PRがマージされています。コードベースをスキャンし、次を確認してください:
        1. src/lib/restClient.ts をインポートしている箇所が残っていないか
        2. REST クライアントだけが使用していた共有ユーティリティ内のデッドコード
        3. 削除可能な REST 固有の型やインターフェース

        これらをクリーンアップし、どこからもインポートされていない場合は
        src/lib/restClient.ts を完全に削除してください。
        ```
      </PromptBlock>
    </Step>
  </Steps>
</div>
