8 signes que votre app IA est une démo, pas un produit

10 min read

Un ami m'a envoyé un lien vendredi soir. « Teste ça, c'est pas fini mais ça marche. »

Déjà mauvais signe : localhost:3050. 😬

TL;DR : 8 signaux que votre app IA n'est pas prête pour la prod. Pour chacun : ce qui plante, pourquoi ça plante, et un prompt Claude Code pour réparer. Indispensable si vous avez déjà déployé quelque chose, même un outil perso que personne ne connaît encore.

Comic illustration comparing software development stages with AI monitoring
Quand votre MVP ressemble plus à un Minimum Viable Prototype

Je lui ai dit. Il m'a envoyé un vrai lien dix minutes plus tard.

J'ai ouvert l'app, regardé autour. L'idée était solide. Mais déformation professionnelle, j'ai appuyé sur F12. Ouvert la console.

Ce que j'ai trouvé, c'était un best-of de tout ce qui tue les apps en production.

Des erreurs CORS empilées sur trois niveaux. Une clé API OpenAI qui traînait en texte brut dans les requêtes réseau. Un SELECT * qui se déclenchait à chaque frappe dans le champ de recherche. Aucune limitation de débit nulle part. Quand j'ai demandé comment il surveillait les erreurs en prod, il a dit « je regarde juste si ça plante ».

Pas un produit. Une démo avec un nom de domaine.

Classique.

Il y a une version de « fini » qui ressemble exactement au vrai truc. Même UI. Même URL. Parfois même des utilisateurs payants. Mais en dessous, ça tourne sur des suppositions qui ne tiennent que quand rien ne va de travers.

Une démo est optimisée pour impressionner. Un produit est optimisé pour survivre. Ce ne sont pas deux points sur un spectre, ce sont deux modes de construction complètement différents. Une démo réussit si elle marche une fois devant quelqu'un. Un produit doit marcher dix mille fois pendant que vous ne regardez pas.

Chaque signe de cette liste est une conséquence directe de cette distinction unique.

1. Vous n'avez aucune visibilité sur ce qui se passe en production

Si votre stratégie de monitoring c'est « je remarquerai si ça plante », vous n'avez pas de monitoring. Vous avez de l'espoir.

Pas de logs structurés. Pas d'alertes d'erreur. Pas de vérifications d'uptime. En mode démo, vous faites tourner l'app vous-même, vous voyez tout, rien ne vous surprend. En production, des fonctionnalités peuvent planter silencieusement pendant trois jours. Les utilisateurs arrêtent de revenir. Vous n'avez aucune idée pourquoi.

J'avais un webhook n8n qui a arrêté de traiter pendant 48 heures. Je l'ai découvert par hasard en débuggant autre chose. Puis j'ai lu un commentaire sur un de mes articles Medium demandant pourquoi l'outil que j'avais mentionné renvoyait des 503. L'article avait trois jours. L'outil était down depuis que je l'avais publié.

Solution : Sentry gratuit pour les erreurs runtime. UptimeRobot pour l'uptime. Quinze minutes au total. Aucune excuse.

« Configure un monitoring de production basique pour cette app. Ajoute Sentry pour le tracking d'erreurs, intègre UptimeRobot via un endpoint /health, et ajoute une alerte webhook Slack pour toute exception non gérée en prod. »

Vous n'avez pas besoin d'une salle de guerre. Vous avez besoin d'un détecteur de fumée.

2. Vous n'avez pas d'environnement de staging

L'app de mon ami vivait sur un serveur. Le même serveur sur lequel il développait activement. Ce qui signifiait qu'à chaque fois qu'il poussait un fix, la production était l'environnement de test.

J'ai cassé l'auth d'OpenClaw pendant deux heures parce qu'une variable d'environnement en prod avait un nom légèrement différent du local. Le genre de truc qu'on attrape immédiatement en staging. Le genre de truc qui fait que les utilisateurs pensent que votre app les déconnecte au hasard, et puis ils ne reviennent pas.

Le staging n'a pas besoin d'être fancy. Un $3 VPS (je fais tourner le mien sur une $5 box — même principe). Une branche preview Vercel. Un workflow GitHub Actions qui déploie en staging sur chaque PR et en prod seulement sur merge vers main.

N'importe quoi qui crée une couche entre « je viens de changer quelque chose » et « de vrais utilisateurs tapent dessus ». Le but n'est pas d'avoir un processus parfait. Le but est d'avoir un déploiement qui ne pointe pas directement vers de vrais utilisateurs.

« Crée une configuration d'environnement de staging pour ce projet. Sépare .env.local et .env.production, ajoute un workflow GitHub Actions qui déploie en staging sur PR et en prod sur merge vers main, et ajoute une checklist pré-déploiement au README. »

3. Vos clés API sont dans le code

C'est ce que l'IA génère par défaut :

const openai = new OpenAI({ apiKey: "sk-proj-..." });

Ça marche. C'est aussi à un git push d'être public.

Je n'expliquerai pas comment, mais j'ai des amis qui ne paient jamais pour un seul outil SaaS. Pas parce qu'ils piratent quoi que ce soit. Parce que tous les quelques mois ils lancent un scan de deux minutes et trouvent assez de clés leaked pour couvrir leur stack pour le trimestre suivant. Qui traînent dans des repos publics. Oubliées dans l'historique des commits. Comme un monde post-apocalyptique où les portes sont ouvertes et les frigos encore pleins. Personne n'a fait le ménage avant de partir.

Votre clé est probablement dans un de ces frigos en ce moment.

L'IA n'a aucun concept de si vous construisez une app todo personnelle ou un SaaS avec des clients payants. Elle met la clé où c'est pratique. « Ça va finir sur GitHub » n'est pas dans son modèle de menace.

Solution : fichier .env, .gitignore, terminé. Puis lancez git log -p | grep -i "api_key" sur vos repos existants. Vous n'aimerez peut-être pas ce que vous trouvez.

« Audite cette codebase pour les clés API, tokens et secrets hardcodés. Liste chaque occurrence avec fichier et numéro de ligne. Génère la migration .env complète et met à jour toutes les références pour utiliser process.env. »

(Ce n'est pas une erreur de débutant. C'est une erreur « aller vite sans checklist ». Ça arrive à tout le monde finalement.)

4. Vous n'avez pas de limitation de débit

Quelqu'un trouvera votre endpoint API. Ça peut être un bot. Ça peut être un utilisateur curieux. Ça peut être un scraper qui a trouvé votre URL dans un sitemap. Peu importe qui. Ce qui compte c'est qu'ils vont le frapper 400 fois en trois minutes et vous le découvrirez sur votre dashboard de facturation.

Sur ContentForge, j'avais un endpoint de génération sans limites. Un scraper l'a frappé avant même que je lance publiquement. Pas de dégâts parce que j'ai attrapé ça vite. Mais l'alerte mentale était forte : si je n'avais pas regardé les logs ce matin-là, j'aurais cramé tout mon budget API avant que le premier vrai utilisateur arrive.

Solution : express-rate-limit en Node. Rate limiting au niveau Traefik ou Nginx si vous êtes self-hosted. Cinq lignes de config. Arrête 90% des trucs stupides avant qu'ils deviennent des trucs coûteux.

« Ajoute du rate limiting à tous les endpoints API dans cette codebase. Utilise express-rate-limit avec 100 requêtes par 15 minutes par IP par défaut. Applique des limites plus strictes sur les routes auth et tout endpoint qui déclenche un appel API externe. »

5. Vous n'avez jamais testé ce qui arrive quand quelqu'un fait quelque chose de stupide

L'IA génère le happy path. À chaque fois.

L'utilisateur remplit le formulaire correctement, clique le bon bouton, a une connexion stable, ne double-clique pas sur submit. Ce qu'elle ne génère pas : les soumissions de champs vides. Les uploads de fichiers avec 0 bytes. Les sessions qui expirent mid-form. Le même bouton cliqué deux fois parce que le premier clic semblait lent.

Sur ContentForge, un utilisateur a soumis un prompt vide. NaN s'est écrit en base. Ce qui a cascadé en métadonnées cassées sur chaque article généré après ça. Je l'ai trouvé deux jours plus tard en débuggant quelque chose de complètement différent.

Solution : avant de partager le lien avec qui que ce soit, passez dix minutes à activement essayer de casser votre propre app. Pas de tests unitaires requis. Juste du chaos. Cliquez des trucs dans le mauvais ordre. Laissez des champs vides. Soumettez deux fois. Rafraîchissez mid-opération.

Ou lancez juste ça dans Claude Code d'abord :

« Agis comme un utilisateur malveillant essayant de casser cette app. Teste chaque formulaire avec des inputs vides, des caractères spéciaux, et des payloads oversized. Essaie de soumettre le même formulaire deux fois en succession rapide. Expire la session mid-flow. Documente chaque crash, comportement inattendu, ou edge case non géré que tu trouves. »

L'IA ne fera jamais ça pour vous sauf si vous demandez explicitement. Et même là, elle ratera la moitié.

6. Vos configs prod et dev sont les mêmes fichiers 😱

Même .env. Même base de données. Même bucket S3.

L'IA ne fait pas la distinction entre environnements. Elle configure pour « ça marche », pas pour « ça marche en sécurité quand vous testez une migration destructive en local ». La séparation d'environnements n'est pas dans le prompt, donc ça n'arrive pas dans le code.

Ce n'est pas juste un fix technique. C'est une décision structurelle qui doit être prise avant le premier déploiement, pas découverte six semaines plus tard quand un test local efface une table avec de vraies données utilisateur. Définir ces frontières en amont est le genre de contrat architectural qui sépare le gambling du shipping. C'est pourquoi le framework de contrats de prompts existe — définir les frontières avant d'être forcé de le faire.

Solution : .env.local, .env.production, deux bases de données séparées. Même pour un side project avec trois utilisateurs. Surtout pour un side project avec trois utilisateurs.

« Audite la configuration d'environnement de ce projet. Identifie chaque endroit où prod et dev partagent la même config, base de données, ou stockage. Génère un plan complet de séparation d'environnements avec des fichiers .env séparés, connexions de base de données, et buckets de stockage pour chaque environnement. »

7. Vos erreurs sont silencieuses

L'IA écrit des blocs try/catch. Elle les remplit aussi avec console.error ou rien du tout.

L'erreur est attrapée. Personne ne sait. L'utilisateur voit un résultat vide ou un spinner figé. Il part. Vous ne voyez rien.

J'avais un formulaire de contact sur un side project qui droppait silencieusement chaque soumission pendant deux semaines. Le mailer plantait sur un problème de config. Attrapé, loggé nulle part, avalé. Je l'ai découvert quand quelqu'un a demandé dans les commentaires pourquoi je n'avais jamais répondu à son message.

Deux semaines de leads morts. Zéro indication que quelque chose clochait de mon côté.

Solution : Sentry gratuit. C'est une plateforme de tracking d'erreurs qui attrape chaque exception non gérée en temps réel, avec la stack trace complète, le navigateur de l'utilisateur, la ligne exacte de code, et un compteur de reproduction. Dix minutes de setup. Pas optionnel si vous avez de vrais utilisateurs.

Pas encore Sentry ? Au minimum, lancez ça d'abord :

« Audite chaque bloc try/catch dans cette codebase. Remplace les catches vides et les catches console.error-only avec du logging d'erreur structuré. Ajoute un handler global unhandledRejection. Sors un résumé de chaque point de failure silencieux que tu as trouvé. »

Les erreurs silencieuses ne sont pas des bugs. Ce sont des fantômes.

8. Vous ne savez pas ce que vous dépensez en temps réel

La facture arrive. Vous l'ouvrez. Vous ne reconnaissez pas le nombre.

En dev, vous appelez l'API dix fois. Vous testez une fonctionnalité, ça marche, vous passez à autre chose. En prod, un utilisateur avec une boucle de retry agressive, un champ de recherche qui tire à chaque frappe, une requête non indexée qui fait des full table scans sur un dataset qui grandit. N'importe lequel de ces trucs peut transformer un budget de 20€/mois en surprise de 200€ avant que vous finissiez votre café.

L'IA génère du code qui marche. Elle ne génère pas de code qui est économiquement safe sous charge. Elle n'a aucun concept de votre cap budgétaire, votre marge, ou ce qui arrive quand quelqu'un qui n'est pas vous frappe l'endpoint 400 fois.

Solution : alertes de facturation sur chaque service que vous payez. AWS, OpenAI, Anthropic, Supabase. Ils ont tous des alertes de seuil. Configurez-les avant de partager le lien publiquement. Limites hard sur les appels API par utilisateur par jour. Un dashboard de coût basique, même un spreadsheet, revu hebdomadairement.

Pas glamour. Sauve votre mois.

« Ajoute une protection de facturation à cette app. Implémente des limites quotidiennes d'appels API par utilisateur, ajoute des caps hard sur toute boucle qui appelle une API externe, et génère une section README avec des instructions step-by-step pour configurer des alertes budget sur OpenAI, Anthropic, AWS, et Supabase. »

Shippez bien ou shippez deux fois

Mon ami, au fait, a tout réparé. Ça lui a pris un weekend. L'app est vraiment bien, meilleure que la plupart de ce que je vois shippé par des équipes avec de vrais budgets. C'est le truc avec les apps vibe-codées bien faites : l'idée et l'exécution peuvent être exceptionnelles. C'est la couche infrastructure qui les tue. Et cette partie est réparable.

L'industrie va continuer d'appeler ces démos des « produits » pendant encore dix-huit mois. Les screenshots ont l'air identiques. Les posts de lancement sonnent pareils.

Les builders qui shippent vraiment vérifient cette liste avant de partager le lien. Pas après la breach. Pas après la facture de 14k€. Avant.

Une démo impressionne. Un produit survit.


Si ça vous a sauvé d'une mauvaise soirée de vendredi, il y en a plus d'où ça vient. J'écris sur construire de vraies choses avec l'IA, les parties que les tutoriels sautent.


(*) La couverture est générée par IA. Promptée, pas peinte, mais les histoires d'horreur dans l'article sont bien trop réelles.

Cet article peut contenir des liens d'affiliation, et je peux gagner une petite commission.


Entre démo et production, il y a un monde. Chaque semaine, je partage les leçons pour franchir ce fossé avec des outils AI solides.

Rejoindre la newsletter