@nodefony/devkit 10.0.0-beta.5 → 10.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.157.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.157.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +3 -3
- package/dist/nodefony/controllers/DevkitController.js +1 -1
- package/dist/nodefony/controllers/McpController.js +2 -2
- package/dist/nodefony/controllers/ProfileSessionController.js +1 -1
- package/dist/nodefony/mcp/profileRoute.js +28 -9
- package/dist/nodefony/service/DevkitService.js +4 -4
- package/docs/index.md +1 -1
- package/package.json +11 -11
- package/skills/nodefony-add-crud/SKILL.md +38 -23
- package/skills/nodefony-add-realtime-channel/SKILL.md +376 -111
- package/skills/nodefony-add-realtime-channel/references/binaire.md +191 -0
- package/skills/nodefony-add-realtime-channel/references/production.md +121 -0
- package/skills/nodefony-browser/SKILL.md +27 -2
- package/skills/nodefony-browser/scripts/audit.mjs +12 -0
- package/skills/nodefony-browser/scripts/inspect.mjs +40 -81
- package/skills/nodefony-browser/scripts/lib/actions.mjs +113 -0
- package/skills/nodefony-browser/scripts/lib/browser.mjs +50 -11
- package/skills/nodefony-browser/scripts/lib/probes.mjs +56 -0
- package/skills/nodefony-browser/scripts/watch.mjs +27 -11
- package/skills/nodefony-dev/SKILL.md +11 -0
- package/skills/nodefony-dev/references/rapport-de-build.md +19 -0
- package/skills/nodefony-devops/SKILL.md +28 -21
- package/skills/nodefony-migrate-schema/SKILL.md +110 -20
- package/skills/nodefony-migrate-schema/references/verdicts.md +22 -20
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nodefony-migrate-schema
|
|
3
3
|
description: >
|
|
4
|
-
Fait évoluer le schéma d'une base Nodefony et le porte en production, par
|
|
5
|
-
`orm:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
exemplaires. À charger AVANT de modifier une entité déjà en base, ou avant de déployer un schéma
|
|
10
|
-
changé.
|
|
4
|
+
Fait évoluer le schéma d'une base Nodefony et le porte en production, par `orm:generate` et
|
|
5
|
+
`orm:migrate` — jamais par un `ALTER` à la main ni en supprimant la base. Porte la lecture de
|
|
6
|
+
l'état, le plan avant le geste, chaque code de refus et son geste, le renommage déclaré, les trois
|
|
7
|
+
interdits qui cassent un historique, et le déploiement où les migrations passent AVANT les
|
|
8
|
+
exemplaires. À charger AVANT de modifier une entité déjà en base, ou de déployer un schéma changé.
|
|
11
9
|
Déclencheurs : "j'ai ajouté un champ à une entité", "la colonne n'existe pas en base",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
10
|
+
"migrer le schéma", "orm:migrate", "orm:generate", "déployer un changement de schéma",
|
|
11
|
+
"no such column",
|
|
14
12
|
"column does not exist", "ma base ne correspond plus au code", "adopter une base existante",
|
|
15
13
|
"réparer une migration en échec", "éprouver une migration sans casser ma base",
|
|
16
|
-
"rejouer les migrations depuis zéro"
|
|
14
|
+
"rejouer les migrations depuis zéro", "renommer une colonne ou une table",
|
|
15
|
+
"changer le type ou la longueur d'une colonne", "changer de base", "passer à PostgreSQL ou
|
|
16
|
+
MySQL".
|
|
17
17
|
metadata:
|
|
18
|
-
version:
|
|
18
|
+
version: 4
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
# Faire évoluer un schéma, et le porter en production
|
|
@@ -29,18 +29,27 @@ metadata:
|
|
|
29
29
|
> la ligne exacte :
|
|
30
30
|
> `node node_modules/@nodefony/devkit/skills/nodefony-dev/scripts/docs.mjs <termes>`.
|
|
31
31
|
|
|
32
|
-
## 1. La seule chose à savoir avant tout le reste
|
|
32
|
+
## 1. La seule chose à savoir avant tout le reste — QUI fabrique le schéma ici ?
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
La clé `ddl` d'un connecteur répond à une seule question : qui fabrique les tables. Le mode n'est
|
|
35
|
+
presque jamais écrit, il se DÉDUIT — et c'est lui qui décide du geste.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
| Situation | Mode | Qui fabrique les tables |
|
|
38
|
+
| -------------------------------------------------------- | --------- | ----------------------------------------------------------- |
|
|
39
|
+
| `ddl` écrit dans la configuration | lui | ce que dit la configuration — il gagne toujours |
|
|
40
|
+
| développement, l'application versionne **≥ 1** migration | `migrate` | les migrations, appliquées au démarrage |
|
|
41
|
+
| développement, **aucune** migration ; ou `NODE_ENV=test` | `auto` | le démarrage, d'après les entités (création + ajouts vides) |
|
|
42
|
+
| **tout le reste**, production comprise | `none` | personne au démarrage : un job lance `orm:migrate` AVANT |
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
🔴 **Une application créée par `nodefony create app` avec un ORM SQL est en `migrate` dès
|
|
45
|
+
l'installation** : le générateur écrit ET applique sa migration initiale. Le cas courant, en
|
|
46
|
+
développement, est donc : **une entité change → une migration s'écrit** (§ 3). Ne crois pas
|
|
47
|
+
qu'« en développement la base suit le code » sans avoir vérifié qu'aucune migration n'existe
|
|
48
|
+
(`npx nodefony orm:migrate:status --json`).
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
En `auto` seulement, un champ ajouté **qui accepte le vide** est posé au démarrage suivant — rien à
|
|
51
|
+
taper. Tout le reste (renommage, type, longueur, suppression, champ obligatoire) n'y est JAMAIS
|
|
52
|
+
rattrapé : l'ancienne colonne reste en base, la nouvelle naît vide.
|
|
44
53
|
|
|
45
54
|
## 2. Lire l'état — deux voies, selon que l'application tourne
|
|
46
55
|
|
|
@@ -115,6 +124,62 @@ relue et versionnée en amont, et c'est `orm:migrate` seul qui l'applique.
|
|
|
115
124
|
> second échoue sur un objet qui n'a jamais existé. Un `ddl` écrit dans la configuration gagne
|
|
116
125
|
> toujours ; sous `NODE_ENV=test`, rien ne change.
|
|
117
126
|
|
|
127
|
+
### 🔴 Un RENOMMAGE — le DÉCLARER, jamais le laisser deviner
|
|
128
|
+
|
|
129
|
+
Une colonne qui disparaît pendant qu'une autre apparaît, c'est un renommage (les données suivent)
|
|
130
|
+
OU une suppression puis un ajout (les données sont perdues). Aucun diff ne voit une intention. Ne
|
|
131
|
+
lance donc JAMAIS `orm:generate` nu après avoir renommé un champ : il s'arrête
|
|
132
|
+
(`NF_GENERATE_NEEDS_ANSWER`), et **il n'y a pas de question à laquelle répondre** — l'outil tourne
|
|
133
|
+
sans terminal, humain devant l'écran compris. La réponse se DÉCLARE :
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# une colonne : la table sous le nom que porte son entité
|
|
137
|
+
npx nodefony orm:generate --name titre_en_anglais --rename article.titre=title
|
|
138
|
+
# une table, puis une colonne DANS la table renommée (son NOUVEAU nom)
|
|
139
|
+
npx nodefony orm:generate --name lignes --rename invoice_line=invoice_det --rename invoice_det.fk_parent_line=fk_parent
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- La migration porte un `RENAME`, **changement de type compris** (`varchar(8)` → `varchar(16)`
|
|
143
|
+
renommé ET élargi s'écrit en entier).
|
|
144
|
+
- Le rapport `--json` le confirme : `renamed: ["article.titre → title"]`. Relis le fichier quand même.
|
|
145
|
+
- Un nom mal écrit, une ancienne colonne absente du dernier instantané, un nouveau nom qu'aucune
|
|
146
|
+
entité ne déclare : refus `NF_GENERATE_RENAME`, **rien n'est écrit**.
|
|
147
|
+
- Une VRAIE suppression ET un ajout sans rapport dans la même table : **deux générations** — d'abord
|
|
148
|
+
l'entité sans la colonne retirée (la perte est nommée par le garde destructif), puis avec
|
|
149
|
+
l'ajout. Ne déclare pas `--rename` pour faire taire l'outil : ce serait mentir sur les données.
|
|
150
|
+
|
|
151
|
+
Allonger une colonne (`varchar(16)` → `varchar(32)`) ou monter un entier de rang (`integer` →
|
|
152
|
+
`bigint`) n'est PAS destructif : le générateur le constate sur l'état de départ et n'exige rien. Le
|
|
153
|
+
raccourcir, ou rendre la colonne obligatoire, reste refusé sans `--allow-destructive`.
|
|
154
|
+
|
|
155
|
+
### Les pièges d'un schéma qui ÉVOLUE — constatés en faisant migrer un vrai progiciel
|
|
156
|
+
|
|
157
|
+
Chacun a été rencontré en portant un schéma réel d'une version à la suivante, sur SQLite,
|
|
158
|
+
PostgreSQL, MariaDB et MySQL. Le geste est le seul qui ait tenu sur les quatre.
|
|
159
|
+
|
|
160
|
+
1. **Renommer la PROPRIÉTÉ sans renommer la colonne ne demande AUCUNE migration.** Le modificateur
|
|
161
|
+
`column` garde le nom en base : `title: { kind: "string", length: 180, column: "titre" }`. Le
|
|
162
|
+
code lit `title`, la base garde `titre`, `orm:generate` répond « rien à écrire ». Choisis-le
|
|
163
|
+
quand seul le nom vu par le code doit changer — c'est le renommage qui ne coûte rien.
|
|
164
|
+
2. **Une table renommée fait apparaître des `DROP CONSTRAINT` / `DROP INDEX` puis leurs `ADD`** :
|
|
165
|
+
les noms de contraintes que le kit dérive du nom de table changent, la base garde les anciens.
|
|
166
|
+
En SQLite, la table est même RECRÉÉE (`__new_<table>`, recopie, `DROP TABLE`, `RENAME`). C'est
|
|
167
|
+
la mécanique, pas une perte, et le garde ne la signale pas. Ce qui se vérifie : la ligne
|
|
168
|
+
`renamed` du rapport, et **aucun `DROP COLUMN`** dans le fichier.
|
|
169
|
+
3. **Une référence posée sur des lignes DÉJÀ remplies échoue si une ligne pointe vers rien** —
|
|
170
|
+
sur les quatre moteurs : PostgreSQL et MySQL refusent l'`ADD CONSTRAINT`, SQLite refuse la
|
|
171
|
+
validation (« référence(s) orpheline(s) », table et ligne nommées). La migration est annulée et
|
|
172
|
+
un marqueur d'échec posé. Geste : corriger d'ABORD les lignes dans une migration libre
|
|
173
|
+
(`--custom` : `UPDATE … SET fk = NULL WHERE …`), PUIS déclarer la référence ; après un échec,
|
|
174
|
+
`orm:migrate:repair` lève le marqueur une fois la cause traitée.
|
|
175
|
+
4. **Retirer un champ de l'entité, c'est `DROP COLUMN`** : refusé sans `--allow-destructive`.
|
|
176
|
+
Un progiciel qui abandonne une colonne la laisse souvent en base sur les installations
|
|
177
|
+
existantes (le script de passage réel ne la supprime pas). Si ses données comptent encore,
|
|
178
|
+
garde le champ, facultatif, plutôt que de le retirer.
|
|
179
|
+
5. **Une évolution se prouve sur une base PEUPLÉE, jamais vide** (§ 4 b). Une table vide ne
|
|
180
|
+
déclenche ni la recréation SQLite d'une table référencée, ni une référence orpheline : un défaut
|
|
181
|
+
de l'applicateur SQLite n'apparaissait QUE sur des lignes réelles. Une ligne par table suffit.
|
|
182
|
+
|
|
118
183
|
### 🔴 Un champ OBLIGATOIRE sur une table PEUPLÉE — ton moteur ne fait pas ce que tu crois
|
|
119
184
|
|
|
120
185
|
Ajouter une colonne `NOT NULL` **sans valeur par défaut** à une table qui porte déjà des lignes n'a
|
|
@@ -218,6 +283,29 @@ Deux choses qu'il rapporte et qu'il faut lire :
|
|
|
218
283
|
> Cela ne concerne QUE cette commande de reprise : la création des tables, leur migration et le
|
|
219
284
|
> fonctionnement de l'application sont inchangés sur MariaDB.
|
|
220
285
|
|
|
286
|
+
### Changer de BASE — de SQLite à PostgreSQL, MySQL ou MariaDB
|
|
287
|
+
|
|
288
|
+
Une entité écrite par `create entity` est une description PORTABLE (`defineTable`) : elle suit la
|
|
289
|
+
base du connecteur, **sans être réécrite**. Changer de moteur tient en quatre gestes :
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
npm install pg # ou mysql2 — le pilote de la NOUVELLE base (absent : le démarrage le nomme)
|
|
293
|
+
# .env : NF_DATABASE_URL=postgres://user:secret@hote:5432/app (le dialecte se déduit de l'URL)
|
|
294
|
+
npx nodefony orm:generate --name initiale # migration INITIALE de ce dialecte
|
|
295
|
+
npx nodefony orm:migrate
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
- **Les migrations se rangent par dialecte** (`migrations/<dialecte>/`) : celles de SQLite ne
|
|
299
|
+
s'appliquent jamais ailleurs, d'où la migration initiale du nouveau moteur.
|
|
300
|
+
- 🔴 **Les DONNÉES ne suivent pas.** Le schéma change de base, les lignes restent dans l'ancienne :
|
|
301
|
+
aucune commande ne les transfère — export puis import, à ta charge.
|
|
302
|
+
- **Une table NATIVE ne suit pas** (`sqliteTable`, ou `create entity --dialect <moteur>`) : pointée
|
|
303
|
+
vers un autre moteur, l'application refuse de démarrer en nommant l'entité
|
|
304
|
+
(`EntityNotPortedError`). Régénère-la sans `--dialect` (`create entity <Nom> … --force`).
|
|
305
|
+
- **Certains écarts appartiennent au moteur**, pas au framework : l'ordre de tri des chaînes et
|
|
306
|
+
l'égalité sans casse suivent la collation de la base, la place des `NULL` dans un tri diffère, le
|
|
307
|
+
type `vector` n'existe qu'en PostgreSQL. Le SQL natif que tu écris reste propre à ton dialecte.
|
|
308
|
+
|
|
221
309
|
## 4. Éprouver une migration — sur une base d'ESSAI, jamais sur la tienne
|
|
222
310
|
|
|
223
311
|
Quand il faut **prouver** qu'une migration fait ce qu'elle annonce, la réponse n'est jamais de
|
|
@@ -320,9 +408,11 @@ Le `code` est stable — **lis-le, il désigne le geste**.
|
|
|
320
408
|
| `NF_MIGRATE_HASH_MISMATCH` | un fichier déjà appliqué a été modifié | RÉTABLIR le fichier (1er geste) ; `--update-hashes` seulement si la modification était sans effet |
|
|
321
409
|
| `NF_MIGRATE_OUT_OF_ORDER` | une migration en attente se range avant la dernière posée | renommer la nouvelle après la dernière appliquée |
|
|
322
410
|
| `NF_MIGRATE_MISSING_FILE` | une migration appliquée n'a plus de fichier | rétablir le fichier — il fait partie de l'historique |
|
|
323
|
-
| `NF_GENERATE_DATABASE_BEHIND` | rien à écrire, et pourtant la base ne porte pas le schéma
|
|
411
|
+
| `NF_GENERATE_DATABASE_BEHIND` | rien à écrire, RIEN n'attend, et pourtant la base ne porte pas le schéma | l'historique affirme une migration jamais exécutée : `orm:migrate:repair --forget <source>/<tag>` puis `orm:migrate` |
|
|
324
412
|
| `NF_MIGRATE_LOCK_TIMEOUT` | un autre travail de migration tient le verrou | ATTENDRE puis rejouer — ce n'est pas une panne, et le verbe est idempotent |
|
|
325
413
|
| `NF_MIGRATE_DESTRUCTIVE` | les migrations en attente SUPPRIMENT des données | lire le SQL (`--dry-run`), puis assumer avec `--allow-destructive` |
|
|
414
|
+
| `NF_GENERATE_NEEDS_ANSWER` | une colonne disparaît et une autre apparaît : renommage ou perte ? | renommage → `--rename table.ancienne=nouvelle` ; vraie suppression + ajout → deux générations |
|
|
415
|
+
| `NF_GENERATE_RENAME` | un `--rename` mal écrit, ou que le dernier instantané ne permet pas | corriger la déclaration — la table sous le nom de son entité ; rien n'a été écrit |
|
|
326
416
|
|
|
327
417
|
Les codes exhaustifs, avec un exemple de charge utile pour chacun :
|
|
328
418
|
[`references/verdicts.md`](references/verdicts.md).
|
|
@@ -113,26 +113,28 @@ n'a jamais les deux — c'est le discriminant à tester.
|
|
|
113
113
|
|
|
114
114
|
### Refus d'usage — la demande elle-même
|
|
115
115
|
|
|
116
|
-
| Code | Ce qui s'est passé
|
|
117
|
-
| -------------------------------- |
|
|
118
|
-
| `NF_MIGRATE_UNKNOWN_CONNECTOR` | aucun connecteur de ce nom
|
|
119
|
-
| `NF_MIGRATE_UNKNOWN_TAG` | `--up-to` désigne une migration inconnue
|
|
120
|
-
| `NF_MIGRATE_UNKNOWN_SOURCE` | `--source` n'est pas déclarée par cette application
|
|
121
|
-
| `NF_MIGRATE_URL_MISMATCH` | la variable de migration désigne une base d'un AUTRE dialecte
|
|
122
|
-
| `NF_MIGRATE_NOT_CONFIGURED` | connecteur SQL non déclaré dans la configuration
|
|
123
|
-
| `NF_MIGRATE_SECONDARY_CONNECTOR` | un connecteur secondaire porte le nom d'un dossier de dialecte (`sqlite`, `postgres`, `mysql`, `meta`)
|
|
124
|
-
| `NF_MIGRATE_NO_MIGRATIONS` | ce connecteur est porté par une base qui ne se migre pas ainsi
|
|
125
|
-
| `NF_MIGRATE_NOT_DEVELOPMENT` | geste réservé au développement, demandé ailleurs
|
|
126
|
-
| `NF_MIGRATE_DESTRUCTIVE` | des migrations en attente SUPPRIMENT des données
|
|
127
|
-
| `NF_MIGRATE_UNAVAILABLE` | la commande s'est arrêtée sans pouvoir nommer la cause
|
|
128
|
-
| `NF_MIGRATE_CONFIRM_REQUIRED` | `orm:reset` demandé hors terminal, ou en sortie machine
|
|
129
|
-
| `NF_GENERATE_NAME` | le nom de migration demandé n'est pas utilisable
|
|
130
|
-
| `NF_GENERATE_MISSING_ENTITY` | une entité est enregistrée sans fichier qui la fournisse
|
|
131
|
-
| `NF_GENERATE_UNREADABLE_ENTITY` | rien d'écrit, et un fichier d'entités ne s'importe pas : sa table n'est vue par personne
|
|
132
|
-
| `NF_GENERATE_FRAMEWORK_TABLE` | une entité de l'application usurpe une table du framework
|
|
133
|
-
| `NF_GENERATE_DESTRUCTIVE` | la migration ÉCRITE supprime des données
|
|
134
|
-
| `NF_GENERATE_DATABASE_BEHIND` | rien à écrire, et pourtant la base ne porte pas le schéma
|
|
135
|
-
| `NF_GENERATE_TOOL_MISSING` | l'outil de génération n'est pas installé
|
|
116
|
+
| Code | Ce qui s'est passé | Le geste |
|
|
117
|
+
| -------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `NF_MIGRATE_UNKNOWN_CONNECTOR` | aucun connecteur de ce nom | le message liste ceux que l'application déclare |
|
|
119
|
+
| `NF_MIGRATE_UNKNOWN_TAG` | `--up-to` désigne une migration inconnue | relire `sources[].pendingTags` |
|
|
120
|
+
| `NF_MIGRATE_UNKNOWN_SOURCE` | `--source` n'est pas déclarée par cette application | relire `sources[].name` |
|
|
121
|
+
| `NF_MIGRATE_URL_MISMATCH` | la variable de migration désigne une base d'un AUTRE dialecte | corriger la variable, ou choisir le bon connecteur |
|
|
122
|
+
| `NF_MIGRATE_NOT_CONFIGURED` | connecteur SQL non déclaré dans la configuration | le déclarer pour pouvoir le suivre |
|
|
123
|
+
| `NF_MIGRATE_SECONDARY_CONNECTOR` | un connecteur secondaire porte le nom d'un dossier de dialecte (`sqlite`, `postgres`, `mysql`, `meta`) | renommer le connecteur dans `connectors` — un secondaire range ses migrations sous `migrations/<connecteur>/` |
|
|
124
|
+
| `NF_MIGRATE_NO_MIGRATIONS` | ce connecteur est porté par une base qui ne se migre pas ainsi | rien à migrer ici — ce n'est pas une panne |
|
|
125
|
+
| `NF_MIGRATE_NOT_DEVELOPMENT` | geste réservé au développement, demandé ailleurs | passer par le travail de déploiement |
|
|
126
|
+
| `NF_MIGRATE_DESTRUCTIVE` | des migrations en attente SUPPRIMENT des données | relire le fichier produit, puis assumer explicitement |
|
|
127
|
+
| `NF_MIGRATE_UNAVAILABLE` | la commande s'est arrêtée sans pouvoir nommer la cause | constater l'état (`orm:migrate:status`) avant de reprendre |
|
|
128
|
+
| `NF_MIGRATE_CONFIRM_REQUIRED` | `orm:reset` demandé hors terminal, ou en sortie machine | relancer avec `--yes` si l'effacement est voulu |
|
|
129
|
+
| `NF_GENERATE_NAME` | le nom de migration demandé n'est pas utilisable | reprendre la suggestion que le message donne |
|
|
130
|
+
| `NF_GENERATE_MISSING_ENTITY` | une entité est enregistrée sans fichier qui la fournisse | `nodefony inspect entities --json` pour la situer |
|
|
131
|
+
| `NF_GENERATE_UNREADABLE_ENTITY` | rien d'écrit, et un fichier d'entités ne s'importe pas : sa table n'est vue par personne | corriger la cause nommée (souvent un paquet absent des dépendances), ou sortir le fichier de `nodefony/entity/` |
|
|
132
|
+
| `NF_GENERATE_FRAMEWORK_TABLE` | une entité de l'application usurpe une table du framework | la renommer, ou écrire une migration libre (`--custom`) |
|
|
133
|
+
| `NF_GENERATE_DESTRUCTIVE` | la migration ÉCRITE supprime des données | relire le fichier, puis annuler (`git checkout`) ou appliquer — la mise en service a sa propre garde |
|
|
134
|
+
| `NF_GENERATE_DATABASE_BEHIND` | rien à écrire, RIEN n'attend, et pourtant la base ne porte pas le schéma | `repair --forget <source>/<tag>` : l'historique affirme une migration jamais exécutée |
|
|
135
|
+
| `NF_GENERATE_TOOL_MISSING` | l'outil de génération n'est pas installé | l'installer en dépendance de développement |
|
|
136
|
+
| `NF_GENERATE_NEEDS_ANSWER` | une colonne disparaît et une autre apparaît — l'outil demande « renommage ? », sans terminal possible | renommage → `--rename table.ancienne=nouvelle` ; vraie suppression + ajout → deux générations |
|
|
137
|
+
| `NF_GENERATE_RENAME` | `--rename` mal écrit, ancien nom absent du dernier instantané, ou nouveau nom qu'aucune entité ne porte | corriger la déclaration (la table sous le nom de son entité) — rien n'a été écrit |
|
|
136
138
|
|
|
137
139
|
## Un contrat qui ne bougera pas
|
|
138
140
|
|