> ## 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.

# Playbook pour corriger une migration de base de données instable

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="Corriger un playbook de migration de base de données peu fiable" description="Votre playbook de db-migration fonctionne sur des schémas simples mais échoue dès qu’il y a des clés étrangères. Transmettez quatre liens de session à Devin et laissez-le combler les lacunes." prompt="Notre playbook !db-migration échoue systématiquement lorsque les sessions rencontrent des contraintes de clé étrangère. Voici 4 sessions récentes — les sessions 1 et 2 ont réussi sur des tables indépendantes, mais les sessions 3 et 4 ont échoué avec des erreurs de clés étrangères (FK). Analysez les échecs, comparez-les aux réussites et mettez à jour le playbook pour gérer les dépendances de clés étrangères (FK) avant toute opération destructive." category="Optimisation de Devin" features="Avancé, Playbooks" agent="advanced" intent="improve" />

<div className="uc-detail-wrapper">
  <Tip>Vous ne voulez pas configurer cela manuellement ? Collez un lien vers cette page dans une session Devin et demandez-lui de tout configurer pour vous.</Tip>

  <Steps>
    <Step title="Repérer le motif à travers les sessions">
      Votre équipe utilise le playbook `!db-migration` depuis quelques semaines. Il a géré le renommage de colonnes et l’ajout d’index sans problème — mais les deux dernières sessions ont planté en milieu de migration lorsqu’elles ont essayé de supprimer une colonne référencée par d’autres tables.

      Ouvrez chaque session et regardez le point d’échec. Dans ce cas, les sessions 3 et 4 ont toutes deux échoué à la même étape :

      ```
      ERROR: cannot drop column "account_id" because other objects depend on it
      DETAIL: constraint fk_orders_account_id on table orders depends on column account_id
      HINT: Use DROP ... CASCADE to drop dependent objects too.
      ```

      Vous disposez maintenant d’un signal clair : le playbook n’a aucune étape pour vérifier les dépendances de clés étrangères avant les opérations destructrices. Deux sessions ont réussi parce qu’elles touchaient des tables autonomes ; deux ont échoué parce que ce n’était pas le cas.
    </Step>

    <Step title="Ouvrir l’onglet Improve Playbook avec les liens de session">
      Allez sur [app.devin.ai](https://app.devin.ai/?utm_source=docs\&utm_medium=use-case-gallery) et cliquez sur **avancé** sous la zone de saisie. Sélectionnez l’onglet **Improve Playbook**.

      Choisissez `!db-migration` dans la liste déroulante des playbooks, puis sélectionnez les quatre sessions dans le **menu déroulant multi-sélection des sessions** — à la fois les réussites et les échecs. Inclure des sessions réussies permet à Devin de voir ce que le playbook fait bien, pas seulement là où il échoue.

      <PromptBlock agent="advanced" intent="improve">
        ```txt Improve the db-migration playbook theme={null}
        Our !db-migration playbook works for simple table changes but fails
        when sessions hit foreign key constraints. Sessions 1 and 2 succeeded
        on standalone tables, but sessions 3 and 4 crashed on FK errors.

        Analyze all 4. Figure out what the successful sessions did differently
        (they hit standalone tables with no incoming FKs). Then update the
        playbook to:
        1. Query information_schema for FK dependencies before any DROP or ALTER
        2. Generate ALTER TABLE ... DROP CONSTRAINT statements when FKs exist
        3. Add a rollback step that re-creates dropped constraints if the
           migration fails partway through
        ```
      </PromptBlock>

      Ce qui rend ce prompt efficace :

      * **Nomme l’échec exact** — « contraintes de clé étrangère » au lieu de « il échoue parfois »
      * **Oppose réussites et échecs** — Devin peut comparer les transcriptions de session pour voir où elles divergent
      * **Liste des correctifs concrets** tout en laissant à Devin la possibilité de faire remonter des problèmes que vous auriez manqués
    </Step>

    <Step title="Examiner le diff du playbook">
      Devin lit les transcriptions des quatre sessions, identifie précisément où les échecs ont divergé des réussites et propose des modifications ciblées. Le résultat ressemble à un changelog pour votre playbook :

      ```
      ## Analysis

      Sessions 1-2 succeeded because they only modified tables with no
      incoming foreign keys. Sessions 3-4 failed at step 4 ("Drop the
      old column") because the orders and invoices tables had FK
      references to the target column.

      ## Changes to !db-migration

      Added step 3a: "Before any DROP or ALTER that removes a column,
        query information_schema.key_column_usage to list dependent FKs.
        If any exist, generate ALTER TABLE ... DROP CONSTRAINT statements
        and execute them first. Save the original constraint DDL for
        rollback."

      Added step 7: "Rollback procedure — if any step after FK removal
        fails, re-create the dropped constraints using the saved DDL
        from step 3a."

      Updated Advice section: "Always run the migration against a staging
        database first. FK chains can be deeper than expected — a column
        in table A may be referenced by B, which is referenced by C.
        Query recursively."
      ```

      Le playbook est enregistré automatiquement. Si quelque chose ne va pas, répondez dans la même session — par exemple : « Ajoute aussi une étape pour notifier le canal Slack #database avant d’exécuter des migrations destructrices. »
    </Step>

    <Step title="Vérifier la correction sur une nouvelle migration">
      Vous n’avez pas besoin de quitter votre session Devin actuelle. Une fois la mise à jour du playbook enregistrée, utilisez la même session pour lancer une session Devin standard qui teste le playbook mis à jour sur le scénario exact qui avait échoué auparavant :

      <PromptBlock>
        ```txt Test the updated playbook theme={null}
        Use the !db-migration playbook to drop the legacy_account_id column
        from the users table. This column is referenced by orders.account_id
        and invoices.billing_account_id — the playbook should handle the FK
        dependencies automatically.
        ```
      </PromptBlock>

      Si cette session réussit, la correction fonctionne. Si elle rencontre un nouveau cas limite (par exemple, des références de clés étrangères circulaires), renvoyez cette session dans l’onglet Improve Playbook pour un nouveau cycle.
    </Step>
  </Steps>
</div>
