Canvas (archive de conception)Stack technique 2026+

Stack technique 2026+

Archive de conception. Cette page raconte ce qui etait vise le jour ou elle a ete ecrite, pas l'etat du code aujourd'hui. Ce qui a ete livre depuis est recense dans le README.

Archive de conception. Cette page raconte ce qui etait vise le jour ou elle a ete ecrite, pas l'etat du code aujourd'hui. Ce qui a ete livre depuis est recense dans le README.

← retour au README


4. Stack technique 2026+

Bloc 1 — Pattern de versionnage (v0.dev)

Technique : modèle « chat-as-branch » (une conversation = une branche) : chaque conversation crée une branche de thème, chaque message qui modifie des fichiers crée un snapshot (à la manière d'un commit).

Modèle de données : Conversation (1) → Message (n) → ThemeVersion (n optionnels) ; chaque ThemeVersion porte parentVersionId, themeFilesDiff (jsonpatch), metadata.

API V1 :

  • POST /api/branches/[id]/restore : remet les fichiers dans l'état du snapshot N
  • POST /api/branches/[id]/fork : nouvelle conversation depuis le snapshot N
  • POST /api/branches/[id]/publish : push vers le draft Shopify connecté

Stockage : V1 = snapshot complet en base (JSON Postgres), V2 = diffs jsonpatch avec compaction toutes les N versions (sinon 50 snapshots × 200 fichiers ≈ 10 MB).

Pièges : la restauration est destructive → snapshot automatique du travail en cours avant. Calqué sur un git stash automatique.

Sources :

Bloc 2 — Boucle d'agent du Vercel AI SDK + Workflow DevKit

Technique : ToolLoopAgent (AI SDK v6) + Workflow DevKit (durabilité, GA fin 2025).

Pattern :

  1. Task Prisma persisté ({id, conversationId, status, agentRunId, plan})
  2. POST /api/tasks/[id]/run → encapsule ToolLoopAgent dans une fonction Workflow DevKit, renvoie agentRunId immédiatement
  3. Streaming via getWritable() (flux durable) → SSE consommé par l'UI ; une reconnexion reprend à partir de l'offset
  4. Reprise après crash : rejeu déterministe offert par Workflow DevKit (toute E/S passe par step() ou tool())
  5. stopWhen: [stepCountIs(40), hasToolCall("requestUserApproval")] pour l'humain dans la boucle (HITL)

Pièges : Workflow DevKit est en GA depuis peu (oct. 2025), surveiller les changements cassants sur les flux durables. Convention stricte : toute E/S externalisée.

Sources :

Bloc 3 — Éditeur Monaco

Technique : @monaco-editor/react (référence en 2026, 88 extraits Context7). Bundle de 5–10 MB → chargement différé obligatoire via next/dynamic({ssr: false}).

Pattern :

const Editor = dynamic(() => import("@monaco-editor/react"), {
  ssr: false,
})
// Multi-tab via prop `path` + saveViewState=true (cursor/scroll par fichier)
// Custom theme via useMonaco + monaco.editor.defineTheme (OKLch BoostEcom)

LSP Liquid : @shopify/theme-language-server-node (officiel), exécuté dans une Vercel Function exposée en WebSocket (WebSocket pris en charge par Vercel en 2025), connecté via monaco-languageclient (Typefox).

Pièges : bundle de 5–10 MB → découpage en chunks agressif, chargement uniquement quand l'utilisateur ouvre le Workspace. Repli si les retours disent « trop lourd » : CodeMirror 6 (300 KB) + @codemirror/lang-liquid.

Sources :

Bloc 3.5 — Serveurs MCP natifs de Shopify (découverte de la recherche)

Shopify a publié en open source 3 serveurs MCP officiels en 2026 (github.com/ Shopify/Shopify-AI-Toolkit, MIT). Aucun ne couvre notre besoin (opérations marchand de niveau production), notre MCP maison reste donc légitime, mais on peut composer :

MCP officielPérimètreNotre usage
Dev MCP (shopify-dev-mcp)Documentation + introspection du schéma GraphQL✅ Intégrer côté agents de développement BoostEcom (Cursor / Claude Code) : accélère notre productivité interne
Storefront MCPAcheteur (search_catalog, lookup_catalog, get_product, cart, checkout)🔍 V2/Phase 2 (AI Operator côté acheteur) : fork comme base d'un assistant d'achat dans la boutique
Admin MCP (Winter '26)Développeur (scaffolding d'app, opérations GraphQL, génération de code Admin/UI/Liquid/Hydrogen)🔍 Surveiller : Shopify pourrait l'étendre aux opérations marchand, on sera prêts à pivoter

Notre MCP (src/app/api/mcp/[storeId]/register-tools.ts) couvre le manque d'opérations marchand en production : opérer une boutique avec une auth multi-tenant pour le CRUD pages/blogs/menus/clients/réductions. À garder jusqu'à preuve du contraire côté Shopify.

Risque : Shopify pourrait publier plus tard un MCP standardisé d'opérations marchand (Winter '26+). Parade : l'encapsuler derrière notre interface d'outil, et s'aligner progressivement sur sa forme si elle émerge.

Bloc 4 — API Theme de Shopify

Technique : GraphQL Admin API 2025-10. REST est legacy depuis 2024-10, les nouvelles apps sont GraphQL uniquement depuis avril 2025.

Mutations clés :

  • themeCreate(name, source) : clone Live ou Dawn
  • themeFilesUpsert(themeId, files: [...]) : lot de 50 maximum, job asynchrone
  • themeFilesDelete, themeRename, themeDelete
  • themePublish(id) : bascule atomique du live ← clic explicite

Requêtes : themes, theme(id), themeFiles(themeId).

Sandbox : thème draft = role: UNPUBLISHED. URL de preview = https://{shop}.myshopify.com/?preview_theme_id={id} + cookie _shopify_tm.

Scopes minimum : read_themes, write_themes, unauthenticated_read_content.

Pièges :

  • Limite de débit GraphQL en seau percé (1000 points de coût, recharge de 50/s) : file + backoff sur 429
  • Limite de 20 thèmes par boutique → nettoyage automatique des drafts inactifs depuis plus de 30 jours ; pool de drafts pour paralléliser
  • Demande d'exception requise pour write_themes sur une app publique (pas bloquant pour une custom app)

Sources :

Bloc 5 — Proxy de preview live

Technique : iframe directe avec ?preview_theme_id={id}. Shopify n'envoie PAS de frame-ancestors sur le storefront public (seulement sur l'admin).

Hot reload : utiliser @shopify/theme-hot-reload (npm, MIT, officiel Shopify), sans réinventer le mécanisme. La lib gère :

  • l'équivalent d'une surveillance du système de fichiers côté serveur (notre push themeFilesUpsert)
  • l'injection d'un script basé sur SSE dans le draft
  • un rechargement intelligent par section (seule la section est rendue à nouveau, pas toute la page) = une UX bien supérieure au rechargement complet
  • le remplacement à chaud du CSS, instantané, sans recharger la page

Pattern :

  1. Importer @shopify/theme-hot-reload dans la Vercel Function proxy /api/preview/[storeId]/*
  2. Encapsuler leur endpoint SSE dans notre flux
  3. Sur themeFilesUpsert côté workspace → diffusion d'un événement → la lib pousse la bonne mise à jour à l'iframe

Verrouiller la version exacte (lib en 0.0.x, API instable). Scope unauthenticated_read_content requis (déjà présent dans nos custom apps habituelles).

Pièges :

  • Page de mot de passe des boutiques de développement → casse l'iframe. Contournement : réécriture par proxy Next.js /preview/:shop/:path* qui propage les cookies en same-origin
  • Cookie tiers _shopify_tm : peut expirer ; même parade

Sources :

Bloc 6 — UX de la file de tâches (Linear + Cursor)

Technique : modèle Agent Session de Linear combiné au **background agent

  • git worktree** de Cursor. Persistance Prisma. Exécution = Workflow DevKit (cf. Bloc 2).

États : pending → in_progress → waiting_review → done | failed | cancelled (calqué sur Linear).

Schéma Prisma :

model Task {
  id              String      @id @default(cuid())
  storeId         String
  conversationId  String?
  title           String
  description     String?
  status          TaskStatus
  priority        Int         @default(0)
  assigneeAgent   String?     // "atlas" | "maya" | "marco" | …
  parentTaskId    String?
  dependsOnTaskIds String[]
  plan            Json?       // AgentPlan steps
  output          Json?       // run result
  agentRunId      String?     // Workflow DevKit run ID
  createdBy       String
  createdAt       DateTime    @default(now())
  updatedAt       DateTime    @updatedAt
  completedAt     DateTime?
}

enum TaskStatus {
  PENDING IN_PROGRESS WAITING_REVIEW DONE FAILED CANCELLED
}

model TaskActivity {
  id        String   @id @default(cuid())
  taskId    String
  type      String   // "comment" | "tool_call" | "status_change"
  payload   Json
  ts        DateTime @default(now())
}

UI : panneau gauche du workspace, priorité par glisser-déposer, filtre par statut/agent, badge live « in_progress » avec indicateur de streaming.

Parallélisation : chaque tâche = un run Workflow isolé. État partagé via la base (pas en mémoire de processus).

Pièges : limite de 20 thèmes Shopify → au plus ~10 tâches parallèles avec isolation par draft. V1 = exécution séquentielle, V2 = parallèle avec un pool de drafts recyclés.

Sources :

Bloc 7 — Terminal dans le navigateur

Technique V1 : console en lecture seule (SSE des sorties des appels d'outils des agents, zéro infra, zéro coût).

Technique V2 : Vercel Sandbox (microVM Firecracker, $0.128 par heure CPU en Pro). POST /api/sandbox/exec → lancement éphémère, exécution de la commande (shopify theme check, shopify theme push --json), stdout/stderr diffusés en SSE, arrêt forcé à 60 s.

Pas de WebContainers (StackBlitz) : licence opaque, dépendance externe, bundle client lourd, pas de système de fichiers partagé avec le backend Prisma.

Replis documentés :

  • E2B (2e choix) : communauté plus large, adopté par des entreprises du Fortune 500, Firecracker aussi, sessions de 24 h (contre 5 h chez Vercel). Bascule si les quotas Vercel deviennent contraignants.
  • Daytona (voie d'évolution V3) : seul à prendre en charge Computer Use en natif, démarrage à froid de 90 ms (contre 150 ms chez Vercel), sessions illimitées. Pour la V3, si on veut intégrer Computer Use dans le workspace (preview multi-segment réaliste, test du checkout de bout en bout).

Écartés : Modal (orienté Python, pas pertinent), le SDK CodeSandbox (tarification par sandbox inadaptée), Northflank/Beam auto-hébergés (charge d'exploitation disproportionnée).

Pièges : plafond d'heures CPU par organisation, chaque sandbox étiquetée avec orgId pour le suivi de facturation. Un démarrage à froid Firecracker de ~1-2 s convient à un usage ponctuel, pas à l'interactif (V3 = Daytona ou Fly.io Sprites si besoin).

Sources :


Suivant : data-model.md