nestgen-cli 0.1.0 → 0.2.1

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/readme.md CHANGED
@@ -4,24 +4,68 @@
4
4
  [![CI](https://github.com/el-hack/nestgen-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/el-hack/nestgen-cli/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/npm/l/nestgen-cli)](LICENSE)
6
6
 
7
- NestGen CLI generates NestJS project scaffolding and TypeORM resources. The canonical package is [`nestgen-cli`](https://www.npmjs.com/package/nestgen-cli); the canonical repository is [`el-hack/nestgen-cli`](https://github.com/el-hack/nestgen-cli).
7
+ NestGen CLI generates NestJS project scaffolding and TypeORM or Prisma resources. The canonical package is [`nestgen-cli`](https://www.npmjs.com/package/nestgen-cli); the canonical repository is [`el-hack/nestgen-cli`](https://github.com/el-hack/nestgen-cli).
8
+
9
+ ## Published in 0.2.1 / Disponible dans 0.2.1
10
+
11
+ | Available now / Disponible maintenant | Evidence / Preuve |
12
+ | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | Nest project, module and TypeORM or Prisma resource generation | The commands are shipped by `nestgen-cli@0.2.1` and covered by the CLI contract tests. |
14
+ | Declarative resource relations, safe updates and migration plans | The generated manifest protects manual edits; migrations remain explicitly reviewed and applied by the developer. |
15
+ | Operational foundation and authorization metadata | Both are optional extension points; NestGen does not configure an identity provider, a global guard or an external monitoring service. |
16
+ | Store API example | The package ships the [version-pinned example](examples/store-api/README.md), which CI reconstructs from its resource definitions. |
17
+
18
+ ## Planned (not released) / Prévu (non publié)
19
+
20
+ The [roadmap](roadmap.md) contains topics under consideration after 0.2.1. They have no release date and are not part of the npm contract until they appear in a versioned guide and `CHANGELOG.md`. La roadmap recense des pistes après 0.2.1 ; elles n’ont ni date de sortie ni engagement de compatibilité avant leur publication dans un guide versionné et le changelog.
8
21
 
9
22
  ## Supported contract
10
23
 
11
- - Node.js `>=24.15.0 <27`, npm 11, pnpm or Yarn.
24
+ - Node.js `>=24.15.0 <27` (24, 25 and 26), npm 11, pnpm 10 or Yarn Berry 4. Windows is supported through WSL2 because project generation requires Bash.
12
25
  - `init` creates a NestJS project interactively with TypeORM or Prisma.
13
26
  - `module <name>` adds the advanced module layout for TypeORM or Prisma.
14
- - `resource <name>` currently generates a **TypeORM** REST CRUD: entity, DTOs, repository, controller, validation, pagination, `404` and unique-constraint `409`.
27
+ - `resource <name>` generates a TypeORM or Prisma REST CRUD: entity or model, DTOs, repository, controller, validation, pagination, `404` and unique-constraint `409`.
15
28
  - `doctor`, `--dry-run`, `--help`, `--version`, `--no-interactive` and `--quiet` are scriptable CLI features.
29
+ - Existing Nest projects are supported when `nest-cli.json` declares a custom `sourceRoot`. In a workspace with several applications, pass `--application <name>` to target one application explicitly.
30
+
31
+ The repository CI executes generator contracts on the declared Node lines and on Linux and macOS. Windows users are supported through WSL2, whose Linux environment is covered by the Ubuntu runner. On Ubuntu/Node 24.15 it additionally validates Prisma, a TypeORM HTTP/PostgreSQL integration, generated Docker configurations, package-manager lockfile creation and locked reinstallation for npm, pnpm and Yarn, and the npm tarball. It does not publish releases or deploy applications. See [COMPATIBILITY.md](COMPATIBILITY.md) for the exact coverage and exclusions.
32
+
33
+ ## Releases
34
+
35
+ Create releases from an annotated `vX.Y.Z` tag that points to the commit containing the same version in `package.json` and `package-lock.json`, plus a matching `CHANGELOG.md` section. The tag triggers the release workflow, which builds the package, verifies the tag/commit/version/archive SHA-512 relationship, publishes with npm Trusted Publishing (GitHub OIDC, no npm token in the repository), checks the npm `latest` dist-tag and archive integrity, then installs and runs the published binary in a clean directory.
36
+
37
+ Before the first release, configure `el-hack/nestgen-cli` as a Trusted Publisher in npm for the `Release` workflow. If publication fails before npm accepts the version, repair the release commit and replace the unpublished tag. If npm has accepted the version but a later registry check fails, do not republish that version: investigate the immutable tarball, correct the issue in a new SemVer version, then publish a new tag. The workflow creates the GitHub release only after the isolated install succeeds.
38
+
39
+ ## Outputs by ORM
40
+
41
+ | Command | ORM | Persistence output |
42
+ | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
43
+ | `resource` (simple or advanced) | TypeORM | Entity and repository using TypeORM; `resource.json` records `orm: "typeorm"`. No Prisma file or import. |
44
+ | `resource` | Prisma | Prisma model, Nest module, DTOs, repository and REST controller; `resource.json` records `orm: "prisma"`. No TypeORM file or import. |
45
+ | `module` | TypeORM | TypeORM entity and repository, registered with `TypeOrmModule.forFeature`. No Prisma runtime or schema change. |
46
+ | `module` | Prisma | Prisma repository, model added to `prisma/schema.prisma`, shared Prisma runtime if absent. No TypeORM file or import. |
16
47
 
17
- The repository CI validates linting, formatting, generator contracts, a Prisma integration, a TypeORM HTTP/PostgreSQL integration, generated Docker configurations, and the npm tarball. It does not publish releases or deploy applications.
48
+ For Prisma, run `npx prisma generate` and apply the schema with `npx prisma db push` or an explicit migration after generating a resource. Selecting an ORM does not convert an existing resource or remove files produced by older generator versions.
49
+
50
+ ## Public demo / Démonstration publique
51
+
52
+ Install the announced release and verify the exact binary before generating anything. Installez la version annoncée et vérifiez le binaire exact avant toute génération.
53
+
54
+ ```bash
55
+ npm install --global nestgen-cli@0.2.1
56
+ nestgen --version # 0.2.1
57
+ ```
58
+
59
+ Then follow the [Store API example](examples/store-api/README.md): it generates customers, products, orders and order items; starts PostgreSQL; creates an explicit migration; and runs generated tests. The versioned [guide](docs/versions/0.2.1.md) documents the commands and constraints used by the demo. Ensuite, suivez l’exemple Store API : il couvre la génération, PostgreSQL, une migration explicite, les tests générés et la documentation de la version.
60
+
61
+ The CI verifies the public commands against the announced package version, reconstructs the example and installs the npm tarball in a clean consumer. It validates reproducibility of these flows, not a production certification / pas une certification de production.
18
62
 
19
63
  ## Quickstart — TypeORM resource
20
64
 
21
- The following flow is the supported end-to-end TypeORM path. It uses Docker for PostgreSQL and creates an explicit migration.
65
+ The following flow is the supported end-to-end TypeORM path. Prerequisites: Node.js `>=24.15.0 <27`, npm 11 and Docker with Compose. It uses Docker for PostgreSQL and creates an explicit migration.
22
66
 
23
67
  ```bash
24
- npm install --global nestgen-cli
68
+ npm install --global nestgen-cli@0.2.1
25
69
  nestgen --version
26
70
  nestgen init
27
71
  ```
@@ -55,39 +99,187 @@ curl --request POST http://localhost:3000/catalog/products \
55
99
  --data '{"sku":"sku-001","price":19.9,"published":true}'
56
100
 
57
101
  curl 'http://localhost:3000/catalog/products?page=1&limit=20'
102
+
103
+ # Swagger UI, when selected during init
104
+ open http://localhost:3000/api
105
+
106
+ # Generated unit and database-backed REST tests
107
+ npm test
108
+ docker compose -f test/compose.e2e.yaml up -d --wait
109
+ npm run test:e2e -- product.e2e-spec.ts
110
+ docker compose -f test/compose.e2e.yaml down -v
111
+
112
+ # Stop the development database when finished
113
+ docker compose down -v
58
114
  ```
59
115
 
60
- A duplicate `sku` returns HTTP `409`; a malformed `price` returns HTTP `400`; an unknown identifier returns HTTP `404`. Run the generated project tests with `npm test` and stop the local database with `docker compose down`.
116
+ A duplicate `sku` returns HTTP `409`; a malformed `price` returns HTTP `400`; an unknown identifier returns HTTP `404`. The REST test database runs separately on `127.0.0.1:5433`, is reset during the test suite and is removed by the cleanup command. On Windows, open `http://localhost:3000/api` in a browser instead of using `open`.
61
117
 
62
118
  ### English quickstart
63
119
 
64
120
  Install `nestgen-cli`, run `nestgen init`, choose **npm**, **typeorm** and Docker, then run the same commands above. `resource product --fields sku:string!,price:number,published:boolean` creates the TypeORM CRUD. Start PostgreSQL with `docker compose up -d postgres`, generate and run the migration through `typeorm-ts-node-commonjs`, start NestJS, then use the two `curl` commands to verify create and list operations.
65
121
 
122
+ ## Maintained Store API example
123
+
124
+ The published package includes a version-pinned [Store API example](examples/store-api/README.md) with customers, products, orders and order items. Its resource definitions are rebuilt by the CLI in CI, including relation constraints and a migration plan, so the guide stays aligned with the distributed generator. Use it when you need a complete multi-resource starting point rather than the single-product quickstart.
125
+
66
126
  ## Commands
67
127
 
68
128
  ```text
69
129
  nestgen init
70
- nestgen module <name> [--orm typeorm|prisma] [--dry-run]
71
- nestgen resource <name> --fields name:type[,name:type] [--route route] [--table table] [--profile simple|advanced]
130
+ nestgen module <name> [--orm typeorm|prisma] [--application name] [--dry-run]
131
+ nestgen resource <name> --fields name:type[,name:type] [--route route] [--table table] [--profile simple|advanced] [--application name]
72
132
  nestgen config init [--orm typeorm|prisma] [--profile simple|advanced] [--package-manager npm|pnpm|yarn]
73
133
  nestgen config show
74
134
  nestgen doctor
75
135
  ```
76
136
 
77
- Fields accepted by `resource` are `string`, `number`, `boolean`, `date` and `uuid`. Add `?` for a nullable field and `!` for a unique field:
137
+ Pour la CI, `init` accepte toutes les réponses interactives sous forme d’options :
138
+
139
+ ```bash
140
+ nestgen init store-api --no-interactive --project-path ./generated --package-manager npm --orm typeorm --docker --swagger --git --modules user,product
141
+ ```
142
+
143
+ Utilisez `--no-docker`, `--no-swagger`, `--no-operations`, `--no-git` ou `--modules ''` pour les désactiver. En mode non interactif, une option manquante est signalée avant toute écriture ou installation.
144
+
145
+ ### Socle d’exploitation optionnel
146
+
147
+ Ajoutez `--operations` à `init` pour générer un socle local d’exploitation, sans dépendance à un service tiers. Il expose `GET /health/live` pour la disponibilité du processus et `GET /health/ready` pour la disponibilité de PostgreSQL ; le second renvoie `503` avec l’état de la dépendance lorsque la base est indisponible. Le projet reçoit aussi un middleware `x-request-id`, un logger JSON qui masque les clés sensibles (`password`, `secret`, `token`, `authorization`, `cookie`, `apiKey`) et `enableShutdownHooks()` pour fermer proprement TypeORM ou Prisma sur `SIGTERM` et `SIGINT`. Le contrat et ses limites sont documentés dans `src/operations/README.md` du projet généré.
148
+
149
+ ### Points d’extension d’autorisation
150
+
151
+ Chaque contrôleur de ressource porte désormais `@ResourceAction('create' | 'list' | 'read' | 'update' | 'delete')`, défini dans `src/app/<ressource>/authorization/resource-policy.ts`. Cette métadonnée est destinée à un guard d’application existant via `Reflector`; NestGen ne configure ni fournisseur d’identité, ni stratégie de connexion, ni guard global.
152
+
153
+ Pour une règle de propriété, déclarez explicitement le propriétaire (`ownerId:uuid`) puis faites charger la ressource par votre guard avant les actions `read`, `update` et `delete`. Le guard compare l’identité déjà établie par votre application avec `resource.ownerId` et retourne `false` lorsqu’elles diffèrent : Nest renvoie alors `403`, y compris pour les accès inter-utilisateurs. Les actions et le nom de ressource restent disponibles dans `ResourcePolicyMetadata`, ce qui permet de centraliser une politique pour plusieurs ressources tout en conservant les conventions Nest standard.
154
+
155
+ Fields accepted by `resource` are `string`, `number`, `integer`, `decimal(precision;scale)`, `enum(VALUE|VALUE)`, `boolean`, `date` and `uuid`. Add `?` for a nullable field and `!` for a unique field. A decimal uses a semicolon between precision and scale so a field list can still be separated by commas. Decimals are exposed as JSON strings to preserve their database precision; enums use uppercase values separated by `|`.
156
+
157
+ `integer` maps to PostgreSQL `integer` / Prisma `Int` and is validated with `@IsInt()`. `decimal(precision;scale)` maps to PostgreSQL `numeric(precision, scale)` / Prisma `Decimal @db.Decimal(precision, scale)` and is validated as a decimal string. `enum(...)` maps to a PostgreSQL enum / a generated Prisma enum and is validated against its declared values.
158
+
159
+ ## Contraintes et index métier
160
+
161
+ Ajoutez des contraintes après le type entre accolades, séparées par `;` : `length` pour une chaîne, `min` et `max` pour un nombre ou un entier, `default` pour une valeur par défaut compatible, et `index` pour un index simple. Les index composites sont déclarés avec `--indexes`, chaque colonne étant séparée par `+`.
162
+
163
+ ```bash
164
+ nestgen resource product \
165
+ --fields sku:string{length=64;index}!,title:string{length=120},quantity:integer{min=0;max=100;default=0},status:enum(DRAFT|ACTIVE){default=DRAFT} \
166
+ --indexes sku+status
167
+ ```
168
+
169
+ NestGen refuse les combinaisons incompatibles, les bornes inversées et les index qui ciblent un champ absent. Les contraintes sont reflétées dans les DTOs, OpenAPI lorsque Swagger est installé, et les schémas TypeORM ou Prisma. Les index reçoivent un nom déterministe fondé sur la table et leurs colonnes, y compris lorsque PostgreSQL impose une limite de longueur.
170
+
171
+ ## Définition de ressource dans un fichier
172
+
173
+ `nestgen resource --file product.resource.json` lit un JSON versionné. La version actuelle est `1`. Les options de ligne de commande (`<name>`, `--fields`, `--route`, `--table`, `--orm`, `--profile`, `--indexes`) remplacent la valeur du fichier lorsqu’elles sont présentes. Ajoutez `uniqueIndexes` au fichier pour les contraintes d’unicité composites, par exemple `"uniqueIndexes": ["userId+roleId"]`.
174
+
175
+ ```json
176
+ {
177
+ "version": 1,
178
+ "name": "product",
179
+ "route": "catalog/products",
180
+ "table": "catalog_products",
181
+ "orm": "prisma",
182
+ "profile": "advanced",
183
+ "fields": ["sku:string!", "status:enum(DRAFT|ACTIVE)"],
184
+ "indexes": ["sku+status"],
185
+ "relations": [{ "type": "belongsTo", "target": "category", "onDelete": "RESTRICT" }]
186
+ }
187
+ ```
188
+
189
+ Le fichier doit être situé dans le projet courant. Les diagnostics indiquent le fichier et le champ ou l’index concerné, et `--dry-run` produit le même plan que la définition équivalente en flags.
190
+
191
+ ### Filtres, recherche et tri contrôlés
192
+
193
+ Ajoutez `list` à la définition pour autoriser explicitement les filtres et tris exposés par l’endpoint de liste. Les champs ou opérateurs absents de cette liste sont refusés avec `400`. Les paramètres de filtre sont convertis selon le type déclaré (`number`, `integer`, `boolean` et `date`) et les requêtes ORM restent paramétrées.
194
+
195
+ ```json
196
+ {
197
+ "version": 1,
198
+ "name": "product",
199
+ "fields": ["sku:string!", "price:number", "published:boolean"],
200
+ "list": {
201
+ "filters": {
202
+ "sku": ["eq", "contains"],
203
+ "price": ["gte", "lt"],
204
+ "published": ["eq"]
205
+ },
206
+ "search": ["sku"],
207
+ "sort": ["sku", "price"]
208
+ }
209
+ }
210
+ ```
211
+
212
+ Les opérateurs autorisés dépendent du type : `eq` et `neq` pour tous les champs, `contains` pour les chaînes, et `gt`, `gte`, `lt`, `lte` pour les nombres, entiers, décimaux et dates. Une requête telle que `GET /products?skuContains=pro&priceGte=10&sort=price:desc` combine les filtres, applique un ordre déterministe (avec `id` comme brise-égalité) et respecte `page` et `limit`. `q` recherche sur les champs déclarés dans `search`.
213
+
214
+ Ajoutez `"cursor": true` dans `list` pour inclure `nextCursor` dans les réponses. Reprenez la liste avec `?after=<nextCursor>` : le curseur opaque est validé et suit l’ordre stable `id:asc`, après application des mêmes filtres et de la même recherche. Un tri métier ne produit donc pas de curseur et ne peut pas être combiné avec `after`; ce choix évite les doublons ou omissions lors de la progression. Les changements concurrents peuvent toujours modifier les données restantes entre deux requêtes, comme avec toute pagination sans snapshot transactionnel.
215
+
216
+ ## Relations entre ressources
217
+
218
+ Une relation est déclarée dans le fichier de définition de la ressource enfant. La ressource cible doit déjà avoir été générée avec le même ORM. `belongsTo` crée la clé étrangère, un index et la propriété inverse sur la cible pour former une relation un-à-plusieurs cohérente.
219
+
220
+ ```json
221
+ {
222
+ "version": 1,
223
+ "name": "order",
224
+ "fields": ["reference:string!"],
225
+ "relations": [
226
+ {
227
+ "type": "belongsTo",
228
+ "target": "customer",
229
+ "field": "customer",
230
+ "inverse": "orders",
231
+ "nullable": false,
232
+ "onDelete": "RESTRICT"
233
+ }
234
+ ]
235
+ }
236
+ ```
237
+
238
+ `field` et `inverse` sont optionnels : NestGen utilise le nom de la ressource cible et un pluriel du nom de la ressource enfant. `nullable` vaut `false` par défaut et `onDelete` vaut `RESTRICT`; les suppressions liées ne déclenchent donc aucune cascade implicite. `SET NULL` est accepté seulement avec `nullable: true`.
239
+
240
+ `manyToMany` crée une table de liaison avec ses deux clés étrangères et une contrainte d’unicité sur la paire. La ressource qui déclare la relation en est propriétaire et reçoit les routes `POST /<ressource>/:id/<relation>/:targetId` et `DELETE /<ressource>/:id/<relation>/:targetId` pour associer et dissocier sans supprimer les deux entités.
241
+
242
+ ```json
243
+ {
244
+ "version": 1,
245
+ "name": "user",
246
+ "fields": ["email:string!"],
247
+ "relations": [{ "type": "manyToMany", "target": "role", "field": "roles", "inverse": "users" }]
248
+ }
249
+ ```
250
+
251
+ Lorsqu’une association porte ses propres données métier, générez-la comme ressource explicite avec deux relations `belongsTo`, puis protégez le couple de clés avec `uniqueIndexes`. Par exemple, une ressource `membership` peut définir `userId`, `roleId` et `grantedAt`, avec `"uniqueIndexes": ["userId+roleId"]`. Cette forme permet de versionner et valider les attributs de l’association, ce que la table de liaison implicite ne fait pas.
252
+
253
+ On creation, non-nullable fields are required. On PATCH, omitted fields are preserved;
254
+ `null` clears only nullable fields and is rejected for other fields. Values such as
255
+ `false`, `0` and an empty string are preserved when valid for the field type.
78
256
 
79
257
  ```bash
80
258
  nestgen resource invoice \
81
- --fields number:string!,amount:number,paid:boolean,dueAt:date? \
259
+ --fields number:string!,lineCount:integer,amount:decimal(12;2),status:enum(DRAFT|ISSUED),paid:boolean,dueAt:date? \
82
260
  --route billing/invoices \
83
261
  --table billing_invoices
84
262
  ```
85
263
 
86
264
  Use `nestgen --help` for the complete accepted option set. Do not rely on undocumented options such as `--crud` or `--path`.
87
265
 
266
+ `--dry-run` emits a versioned JSON plan for `module` and `resource`. Each entry identifies the creation or replacement, and includes the exact unified diff that generation would apply. Conflicts are reported in `conflicts`; no file, dependency or installation is changed.
267
+
268
+ Use `--json` in automation to receive one versioned result on stdout. Failures produce a versioned JSON error on stderr with a stable `USAGE`, `PROJECT_INVALID`, `CONFLICT` or `INTERNAL` code; `--json` also enables non-interactive, quiet and no-color behavior.
269
+
270
+ `nestgen doctor` is read-only. It reports version support, generator availability, Nest dependencies, ORM coherence, NestGen configuration, lockfile consistency and Nest integration. Every diagnostic has an identifier, severity, cause and concrete corrective action; use `nestgen doctor --json` for the same contract in automation.
271
+
272
+ ## Generation metadata
273
+
274
+ Every successful `module` or `resource` generation updates `.nestgen/generation-manifest.json` in the same atomic transaction as the generated files. The versioned manifest records the generator version, a safe structural definition and SHA-256 fingerprints for each generated file. Paths are always project-relative; field default values are deliberately excluded so the manifest can be committed without copying secrets. Later tooling can compare these fingerprints to detect manual edits before proposing an update. An unknown manifest version stops generation before any write.
275
+
276
+ Use `resource <name> --update` to regenerate a resource after changing its fields, route, table or definition file. NestGen previews the same transaction with `--dry-run`; a generated file edited since its recorded generation is reported as a conflict and blocks all writes. Files not tracked by the resource manifest are left untouched, and the manifest is refreshed only after the complete update commits successfully.
277
+
278
+ Add `--migration-name <name>` to an update to prepare the matching migration command and schema-risk review. TypeORM uses `typeorm-ts-node-commonjs migration:generate`; Prisma uses `prisma migrate dev --create-only`. The CLI never runs this command or applies a migration: review the reported column removals, type changes, mandatory fields, unique constraints and relation removals, then run the printed command explicitly in the generated project.
279
+
88
280
  ## Project configuration and profiles
89
281
 
90
- `nestgen config init` writes a versioned `nestgen.config.json` in the current project. Its ORM, architecture profile and package-manager defaults apply to subsequent resource generation; explicit resource flags take precedence.
282
+ `nestgen config init` writes a versioned `nestgen.config.json` in the current project. For `resource`, the resolution order is flags, then the resource definition file, then configuration, then defaults. For `module`, `--orm` overrides configuration, then the default. `profile` is consumed by `resource`; `packageManager` is consumed by `init` and recorded for tooling, but neither `resource` nor `module` installs packages, so it has no runtime effect there. The generator resolves the effective source root from `nest-cli.json`; use `--application <name>` when a Nest workspace contains more than one application.
91
283
 
92
284
  ```bash
93
285
  nestgen config init --orm typeorm --profile advanced --package-manager npm
@@ -95,7 +287,34 @@ nestgen config show
95
287
  nestgen resource order --fields reference:string!,total:number
96
288
  ```
97
289
 
98
- The `simple` profile generates a direct CRUD. The `advanced` profile adds an explicit repository port and Nest injection token between the application service and TypeORM adapter.
290
+ The `simple` profile generates a direct CRUD. The `advanced` profile adds application contracts, a repository port and a framework-independent application service between HTTP and the TypeORM adapter.
291
+
292
+ ## OpenAPI when Swagger is enabled
293
+
294
+ If the project contains `@nestjs/swagger` (selected during `nestgen init`), generated resources enrich the OpenAPI document with DTO property schemas, examples, required and nullable fields, UUID/date formats, endpoint summaries, pagination parameters, and documented `400`, `404`, `409` and success responses. Projects without Swagger keep the same generated REST code and do not receive Swagger imports.
295
+
296
+ ## Tests generated with a resource
297
+
298
+ Each generated resource includes a Jest unit test next to its implementation. In a standard project created by Nest, run the complete suite with `npm test`, or one resource with:
299
+
300
+ ```bash
301
+ npm test -- product.repository.spec.ts
302
+ npm test -- order.service.spec.ts
303
+ ```
304
+
305
+ The simple profile test exercises persistence success, a missing record and a unique-constraint conflict. The advanced profile test exercises the application service output and the HTTP translation of application errors to `404` and `409`. The tests use in-memory doubles; each resource also has a generated REST test backed by PostgreSQL.
306
+
307
+ ## Generated REST tests on an isolated database
308
+
309
+ The first generated resource adds `test/.env.e2e` and `test/compose.e2e.yaml`; every resource adds `test/<resource>.e2e-spec.ts`. The test assigns `DATABASE_NAME` from `DATABASE_TEST_NAME`, resets the schema before every scenario, and drops it when the suite ends. It therefore never targets the development or production database.
310
+
311
+ ```bash
312
+ docker compose -f test/compose.e2e.yaml up -d --wait
313
+ npm run test:e2e -- product.e2e-spec.ts
314
+ docker compose -f test/compose.e2e.yaml down -v
315
+ ```
316
+
317
+ The generated suite covers create, read, partial update, pagination and delete, plus invalid input, malformed UUIDs, missing resources, and duplicate values when the resource declares a unique field with `!`.
99
318
 
100
319
  ## Docker generated by `init`
101
320
 
@@ -117,11 +336,13 @@ docker run --rm --env-file .env --publish 3000:3000 store-api:local
117
336
  ```bash
118
337
  npm ci
119
338
  npm run check
339
+ npm run landing:check
120
340
  npm run format:check
121
341
  npm test
122
342
  npm run test:docker
123
343
  npm run test:prisma
124
344
  npm run test:typeorm
345
+ npm run test:example
125
346
  npm run test:package
126
347
  ```
127
348