Une spec complète à partir d'une phrase
Produit, parcours, règles métier, données, API et plan de développement. Les faits sont sourcés, les hypothèses signalées.
Pour Cursor, Claude Code, Lovable, Bolt et les autres
Kodrudder écrit le dossier complet de votre projet, le donne à votre outil de code, puis vérifie que le code le suit. Fini l'IA qui improvise.
Sans carte bancaire. Votre premier dossier en quelques minutes.
Marques citées à titre d'information. Kodrudder n'est affilié à aucun de ces éditeurs.
De l'idée au code vérifié : une seule spec, qui suit votre projet du premier prompt à la mise en production.
Produit, parcours, règles métier, données, API et plan de développement. Les faits sont sourcés, les hypothèses signalées.
Kodrudder compare la spec au code et vous montre ce qui est fait, partiel ou oublié, fichier par fichier.
Collez un lien GitHub ou déposez une archive : Kodrudder reconstitue la spec de ce qui existe déjà.
AGENTS.md, règles Cursor, Claude Code, Windsurf, prompts Lovable et Bolt, serveur MCP : votre IA lit la spec sans copier-coller.
PRD, récits utilisateur, schéma SQL, contrat d'API, maquettes d'écrans, liste de tâches.
Lien de lecture, relecteurs, commentaires par section : tout le monde travaille sur la même spec.
Envoyez la tâche suivante dans Lovable, Bolt, v0 ou Replit, puis cochez-la quand c'est fait.
Une phrase, quelques questions, et le dossier s'écrit sous vos yeux. Ensuite, il part vers votre outil en un clic.
Décrivez votre projet en langage courant. Kodrudder pose les bonnes questions, écrit tout ce dont votre IA a besoin, puis garde la spec à jour.
Une phrase suffit. Ou un lien vers votre dépôt GitHub.
Uniquement celles qui changent le résultat. Pour le reste, Kodrudder décide et le signale.
Règles, critères d'acceptation, données, API et tâches, relus avant de vous être remis.

Envoyez la spec à votre outil. Comparez-la au code dès que vous voulez savoir où vous en êtes.
Votre idée devient un plan clair que l'IA suit, au lieu de dix allers-retours pour corriger ce qu'elle a deviné.
Des règles, des critères d'acceptation et des tâches que votre outil prend une à une, sans perdre le fil d'une session à l'autre.
Une seule source de vérité, relue, partagée, et confrontée au code à chaque étape.
Voici le dossier produit pour « une application de réservation pour coachs sportifs ». Parcourez-le comme le lira votre IA.
Réservation pour coachs sportifs
Fait sourcéHypothèse (H)
À lire d'abord
Produit. Application web de réservation pour coachs sportifs indépendants : le coach publie disponibilités et tarifs, le client réserve et paie en ligne sans compte, puis reçoit un SMS de rappel J-1. Objectif : moins de no-shows et moins de relances manuelles.
| Écart | Ce qui prévaut sur le texte des sections |
|---|---|
| EC-01 | Webhook tardif sur EXPIREE : PAYE puis REMBOURSE dans une seule transaction (RM-04) |
| EC-02 | rappel_sms créé à la confirmation si début > 24 h ; passé à annule à toute annulation |
| EC-03 | D-05 : 1 rappel + 1 SMS d'annulation coach éventuel, contenu transactionnel |
| EC-04 | Jeton de gestion = 256 bits partout (RM-13 aligné) |
| EC-05 | Blocage de date refusé si réservation EN_ATTENTE_PAIEMENT ou CONFIRMEE ce jour |
| EC-06 | Mobile 06/07 uniquement (RM-11 aligné) ; validation API avant insertion, 400 et non 500 |
| EC-07 | Ajouter GET /api/coach/seances, /disponibilites, /dates-bloquees |
| EC-08 | E-03 lit le statut via API-15 par jeton |
Règles métier et critères d'acceptation
4 hypothèses marquées
| Statut de réservation | Sens |
|---|---|
EN_ATTENTE_PAIEMENT | Créneau verrouillé temporairement, paiement non confirmé |
CONFIRMEE | Paiement reçu, séance planifiée |
ANNULEE_CLIENT | Annulée par le client |
ANNULEE_COACH | Annulée par le coach |
EXPIREE | Paiement non finalisé avant expiration du verrou |
TERMINEE | Heure de fin de séance dépassée |
| Statut de paiement | Sens |
|---|---|
AUCUN | Aucun paiement initié |
PAYE | Capturé |
REMBOURSE | Remboursement intégral émis |
ECHEC_REMBOURSEMENT | Remboursement refusé ou en erreur, à traiter manuellement |
| ID | Besoin | MVP |
|---|---|---|
| BE-01 | Le coach crée un compte et se connecte (email + mot de passe) | MVP-01 |
| BE-02 | Le coach active ses paiements via l'onboarding Stripe Connect | MVP-01 |
| BE-03 | Le coach définit ses séances : durée, prix, lieu | MVP-02 |
| BE-04 | Le coach définit des disponibilités hebdomadaires et bloque des dates | MVP-03 |
| BE-05 | Le client consulte la page publique d'un coach et ses créneaux libres | MVP-04 |
| BE-06 | Le client réserve sans compte (nom, email, mobile) | MVP-04 |
| BE-07 | Un créneau ne peut être réservé que par un seul client | MVP-05 |
| BE-08 | Le client paie en ligne en une fois | MVP-05 |
| BE-09 | Le client reçoit un email de confirmation avec lien de gestion | MVP-06 |
| BE-10 | Le client reçoit un SMS de rappel 24 h avant la séance | MVP-06 |
| BE-11 | Le client annule via son lien, selon le délai | MVP-07 |
| BE-12 | Le coach annule une séance et le client est remboursé automatiquement | MVP-07 |
| BE-13 | Le coach consulte réservations et paiements | MVP-08 |
Valeurs par défaut en H. Toutes les heures sont en Europe/Paris (D-09).
| ID | Règle | Défaut H | Cas limites |
|---|---|---|---|
| RM-01 | Un créneau = (coach, début, durée). Il est réservable s'il est dans une disponibilité, hors date bloquée et sans réservation EN_ATTENTE_PAIEMENT ou CONFIRMEE chevauchante | Pas de chevauchement, pas de pause tampon | Deux séances de durées différentes qui se chevauchent : la seconde est refusée. Créneau passé : non réservable |
| RM-02 | Délai minimal de réservation avant le début | 2 h | Créneau à moins de 2 h : non proposé |
| RM-03 | Horizon maximal de réservation | 60 jours | Au-delà : non proposé |
| RM-04 | Verrou de paiement : la création passe la réservation en EN_ATTENTE_PAIEMENT et verrouille le créneau | 15 min. Expiration → EXPIREE, créneau libéré | Paiement confirmé après expiration : remboursement automatique et information du client. Abandon sur Stripe : EXPIREE à l'échéance |
| RM-05 | Concurrence : le verrou est atomique (contrainte d'unicité en base), la première écriture gagne | n/a | Deux requêtes simultanées : une seule réussit, l'autre reçoit « créneau indisponible » |
| RM-06 | Paiement : montant = prix de la séance, EUR, intégral. Passage à CONFIRMEE uniquement sur webhook Stripe signé et idempotent | Aucune commission (D-10) | Webhook en doublon : sans effet. Échec de carte : réservation reste EN_ATTENTE_PAIEMENT jusqu'à expiration. Montant reçu ≠ attendu : réservation non confirmée |
| RM-07 | Annulation client (D-07) via lien de gestion | Plus de 24 h avant le début : ANNULEE_CLIENT + remboursement intégral. À 24 h pile ou moins : annulation refusée | Séance déjà TERMINEE ou annulée : refus. Lien utilisé deux fois : idempotent |
| RM-08 | Annulation coach : toujours possible avant le début, remboursement intégral automatique | Notification email + SMS au client | Annulation avec remboursement en échec : ANNULEE_COACH, paiement ECHEC_REMBOURSEMENT, alerte au coach |
| RM-09 | Frais de remboursement : le client reçoit le montant intégral payé. Le surcoût éventuel des frais Stripe sur remboursement est à vérifier | Absorbé par le coach H | Coach sans solde Connect suffisant : remboursement à traiter manuellement |
| RM-10 | Rappel SMS : 1 SMS 24 h avant le début, uniquement pour une réservation CONFIRMEE (D-05, D-06). Contenu transactionnel sans offre promotionnelle | Envoi à début − 24 h | Réservation faite à moins de 24 h du début : pas de rappel, la confirmation par email suffit. Annulée avant l'envoi : aucun SMS. Mobile invalide ou échec Twilio : 1 nouvel essai à +10 min, puis echec journalisé, sans blocage de la réservation. Jamais d'envoi en doublon pour une même réservation |
| RM-11 | Validation du mobile : format français (+33 / 0X) normalisé E.164 ; email valide | Mobile et email obligatoires | Format invalide : réservation refusée avec message explicite |
| RM-12 | Modification de disponibilités : sans effet sur les réservations CONFIRMEE existantes. Un blocage de date sur une réservation existante est refusé tant que le coach ne l'annule pas (RM-08) | n/a | Suppression d'une séance du catalogue : les réservations existantes sont conservées |
| RM-13 | Droits : un coach ne voit et ne modifie que ses données. Le lien de gestion client contient un jeton aléatoire non devinable, limité à une réservation | Jeton ≥ 128 bits | Jeton invalide ou inconnu : 404 sans fuite d'information |
| RM-14 | Paiement activé : une séance n'est réservable que si l'onboarding Connect du coach est complet | n/a | Compte Connect restreint ou désactivé après coup : nouvelles réservations bloquées, existantes conservées |
| RM-15 | Passage à TERMINEE : automatique après l'heure de fin | n/a | Aucun remboursement possible après TERMINEE |
| Initiateur | Statut courant | Délai avant le début | Résultat | Remboursement |
|---|---|---|---|---|
| Client | CONFIRMEE | > 24 h | ANNULEE_CLIENT | Intégral |
| Client | CONFIRMEE | ≤ 24 h | Refusé | Aucun |
| Client | EN_ATTENTE_PAIEMENT | tout | EXPIREE (libération du créneau) | Aucun paiement à rembourser |
| Client | TERMINEE, ANNULEE_*, EXPIREE | tout | Refusé | Aucun |
| Coach | CONFIRMEE | tout (avant début) | ANNULEE_COACH | Intégral automatique |
| Coach | EN_ATTENTE_PAIEMENT | tout | EXPIREE | Aucun paiement à rembourser |
| Coach | TERMINEE, ANNULEE_*, EXPIREE | tout | Refusé | Aucun |
| ID | Étant donné | Quand | Alors | BE | RM |
|---|---|---|---|---|---|
| CA-01 | Un coach a une disponibilité le lundi 10:00–12:00 et une séance de 60 min | Un client ouvre sa page publique | Les créneaux 10:00 et 11:00 sont proposés | BE-05 | RM-01 |
| CA-02 | Une date est bloquée par le coach | Un client consulte cette date | Aucun créneau n'est proposé | BE-04 | RM-01 |
| CA-03 | Un créneau dans 1 h | Un client consulte la page | Le créneau n'est pas proposé | BE-05 | RM-02 |
| CA-04 | Un créneau dans 61 jours | Un client consulte la page | Le créneau n'est pas proposé | BE-05 | RM-03 |
| CA-05 | Un créneau libre | Un client soumet nom, email et mobile valides | Réservation EN_ATTENTE_PAIEMENT, redirection vers Stripe Checkout, créneau verrouillé | BE-06, BE-08 | RM-04 |
| CA-06 | Un créneau libre | Deux requêtes de réservation arrivent simultanément | Une seule réussit, l'autre reçoit « créneau indisponible » | BE-07 | RM-05 |
| CA-07 | Une réservation EN_ATTENTE_PAIEMENT depuis 16 min | Le job d'expiration s'exécute | Statut EXPIREE, créneau à nouveau réservable | BE-07 | RM-04 |
| CA-08 | Une réservation EN_ATTENTE_PAIEMENT | Un webhook Stripe signé de paiement réussi arrive | Statut CONFIRMEE, paiement PAYE, email de confirmation envoyé | BE-08, BE-09 | RM-06 |
| CA-09 | Le même webhook déjà traité | Il est reçu à nouveau | Aucun changement d'état, aucun second email | BE-08 | RM-06 |
| CA-10 | Un webhook avec signature invalide | Il est reçu | Rejeté (400), aucun changement d'état | BE-08 | RM-06 |
| CA-11 | Une réservation EXPIREE | Un webhook de paiement réussi arrive | Paiement REMBOURSE automatiquement, réservation reste EXPIREE | BE-08 | RM-04 |
| CA-12 | Un paiement dont le montant ≠ prix attendu | Le webhook arrive | La réservation n'est pas confirmée et l'anomalie est journalisée | BE-08 | RM-06 |
| CA-13 | Une réservation CONFIRMEE à plus de 24 h | Le client annule via son lien | ANNULEE_CLIENT, paiement REMBOURSE intégral, créneau libéré | BE-11 | RM-07 |
| CA-14 | Une réservation CONFIRMEE à 24 h ou moins | Le client tente d'annuler | Refus avec message explicite, statut inchangé | BE-11 | RM-07 |
| CA-15 | Une réservation ANNULEE_CLIENT | Le client rouvre son lien d'annulation | Aucun second remboursement, message « déjà annulée » | BE-11 | RM-07 |
| CA-16 | Une réservation CONFIRMEE à 2 h | Le coach l'annule | ANNULEE_COACH, remboursement intégral, email et SMS au client | BE-12 | RM-08 |
| CA-17 | Le remboursement Stripe échoue | Le coach annule | ANNULEE_COACH, paiement ECHEC_REMBOURSEMENT, alerte visible au coach | BE-12 | RM-08 |
| CA-18 | Une réservation CONFIRMEE début à T | L'horloge atteint T − 24 h | Un SMS de rappel est envoyé, une seule fois | BE-10 | RM-10 |
| CA-19 | Une réservation créée à moins de 24 h du début | Elle passe en CONFIRMEE | Aucun SMS de rappel, email de confirmation envoyé | BE-10 | RM-10 |
| CA-20 | Une réservation annulée avant T − 24 h | L'horloge atteint T − 24 h | Aucun SMS | BE-10 | RM-10 |
| CA-21 | Twilio renvoie une erreur | Le rappel est envoyé | Un nouvel essai à +10 min, puis échec journalisé, réservation inchangée | BE-10 | RM-10 |
| CA-22 | Un SMS de rappel généré | Son contenu est inspecté | Il ne contient aucune offre promotionnelle (modèle fixe testé) | BE-10 | RM-10 |
| CA-23 | Un mobile « 12345 » | Le client soumet le formulaire | Refus avec message de format, aucune réservation créée | BE-06 | RM-11 |
| CA-24 | Un mobile « 06 12 34 56 78 » | Le client soumet le formulaire | Enregistré en +33612345678 | BE-06 | RM-11 |
| CA-25 | Une réservation CONFIRMEE sur une date | Le coach bloque cette date | Refus tant que la réservation n'est pas annulée | BE-04 | RM-12 |
| CA-26 | Deux coachs A et B | A demande une réservation de B | 403 ou 404, aucune donnée de B exposée | BE-13 | RM-13 |
| CA-27 | Un jeton de gestion inconnu | Le lien est ouvert | 404 sans information sur l'existence d'une réservation | BE-11 | RM-13 |
| CA-28 | Un coach sans onboarding Connect complet | Un client consulte sa page | Aucune séance réservable | BE-02 | RM-14 |
| CA-29 | Une réservation CONFIRMEE dont l'heure de fin est dépassée | Le job de clôture s'exécute | Statut TERMINEE, annulation refusée | BE-13 | RM-15 |
| CA-30 | Un coach connecté avec 3 réservations | Il ouvre son tableau de bord | Les 3 réservations s'affichent avec statut de réservation et de paiement | BE-13 | RM-13 |
| CA-31 | Un email déjà utilisé par un coach | Un second compte est créé avec cet email | Refus avec message d'erreur | BE-01 | — |
| CA-32 | Un coach crée une séance de 60 min à 50 € | Il l'enregistre | Elle apparaît sur sa page publique avec durée, prix et lieu | BE-03 | RM-14 |
| ID | Question | Hypothèse H |
|---|---|---|
| Q-01 | Qui supporte les frais Stripe non restitués lors d'un remboursement ? | Le coach (RM-09), à vérifier dans la tarification Stripe Connect |
| Q-02 | Faut-il un délai de grâce après l'heure de début pour une séance non honorée par le coach ? | Non, hors MVP |
Architecture et données
4 hypothèses marquées
| Couche | Choix | Raison | Alternative écartée |
|---|---|---|---|
| Front + back | Next.js (TypeScript), un seul dépôt | Pages publiques rapides, API et front dans un déploiement unique H | SPA + API séparée : surcoût pour un MVP |
| Base | PostgreSQL | Contraintes d'exclusion (RM-05), transactions, jobs sur SQL | SQLite/NoSQL : pas d'exclusion de chevauchement fiable |
| Paiement | Stripe Checkout + Connect Express (D-02, D-03) | Pas de données carte à gérer | Paiement sur place : no-shows |
| SMS | Twilio (D-04) | Fournisseur retenu en section 1 | Brevo SMS : non évalué |
| Resend H | API simple pour confirmations | SMTP maison | |
| Jobs | Table job_planifie + worker cron (1 min) H | Pas de broker à exploiter, planification en SQL | Redis/BullMQ : composant en plus |
| Hébergement | PaaS EU + Postgres managé, sauvegarde quotidienne H | Données en UE, exploitation légère | Kubernetes : disproportionné |
evenement_stripe), confirme ou rembourse (RM-06).CREATE EXTENSION IF NOT EXISTS btree_gist; -- requis pour l'exclusion (RM-05)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE coach (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
email text NOT NULL,
mot_de_passe_hash text NOT NULL,
nom_affiche text NOT NULL,
slug text NOT NULL, -- lien public partageable (MVP-04)
stripe_account_id text,
connect_complet boolean NOT NULL DEFAULT false, -- RM-14
cree_le timestamptz NOT NULL DEFAULT now(),
CONSTRAINT coach_slug_format CHECK (slug ~ '^[a-z0-9-]{3,50}$')
);
-- CA-31 : un email = un compte (insensible à la casse)
CREATE UNIQUE INDEX coach_email_uniq ON coach (lower(email));
CREATE UNIQUE INDEX coach_slug_uniq ON coach (slug);
CREATE TABLE seance_type (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
coach_id uuid NOT NULL REFERENCES coach(id) ON DELETE CASCADE,
titre text NOT NULL,
duree_minutes integer NOT NULL CHECK (duree_minutes BETWEEN 15 AND 240),
prix_cents integer NOT NULL CHECK (prix_cents > 0), -- RM-06 : EUR, intégral
lieu text NOT NULL,
actif boolean NOT NULL DEFAULT true, -- RM-12 : désactivation sans suppression
cree_le timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX seance_type_coach_idx ON seance_type (coach_id) WHERE actif;
-- Disponibilités hebdomadaires récurrentes (heure locale Europe/Paris, D-09)
CREATE TABLE disponibilite (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
coach_id uuid NOT NULL REFERENCES coach(id) ON DELETE CASCADE,
jour_semaine smallint NOT NULL CHECK (jour_semaine BETWEEN 1 AND 7), -- 1 = lundi
heure_debut time NOT NULL,
heure_fin time NOT NULL,
CONSTRAINT disponibilite_plage CHECK (heure_fin > heure_debut)
);
CREATE INDEX disponibilite_coach_idx ON disponibilite (coach_id, jour_semaine);
CREATE TABLE date_bloquee (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
coach_id uuid NOT NULL REFERENCES coach(id) ON DELETE CASCADE,
jour date NOT NULL,
UNIQUE (coach_id, jour)
);
-- RM-12 (refus du blocage si réservation CONFIRMEE ce jour) : contrôle applicatif, CA-25.
CREATE TABLE reservation (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
coach_id uuid NOT NULL REFERENCES coach(id),
seance_type_id uuid NOT NULL REFERENCES seance_type(id),
client_nom text NOT NULL,
client_email text NOT NULL,
client_mobile_e164 text NOT NULL,
debut timestamptz NOT NULL,
fin timestamptz NOT NULL,
prix_cents integer NOT NULL CHECK (prix_cents > 0), -- copie figée du prix
statut text NOT NULL DEFAULT 'EN_ATTENTE_PAIEMENT',
statut_paiement text NOT NULL DEFAULT 'AUCUN',
verrou_expire_le timestamptz, -- RM-04 : créée + 15 min
jeton_gestion text NOT NULL DEFAULT encode(gen_random_bytes(32), 'hex'), -- RM-13 : 256 bits
stripe_session_id text,
stripe_payment_intent_id text,
cree_le timestamptz NOT NULL DEFAULT now(),
mis_a_jour_le timestamptz NOT NULL DEFAULT now(),
annulee_le timestamptz,
CONSTRAINT reservation_statut_valide CHECK (statut IN
('EN_ATTENTE_PAIEMENT','CONFIRMEE','ANNULEE_CLIENT','ANNULEE_COACH','EXPIREE','TERMINEE')),
CONSTRAINT reservation_paiement_valide CHECK (statut_paiement IN
('AUCUN','PAYE','REMBOURSE','ECHEC_REMBOURSEMENT')),
CONSTRAINT reservation_plage CHECK (fin > debut),
-- RM-11 : mobile français normalisé E.164
CONSTRAINT reservation_mobile_e164 CHECK (client_mobile_e164 ~ '^\+33[67][0-9]{8}$'),
CONSTRAINT reservation_email_format CHECK (client_email ~ '^[^@\s]+@[^@\s]+\.[^@\s]+$'),
-- RM-04 : un verrou est obligatoire tant que le paiement est en attente
CONSTRAINT reservation_verrou_requis CHECK (statut <> 'EN_ATTENTE_PAIEMENT' OR verrou_expire_le IS NOT NULL),
-- RM-06 : CONFIRMEE implique un paiement capturé
CONSTRAINT reservation_confirmee_payee CHECK (statut <> 'CONFIRMEE' OR statut_paiement = 'PAYE'),
-- RM-01 + RM-05 : pas de chevauchement pour un même coach tant que la réservation
-- est EN_ATTENTE_PAIEMENT ou CONFIRMEE ; la première écriture gagne (CA-06).
CONSTRAINT reservation_pas_de_chevauchement EXCLUDE USING gist (
coach_id WITH =,
tstzrange(debut, fin, '[)') WITH &&
) WHERE (statut IN ('EN_ATTENTE_PAIEMENT','CONFIRMEE'))
);
CREATE UNIQUE INDEX reservation_jeton_uniq ON reservation (jeton_gestion); -- RM-13
CREATE UNIQUE INDEX reservation_session_uniq ON reservation (stripe_session_id)
WHERE stripe_session_id IS NOT NULL;
CREATE INDEX reservation_coach_debut_idx ON reservation (coach_id, debut DESC); -- tableau de bord (BE-13)
CREATE INDEX reservation_expiration_idx ON reservation (verrou_expire_le)
WHERE statut = 'EN_ATTENTE_PAIEMENT'; -- job RM-04
CREATE INDEX reservation_cloture_idx ON reservation (fin)
WHERE statut = 'CONFIRMEE'; -- job RM-15
-- Idempotence des webhooks Stripe (RM-06, CA-09)
CREATE TABLE evenement_stripe (
id_evenement text PRIMARY KEY, -- evt_... : doublon = INSERT en conflit, sans effet
type text NOT NULL,
recu_le timestamptz NOT NULL DEFAULT now(),
traite_le timestamptz
);
-- Rappels SMS : au plus un par réservation (RM-10, CA-18)
CREATE TABLE rappel_sms (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
reservation_id uuid NOT NULL UNIQUE REFERENCES reservation(id) ON DELETE CASCADE, -- jamais de doublon
envoi_prevu_le timestamptz NOT NULL, -- début - 24 h
statut text NOT NULL DEFAULT 'a_envoyer'
CHECK (statut IN ('a_envoyer','envoye','echec','annule')),
tentatives smallint NOT NULL DEFAULT 0 CHECK (tentatives BETWEEN 0 AND 2), -- 1 essai + 1 retry à +10 min
twilio_sid text,
derniere_erreur text,
envoye_le timestamptz
);
CREATE INDEX rappel_sms_a_envoyer_idx ON rappel_sms (envoi_prevu_le) WHERE statut = 'a_envoyer';
-- Journal des anomalies (RM-06 montant ≠ attendu, ECHEC_REMBOURSEMENT, échec SMS)
CREATE TABLE journal_anomalie (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
reservation_id uuid REFERENCES reservation(id) ON DELETE SET NULL,
type text NOT NULL,
detail jsonb NOT NULL DEFAULT '{}',
cree_le timestamptz NOT NULL DEFAULT now()
);
| Règle | Mécanisme |
|---|---|
| RM-01, RM-05 | EXCLUDE USING gist partiel sur EN_ATTENTE_PAIEMENT et CONFIRMEE |
| RM-04 | verrou_expire_le obligatoire, index dédié pour le job d'expiration |
| RM-06 | evenement_stripe (idempotence) et CONFIRMEE impossible sans PAYE |
| RM-10 | UNIQUE (reservation_id) sur rappel_sms |
| RM-11 | CHECK E.164 et email |
| RM-13 | Jeton 256 bits, index unique |
RM-02, RM-03 (délai min. 2 h, horizon 60 j), RM-07 et RM-08 (table de décision d'annulation), RM-12 (blocage de date) et RM-14 (connect_complet). Le job d'expiration libère le créneau en passant le statut à EXPIREE, ce qui sort la ligne de la contrainte d'exclusion.
API, intégrations et sécurité
5 hypothèses marquées
Conventions : JSON sur HTTPS ; erreurs { "code", "message" } ; heures ISO 8601 en UTC, affichées en Europe/Paris (D-09). Session coach par cookie HttpOnly, Secure, SameSite=Lax H. Accès client par jeton de gestion (RM-13), sans compte.
| ID | Méthode et chemin | Rôle autorisé | Entrée | Sortie | Erreurs | RM / CA |
|---|---|---|---|---|---|---|
| API-01 | POST /api/coach/inscription | Public | email, mot de passe, nom_affiche | 201 {id, slug} | 400 format ; 409 email déjà utilisé | BE-01 ; CA-31 |
| API-02 | POST /api/coach/connexion | Public | email, mot de passe | 200 + cookie de session | 401 identifiants erronés ; 429 | BE-01 |
| API-03 | POST /api/coach/connect/onboarding | Coach | — | 200 {url} (lien Stripe Connect) | 401 ; 502 Stripe | BE-02 ; RM-14, CA-28 |
| API-04 | GET /api/coach/connect/statut | Coach | — | 200 {connect_complet} | 401 | RM-14 ; CA-28 |
| API-05 | POST /api/coach/seances | Coach | titre, duree_minutes, prix_cents, lieu | 201 séance | 400 validation ; 401 | BE-03 ; RM-06, CA-32 |
| API-06 | PATCH /api/coach/seances/{id} | Coach propriétaire | champs modifiés ou actif=false | 200 séance | 400 ; 401 ; 404 | RM-12, RM-13 |
| API-07 | PUT /api/coach/disponibilites | Coach | liste {jour_semaine, heure_debut, heure_fin} | 200 liste | 400 plage invalide ; 401 | BE-04 ; RM-01, CA-01 |
| API-08 | POST /api/coach/dates-bloquees | Coach | jour | 201 | 401 ; 409 réservation CONFIRMEE ce jour | RM-12 ; CA-25, CA-02 |
| API-09 | DELETE /api/coach/dates-bloquees/{id} | Coach propriétaire | — | 204 | 401 ; 404 | RM-01 |
| API-10 | GET /api/coach/reservations | Coach | filtres statut, du, au | 200 liste (statut, statut_paiement, alerte) | 401 | BE-13 ; RM-13, CA-30, CA-26 |
| API-11 | POST /api/coach/reservations/{id}/annuler | Coach propriétaire | — | 200 {statut, statut_paiement} | 401 ; 404 ; 409 statut non annulable ou séance terminée | BE-12 ; RM-08, RM-15, CA-16, CA-17 |
| API-12 | GET /api/public/coachs/{slug} | Public | — | 200 coach + séances actives (vide si connect_complet faux) | 404 | BE-05 ; RM-14, CA-28, CA-32 |
| API-13 | GET /api/public/coachs/{slug}/creneaux | Public | seance_type_id, du, au | 200 liste de débuts libres | 400 hors horizon ; 404 | BE-05 ; RM-01 à RM-03, CA-01 à CA-04 |
| API-14 | POST /api/public/reservations | Public | seance_type_id, debut, nom, email, mobile | 201 {reservation_id, jeton_gestion, checkout_url} | 400 mobile/email invalide ; 409 créneau indisponible ; 422 coach sans Connect, créneau hors règles | BE-06, BE-07, BE-08 ; RM-04, RM-05, RM-11, RM-14, CA-05, CA-06, CA-23, CA-24 |
| API-15 | GET /api/public/reservations/{jeton} | Détenteur du jeton | — | 200 détail, annulable (booléen), règle d'annulation | 404 jeton inconnu, sans fuite | BE-11 ; RM-13, CA-27, CA-15 |
| API-16 | POST /api/public/reservations/{jeton}/annuler | Détenteur du jeton | — | 200 {statut, statut_paiement} | 404 ; 409 refus (≤ 24 h, terminée, déjà annulée) | BE-11 ; RM-07, RM-15, CA-13, CA-14, CA-15 |
| API-17 | POST /api/webhooks/stripe | Stripe (signature) | événement signé | 200 ; doublon : 200 sans effet | 400 signature invalide | BE-08, BE-09 ; RM-04, RM-06, CA-08 à CA-12 |
| JOB-01 | Worker, chaque minute | Interne | — | Réservations EN_ATTENTE_PAIEMENT échues → EXPIREE | — | RM-04 ; CA-07 |
| JOB-02 | Worker, chaque minute | Interne | — | Envoi des rappel_sms échus (réservation CONFIRMEE), retry à +10 min | — | BE-10 ; RM-10, CA-18 à CA-22 |
| JOB-03 | Worker, chaque minute | Interne | — | CONFIRMEE passée de fin → TERMINEE | — | RM-15 ; CA-29 |
Comportement structurant :
INSERT dans reservation (la contrainte reservation_pas_de_chevauchement tranche la concurrence, violation → 409), puis création de la session Checkout avec stripe_session_id. Si Stripe échoue, la ligne passe en EXPIREE.INSERT dans evenement_stripe ; conflit sur id_evenement → sans effet. Montant ≠ prix_cents → pas de confirmation, ligne dans journal_anomalie. Réservation déjà EXPIREE → remboursement automatique, statut_paiement = REMBOURSE.ECHEC_REMBOURSEMENT et anomalie journalisée.account.updated (reçu par API-17) met à jour connect_complet.| Service | Usage | Point de défaillance | Comportement de repli |
|---|---|---|---|
| Stripe Checkout | Paiement de la réservation | Indisponibilité à la création de session | Réservation EXPIREE, 502 au client, créneau libéré |
| Stripe webhooks | Confirmation, account.updated | Webhook perdu ou en retard | Stripe rejoue ; si le verrou expire avant, paiement tardif remboursé (CA-11) |
| Stripe Connect / remboursements | Onboarding, remboursements | Refus ou solde insuffisant (RM-09) | ECHEC_REMBOURSEMENT, alerte au coach, traitement manuel |
| Twilio | SMS de rappel et d'annulation coach | Erreur API, mobile invalide | 1 retry à +10 min, puis echec journalisé ; réservation inchangée (CA-21) |
| Resend H | Email de confirmation et lien de gestion | Erreur API | Retry par le worker ; lien de gestion aussi affiché sur E-03 |
| PostgreSQL | Données, verrou, jobs | Indisponibilité | 503 ; aucun état partiel grâce aux transactions |
mot_de_passe_hash), limitation des tentatives sur API-02, session expirante H.coach_id de la session ; accès hors périmètre → 404 (CA-26). Jeton de gestion à 256 bits, 404 uniforme si inconnu (CA-27).Plan de développement
1 hypothèse marquée
Hypothèses de plan H : un seul dépôt Next.js + PostgreSQL ; Stripe, Twilio et Resend sont isolés derrière des interfaces simulables (mocks en test) ; tests : Vitest (unitaire et intégration sur Postgres de test) et Playwright (bout en bout). La tranche verticale prioritaire est P-01 (réserver et payer) : elle est livrée dès le jalon J3. Chaque tâche suppose les corrections EC-xx intégrées (marquées « corrige EC-xx »).
| Écart | Décision appliquée dans le plan |
|---|---|
| EC-01 | Webhook tardif sur EXPIREE : PAYE puis REMBOURSE dans une même transaction (T-12) |
| EC-02 | Insertion de rappel_sms à la confirmation (T-11) ; passage à annule aux annulations (T-15, T-17) |
| EC-03 | SMS d'annulation coach conservé ; D-05 devient « 1 rappel + 1 SMS d'annulation coach éventuel », contenu transactionnel (T-17) |
| EC-04 | Jeton = 256 bits partout ; RM-13 aligné (T-02) |
| EC-05 | Blocage de date refusé si réservation EN_ATTENTE_PAIEMENT ou CONFIRMEE ce jour ; en plus, la confirmation Stripe d'une réservation sur date bloquée n'est pas empêchée car le créneau est verrouillé avant (T-08, T-12) |
| EC-06 | Mobile = 06/07 uniquement ; RM-11 aligné ; validation API avant insertion, 400 et non 500 (T-09) |
| EC-07 | Ajout des GET coach séances, disponibilités, dates bloquées (T-06, T-07, T-08) |
| EC-08 | E-03 utilise API-15 par jeton (T-13) |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-01 | Initialiser Next.js (TS), lint, Vitest, Playwright, variables d'environnement typées, CI | package.json, src/lib/env.ts, .github/workflows/ci.yml | — | — | npm run lint && npm test verts en CI | Ne jamais committer de clé ; échouer au démarrage si une variable manque |
| T-02 | Migrations : schéma §4 complet, avec jeton 256 bits (corrige EC-04) et CHECK mobile ^\+33[67][0-9]{8}$ | db/migrations/001_init.sql | T-01 | CA-06, CA-31 | Test d'intégration : insertion chevauchante rejetée par EXCLUDE ; email en double rejeté | Activer btree_gist avant la contrainte ; tester la contrainte sur base réelle, pas en mémoire |
| T-03 | Adaptateurs simulables Stripe, Twilio, Resend, Horloge (interfaces et mocks) | src/adapters/*.ts | T-01 | — | Tests unitaires avec mocks ; horloge injectable | Sans horloge injectable, les tests 24 h et 15 min sont impossibles |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-04 | API-01/02 : inscription, connexion, session cookie HttpOnly, hash argon2id, limitation des tentatives | src/app/api/coach/inscription, connexion, src/lib/auth.ts | T-02 | CA-31 | Test : second compte avec le même email (casse différente) → 409 | Comparer l'email en lower() ; ne pas révéler si l'email existe à la connexion |
| T-05 | API-03/04 : onboarding Connect Express, statut ; account.updated met à jour connect_complet (traité dans T-12) | src/app/api/coach/connect/* | T-04, T-03 | CA-28 | Test mock Stripe : lien renvoyé ; statut reflète connect_complet | Ne jamais déduire « complet » du retour navigateur, seulement du webhook |
| T-06 | Écrans E-05 et E-06 (inscription/connexion, onboarding) | src/app/(coach)/connexion, onboarding | T-04, T-05 | CA-31 | Playwright : création de compte puis affichage du statut Connect | Messages d'erreur liés aux champs (AM-03) |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-07 | API-05/06 + GET /api/coach/seances (corrige EC-07) : création, modification, désactivation (actif=false) | src/app/api/coach/seances | T-04 | CA-32 | Test : séance 60 min à 5000 cents créée, relue par GET ; accès à la séance d'un autre coach → 404 | Filtrer toujours par coach_id de session ; prix en centimes entiers |
| T-08 | API-07/08/09 + GET /api/coach/disponibilites et GET /api/coach/dates-bloquees (corrige EC-07) ; blocage refusé si réservation EN_ATTENTE_PAIEMENT ou CONFIRMEE ce jour (corrige EC-05) | src/app/api/coach/disponibilites, dates-bloquees | T-04 | CA-02, CA-25 | Test : blocage sur jour avec réservation CONFIRMEE → 409 ; idem avec EN_ATTENTE_PAIEMENT | Calculer « le jour » en Europe/Paris, pas en UTC |
| T-09 | Module de calcul des créneaux : disponibilités, dates bloquées, durée, chevauchements, délai min 2 h, horizon 60 j | src/domain/creneaux.ts | T-02, T-03 | CA-01, CA-02, CA-03, CA-04 | Tests unitaires CA-01 à CA-04 avec horloge figée | Passage heure d'été/hiver : tester un lundi de changement d'heure |
| T-10 | Écran E-07 (séances, disponibilités, dates bloquées, lien public copiable) | src/app/(coach)/seances | T-07, T-08 | CA-02, CA-25, CA-32 | Playwright : création séance et disponibilité, blocage refusé affiché | Afficher l'erreur 409 en texte clair (AM-04) |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-11 | API-12/13 : page publique et créneaux ; séances masquées si connect_complet faux | src/app/api/public/coachs/[slug] | T-09, T-05 | CA-01 à CA-04, CA-28, CA-32 | Tests API : coach sans Connect → liste de séances vide | Ne pas exposer d'email ni d'id interne coach |
| T-12 | API-14 : validation entrées (email, mobile 06/07 normalisé E.164, 400 avant insertion, corrige EC-06), INSERT réservation avec verrou 15 min, session Checkout ; violation d'exclusion → 409 ; échec Stripe → EXPIREE | src/app/api/public/reservations, src/domain/reservation.ts, src/lib/telephone.ts | T-11, T-03 | CA-05, CA-06, CA-23, CA-24 | Test concurrence : 2 requêtes parallèles → 1 × 201, 1 × 409 ; « 12345 » → 400 ; « 06 12 34 56 78 » → +33612345678 | Une transaction ; ne pas pré-vérifier la disponibilité puis insérer (course) : la contrainte tranche |
| T-13 | API-17 webhook Stripe : signature, idempotence evenement_stripe, CONFIRMEE si montant égal, anomalie sinon ; à la confirmation, insertion de rappel_sms si début − now > 24 h (corrige EC-02) ; webhook tardif sur EXPIREE : PAYE puis REMBOURSE dans la même transaction (corrige EC-01) ; account.updated → connect_complet | src/app/api/webhooks/stripe, src/domain/paiement.ts | T-12 | CA-08 à CA-12, CA-19 | Tests : doublon sans effet, signature invalide → 400, montant ≠ → pas de confirmation et ligne journal_anomalie, paiement tardif → EXPIREE + REMBOURSE | Lire le corps brut pour la signature ; INSERT dans evenement_stripe et traitement dans la même transaction |
| T-14 | JOB-01 : worker d'expiration des verrous (cron 1 min) | src/worker/expiration.ts | T-12 | CA-07 | Test avec horloge : réservation à 16 min → EXPIREE, créneau à nouveau réservable | Ne toucher que EN_ATTENTE_PAIEMENT ; requête idempotente |
| T-15 | Écrans E-01, E-02, E-03 (E-03 lit API-15 par jeton, corrige EC-08), compte à rebours, états d'erreur | src/app/c/[slug], reserver, retour | T-11, T-12, T-13 | CA-05, CA-06, CA-23, CA-24, CA-07 | Playwright : parcours P-01 complet avec Stripe simulé, du créneau à « confirmée » | Page de retour : statut « en cours de validation » tant que le webhook n'est pas reçu |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-16 | Email de confirmation avec lien de gestion (envoi après confirmation, retry par le worker) | src/adapters/email.ts, src/domain/notifications.ts | T-13 | CA-08, CA-09 | Test : 1 email à la confirmation, 0 sur webhook doublon | Envoyer après commit de la transaction, pas dedans |
| T-17 | JOB-02 : envoi des rappels SMS, 1 retry à +10 min puis echec ; modèle de message fixe sans promotion ; jamais de doublon | src/worker/rappels.ts, src/domain/sms.ts | T-13, T-03 | CA-18 à CA-22 | Tests : 1 SMS à T − 24 h ; erreur Twilio → retry puis echec, réservation inchangée ; contenu = modèle fixe | UNIQUE(reservation_id) + mise à jour atomique du statut avant envoi pour éviter le double envoi |
| T-18 | API-15/16 : détail et annulation client par jeton, table de décision ; remboursement intégral ; rappel_sms.statut='annule' à l'annulation (corrige EC-02) ; 404 uniforme si jeton inconnu | src/app/api/public/reservations/[jeton] | T-13 | CA-13 à CA-15, CA-27 | Tests : > 24 h → ANNULEE_CLIENT + REMBOURSE ; ≤ 24 h → 409 ; 2ᵉ appel idempotent sans second remboursement ; jeton inconnu → 404 | Clé d'idempotence Stripe sur le remboursement ; frontière exacte à 24 h pile = refus |
| T-19 | Écran E-04 (gestion client, confirmation d'annulation avec issue financière, AM-06) | src/app/g/[jeton] | T-18 | CA-13 à CA-15, CA-27 | Playwright : annulation depuis le lien, puis réouverture → « déjà annulée » | Boîte de dialogue accessible au clavier |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-20 | API-10/11 : liste des réservations et annulation coach, remboursement automatique ; ECHEC_REMBOURSEMENT + anomalie + alerte ; rappel_sms → annule ; email + SMS d'annulation coach au client, contenu transactionnel, SMS documenté dans D-05 (corrige EC-03) | src/app/api/coach/reservations | T-18, T-17 | CA-16, CA-17, CA-26, CA-30 | Tests : annulation à 2 h → ANNULEE_COACH + REMBOURSE + email et SMS ; échec Stripe → ECHEC_REMBOURSEMENT ; réservation d'un autre coach → 404 | Ne pas bloquer l'annulation si le remboursement échoue ; ne pas rembourser une réservation EN_ATTENTE_PAIEMENT (→ EXPIREE) |
| T-21 | JOB-03 : clôture CONFIRMEE → TERMINEE ; refus d'annulation ensuite | src/worker/cloture.ts | T-18, T-20 | CA-29 | Test horloge : après fin → TERMINEE, annulation → 409 | Comparer sur fin, pas sur debut |
| T-22 | Écran E-08 (tableau de bord, alerte ECHEC_REMBOURSEMENT, annulation avec confirmation) | src/app/(coach)/tableau-de-bord | T-20, T-21 | CA-16, CA-17, CA-26, CA-29, CA-30 | Playwright : 3 réservations affichées avec statuts en texte ; annulation et alerte visibles | Statuts en texte, pas seulement en couleur (AM-04) |
| ID | Objectif | Modules ou fichiers | Dépend de | CA | Preuve de fin | Piège à éviter |
|---|---|---|---|---|---|---|
| T-23 | Limitation de débit (API-02, 13, 14, 16), en-têtes de sécurité, journaux sans mobile ni email en clair | src/middleware.ts, src/lib/log.ts | T-12, T-18 | CA-26, CA-27 | Test : rafale sur API-14 → 429 ; inspection des logs sans donnée personnelle | Limiter aussi par IP sur les routes publiques |
| T-24 | Tests de bout en bout sur les parcours P-01 à P-04 et mention RGPD en E-02 | e2e/*.spec.ts, E-02 | T-15, T-19, T-22 | CA-05 à CA-30 | npx playwright test vert en CI | Mocks Stripe/Twilio : ne jamais appeler les services réels en CI |
| T-25 | README : installation, variables d'environnement, lancement des workers, limites connues et hypothèses à vérifier (frais de remboursement Connect, solde insuffisant, qualification juridique des SMS) | README.md | T-24 | — | Installation à froid réussie en suivant le README | Lister les limites telles quelles, sans les masquer |
| CA | Tâche(s) |
|---|---|
| CA-01 | T-09, T-11 |
| CA-02 | T-08, T-09, T-10 |
| CA-03 | T-09, T-11 |
| CA-04 | T-09, T-11 |
| CA-05 | T-12, T-15, T-24 |
| CA-06 | T-02, T-12, T-15 |
| CA-07 | T-14, T-15 |
| CA-08 | T-13, T-16 |
| CA-09 | T-13, T-16 |
| CA-10 | T-13 |
| CA-11 | T-13 |
| CA-12 | T-13 |
| CA-13 | T-18, T-19 |
| CA-14 | T-18, T-19 |
| CA-15 | T-18, T-19 |
| CA-16 | T-20, T-22 |
| CA-17 | T-20, T-22 |
| CA-18 | T-17 |
| CA-19 | T-13, T-17 |
| CA-20 | T-17, T-18 |
| CA-21 | T-17 |
| CA-22 | T-17 |
| CA-23 | T-12, T-15 |
| CA-24 | T-12, T-15 |
| CA-25 | T-08, T-10 |
| CA-26 | T-20, T-22, T-23 |
| CA-27 | T-18, T-19, T-23 |
| CA-28 | T-05, T-11 |
| CA-29 | T-21, T-22 |
| CA-30 | T-20, T-22 |
| CA-31 | T-02, T-04, T-06 |
| CA-32 | T-07, T-10, T-11 |
Les 32 CA sont couverts. Les T-13 et T-17 s'appuient sur rappel_sms créé à la confirmation (EC-02) ; l'ordre T-13 → T-17 → T-18 → T-20 respecte les dépendances.
Relecture indépendante
| ID | Gravité | Où | Problème | Correction |
|---|---|---|---|---|
| EC-01 | Haute | §4 reservation_confirmee_payee vs RM-06 / CA-08 | Contrainte CONFIRMEE ⇒ PAYE. Mais RM-07/RM-08 passent en ANNULEE_* avec REMBOURSE : cohérent. En revanche TERMINEE n'a pas de contrainte, et surtout un remboursement automatique sur EXPIREE (RM-04/CA-11) est incohérent avec RM-06 « réservation expirée = créneau libéré » : le client payé tardivement ne voit pas son créneau garanti. Ce cas est traité, mais le paiement PAYE transitoire avant REMBOURSE n'est pas défini. | Préciser en RM-04 : webhook tardif → paiement PAYE puis REMBOURSE dans la même transaction. |
| EC-02 | Haute | RM-10 / §4 rappel_sms / JOB-02 | rappel_sms n'est jamais créé ni annulé dans les parcours : aucune règle ni API ne dit qui insère la ligne (à la confirmation, API-17) ni qui passe annule (annulations RM-07/RM-08). CA-19 (< 24 h : pas de rappel) suppose de ne pas insérer. | Ajouter à API-17 : à la confirmation, insérer rappel_sms si début − now() > 24 h. Ajouter à API-11/API-16 : passer rappel_sms.statut = 'annule'. |
| EC-03 | Moyenne | RM-08 / §5 intégrations | RM-08 prévoit « email + SMS au client » à l'annulation coach, mais aucun SMS d'annulation n'est dans D-05 (1 SMS par réservation), RM-10, ni les CA (CA-16 le cite). Coût et cadre D-06 non traités. | Mettre à jour D-05 : « 1 rappel + 1 SMS d'annulation coach éventuel » et garder son contenu transactionnel, ou retirer le SMS de RM-08/CA-16. |
| EC-04 | Moyenne | RM-13 vs §4 | RM-13 dit « jeton ≥ 128 bits », §4/§5 en fournissent 256 bits. Écart mineur de formulation. | Aligner RM-13 sur « 256 bits » (ou « ≥ 128 » partout). |
| EC-05 | Moyenne | RM-12 / CA-25 vs API-08 | RM-12 : blocage refusé si réservation CONFIRMEE ; la réservation EN_ATTENTE_PAIEMENT ce jour n'est pas couverte et peut devenir CONFIRMEE sur une date bloquée. | Étendre à EN_ATTENTE_PAIEMENT ou filtrer les créneaux/confirmations sur dates bloquées. |
| EC-06 | Moyenne | §4 CHECK reservation_mobile_e164 vs RM-11 | Regex \+33[67]… n'accepte que les mobiles 06/07 ; RM-11 dit « +33 / 0X » (tout format français). CA-24 passe, mais un 01–05, 08–09 est accepté par RM-11 et rejeté en base (500 au lieu de 400). | Aligner RM-11 sur « mobile français 06/07 » et valider côté API avant insertion. |
| EC-07 | Faible | §3 E-01/E-07 vs API | Aucun endpoint de lecture pour E-07 (liste séances, disponibilités, dates bloquées du coach) ni de suppression de disponibilité/séance ; GET coach manquants. | Ajouter GET /api/coach/seances, GET /api/coach/disponibilites, GET /api/coach/dates-bloquees. |
| EC-08 | Faible | §3 E-03 vs API | E-03 affiche le statut « en attente du webhook » mais API-15 est la seule lecture et est présentée pour E-04. | Indiquer que E-03 utilise API-15 par jeton. |
Un dossier offert, sans carte bancaire. Vos propres clés d'IA acceptées dès l'offre gratuite.
Pour juger sur pièces, avec votre idée.
Pour construire vos produits, seul.
Pour une équipe qui partage la même spec.
Un studio qui écrit la spec de votre projet logiciel, la rend lisible par votre outil de code IA, puis vérifie que le code la respecte. Vous gardez un seul document de référence, du premier prompt à la mise en production.
Il planifie la tâche en cours. Kodrudder décrit le produit entier : règles métier, données, cas limites, critères d'acceptation. Et la spec ne disparaît pas à la fin de la session : elle sert de référence à chaque nouvelle tâche.
Oui si vous utilisez Cursor, Claude Code, Codex, Windsurf, Copilot, Gemini, Lovable, Bolt, v0 ou Replit. Le dossier s'exporte dans le format que chacun attend, et un serveur MCP permet à votre outil de le lire directement.
Oui. Donnez un lien GitHub, public ou privé, ou déposez une archive. Kodrudder reconstitue la spec de ce qui existe, signale les points faibles et prépare les fichiers de contexte pour votre outil.
Votre idée, votre code et votre dossier ne servent qu'à produire votre dossier. Nous ne les revendons pas et ne les utilisons pas pour entraîner des modèles. Avec votre propre clé d'IA, vous choisissez aussi le fournisseur.
Oui. Votre premier dossier ne demande ni compte ni carte bancaire. Vous créez un compte gratuit pour le conserver.
Sans carte bancaire.