@flusys/nestjs-core 4.1.1 → 5.0.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 +109 -580
- package/cjs/config/env-config.service.js +11 -8
- package/cjs/docs/docs.config.js +20 -0
- package/cjs/index.js +0 -1
- package/config/env-config.service.d.ts +2 -1
- package/docs/docs.config.d.ts +1 -0
- package/fesm/config/env-config.service.js +11 -8
- package/fesm/docs/docs.config.js +20 -0
- package/fesm/index.js +0 -2
- package/index.d.ts +0 -1
- package/interfaces/base-entity.interface.d.ts +0 -3
- package/package.json +1 -1
- package/cjs/seeders/base-seeder.js +0 -76
- package/cjs/seeders/cli.js +0 -291
- package/cjs/seeders/data-generator.js +0 -226
- package/cjs/seeders/entity-reader.js +0 -129
- package/cjs/seeders/field-patterns.js +0 -182
- package/cjs/seeders/index.js +0 -85
- package/cjs/seeders/seed-config.js +0 -62
- package/cjs/seeders/seed-runner.js +0 -281
- package/fesm/seeders/base-seeder.js +0 -66
- package/fesm/seeders/cli.js +0 -249
- package/fesm/seeders/data-generator.js +0 -216
- package/fesm/seeders/entity-reader.js +0 -119
- package/fesm/seeders/field-patterns.js +0 -143
- package/fesm/seeders/index.js +0 -7
- package/fesm/seeders/seed-config.js +0 -35
- package/fesm/seeders/seed-runner.js +0 -263
- package/seeders/base-seeder.d.ts +0 -14
- package/seeders/cli.d.ts +0 -3
- package/seeders/data-generator.d.ts +0 -15
- package/seeders/entity-reader.d.ts +0 -44
- package/seeders/field-patterns.d.ts +0 -12
- package/seeders/index.d.ts +0 -7
- package/seeders/seed-config.d.ts +0 -12
- package/seeders/seed-runner.d.ts +0 -48
package/README.md
CHANGED
|
@@ -1,92 +1,9 @@
|
|
|
1
1
|
# @flusys/nestjs-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Foundation infrastructure for NestJS applications — environment config, TypeORM migrations, and Swagger setup.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@flusys/nestjs-core)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://nestjs.com/)
|
|
8
|
-
[](https://www.typescriptlang.org/)
|
|
9
|
-
[](https://nodejs.org/)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Table of Contents
|
|
14
|
-
|
|
15
|
-
- [Overview](#overview)
|
|
16
|
-
- [Features](#features)
|
|
17
|
-
- [Architecture](#architecture)
|
|
18
|
-
- [Compatibility](#compatibility)
|
|
19
|
-
- [Installation](#installation)
|
|
20
|
-
- [Environment Setup](#environment-setup)
|
|
21
|
-
- [Quick Start](#quick-start)
|
|
22
|
-
- [EnvConfigService](#envconfigservice)
|
|
23
|
-
- [Migration CLI](#migration-cli)
|
|
24
|
-
- [Migration Config File](#migration-config-file)
|
|
25
|
-
- [CLI Commands](#cli-commands)
|
|
26
|
-
- [Programmatic API](#programmatic-api)
|
|
27
|
-
- [Seed System](#seed-system)
|
|
28
|
-
- [BaseSeeder](#baseseeder)
|
|
29
|
-
- [SeedRunner](#seedrunner)
|
|
30
|
-
- [DataGenerator](#datagenerator)
|
|
31
|
-
- [Seed CLI](#seed-cli)
|
|
32
|
-
- [Swagger Documentation](#swagger-documentation)
|
|
33
|
-
- [setupSwaggerDocs](#setupswaggerdocs)
|
|
34
|
-
- [setupModuleSwaggerDocs](#setupmoduleswaggerdocs)
|
|
35
|
-
- [Database Utilities](#database-utilities)
|
|
36
|
-
- [Core Interfaces](#core-interfaces)
|
|
37
|
-
- [Injection Tokens & Constants](#injection-tokens--constants)
|
|
38
|
-
- [Multi-Tenant Support](#multi-tenant-support)
|
|
39
|
-
- [Troubleshooting](#troubleshooting)
|
|
40
|
-
- [License](#license)
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Overview
|
|
45
|
-
|
|
46
|
-
`@flusys/nestjs-core` is the lowest-level dependency in the FLUSYS NestJS monorepo. Every other package depends on it.
|
|
47
|
-
|
|
48
|
-
**Key design decision:** This package is **pure TypeScript with zero NestJS runtime dependencies** (except the isolated `docs/` module). The migration and seed CLIs run as standalone Node.js processes — no NestJS app bootstrap required. This makes it usable in CI pipelines, build scripts, and non-NestJS tools.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Features
|
|
53
|
-
|
|
54
|
-
- **Type-safe environment config** — Strongly typed `process.env` access with restricted key protection and validation
|
|
55
|
-
- **Migration CLI** — Full CLI and programmatic API for TypeORM migrations, including multi-tenant (run-for-all-tenants)
|
|
56
|
-
- **Data seeder** — Metadata-driven test data generation with Faker.js, topological sort for dependency resolution, and custom seeder support
|
|
57
|
-
- **Swagger setup** — Modular API documentation with advanced filtering by tags, schemas, parameters, and examples
|
|
58
|
-
- **DataSource utilities** — TypeORM DataSource configuration builders for single and multi-tenant setups
|
|
59
|
-
- **Core interfaces** — Contract definitions (entities, config, database, migrations) used by all feature modules
|
|
60
|
-
- **SnakeNamingStrategy** — All columns use `snake_case` by default via `typeorm-naming-strategies`
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Architecture
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
@flusys/nestjs-core ← THIS PACKAGE (pure TypeScript)
|
|
68
|
-
↓
|
|
69
|
-
@flusys/nestjs-shared ← NestJS shared infrastructure
|
|
70
|
-
↓
|
|
71
|
-
auth | iam | storage | email | form-builder | event-manager | notification | localization
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
`nestjs-core` is the only FLUSYS package with no upstream FLUSYS dependencies. All other packages depend on it.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Compatibility
|
|
79
|
-
|
|
80
|
-
| Package | Version |
|
|
81
|
-
|---------|---------|
|
|
82
|
-
| `typeorm` | `^0.3.0` |
|
|
83
|
-
| `typeorm-naming-strategies` | `^4.1.0` |
|
|
84
|
-
| `@faker-js/faker` | `^8.0.0` |
|
|
85
|
-
| `dotenv` | `^16.0.0` |
|
|
86
|
-
| `@nestjs/common` | `^11.0.0` *(docs/ only)* |
|
|
87
|
-
| `@nestjs/swagger` | `^8.0.0` *(docs/ only)* |
|
|
88
|
-
| Node.js | `>= 18.x` |
|
|
89
|
-
| TypeScript | `>= 5.0` |
|
|
90
7
|
|
|
91
8
|
---
|
|
92
9
|
|
|
@@ -94,549 +11,161 @@ auth | iam | storage | email | form-builder | event-manager | notification | loc
|
|
|
94
11
|
|
|
95
12
|
```bash
|
|
96
13
|
npm install @flusys/nestjs-core
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
# Peer dependencies
|
|
101
|
-
npm install typeorm typeorm-naming-strategies @faker-js/faker dotenv
|
|
102
|
-
|
|
103
|
-
# For migration and seed CLIs
|
|
14
|
+
npm install typeorm typeorm-naming-strategies dotenv
|
|
104
15
|
npm install -D ts-node tsconfig-paths
|
|
105
|
-
|
|
106
|
-
# For Swagger (docs/ module only)
|
|
107
|
-
npm install @nestjs/common @nestjs/swagger
|
|
108
16
|
```
|
|
109
17
|
|
|
110
18
|
---
|
|
111
19
|
|
|
112
|
-
## Environment
|
|
113
|
-
|
|
114
|
-
Create a `.env` file in your project root:
|
|
115
|
-
|
|
116
|
-
```env
|
|
117
|
-
PORT=2002
|
|
118
|
-
MODE=dev
|
|
119
|
-
FRONTEND_URL=http://localhost:2001
|
|
120
|
-
ALLOW_ORIGINS=http://localhost:2001,http://localhost:3000
|
|
121
|
-
|
|
122
|
-
# Database
|
|
123
|
-
DB_HOST=localhost
|
|
124
|
-
DB_PORT=5432
|
|
125
|
-
DB_USER=postgres
|
|
126
|
-
DB_PASSWORD=password
|
|
127
|
-
DB_NAME=myapp
|
|
128
|
-
|
|
129
|
-
# JWT
|
|
130
|
-
JWT_SECRET=your-jwt-secret-min-32-chars
|
|
131
|
-
JWT_EXPIRATION=15m
|
|
132
|
-
REFRESH_TOKEN_SECRET=your-refresh-secret
|
|
133
|
-
REFRESH_TOKEN_EXPIRATION=7d
|
|
134
|
-
|
|
135
|
-
# Cache
|
|
136
|
-
REDIS_URL=redis://localhost:6379
|
|
137
|
-
|
|
138
|
-
# Email
|
|
139
|
-
MAIL_FROM=noreply@example.com
|
|
140
|
-
MAIL_APP_PASSWORD=app-password
|
|
141
|
-
|
|
142
|
-
# Multi-tenant (optional)
|
|
143
|
-
TENANT_ID=
|
|
144
|
-
USE_TENANT_MODE=false
|
|
145
|
-
|
|
146
|
-
# Logging
|
|
147
|
-
LOG_DIR=logs
|
|
148
|
-
LOG_LEVEL=debug
|
|
149
|
-
LOG_MAX_SIZE=20m
|
|
150
|
-
LOG_MAX_FILES=14d
|
|
151
|
-
DISABLE_HTTP_LOGGING=false
|
|
152
|
-
```
|
|
20
|
+
## 1. Environment Config
|
|
153
21
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
## Quick Start
|
|
157
|
-
|
|
158
|
-
### Environment Config
|
|
22
|
+
Access typed environment variables via the `envConfig` singleton — no class instantiation needed.
|
|
159
23
|
|
|
160
24
|
```typescript
|
|
161
25
|
import { envConfig } from '@flusys/nestjs-core';
|
|
162
26
|
|
|
163
|
-
const port
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
const mail = envConfig.getMailConfig(); // { MAIL_FROM, MAIL_APP_PASSWORD }
|
|
170
|
-
const logConfig = envConfig.getLogConfig(); // { dir, level, maxSize, maxFiles, disableHttpLogging }
|
|
171
|
-
const tenantId = envConfig.getTenantId(); // string | null
|
|
172
|
-
const multiTenant = envConfig.useTenantMode(); // boolean
|
|
173
|
-
|
|
174
|
-
// Custom variable (throws if missing when throwOnMissing: true)
|
|
175
|
-
const myVar = envConfig.tryGetValue('MY_CUSTOM_VAR', true);
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Add Migration Scripts to package.json
|
|
179
|
-
|
|
180
|
-
```json
|
|
181
|
-
{
|
|
182
|
-
"scripts": {
|
|
183
|
-
"migration:generate": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli generate",
|
|
184
|
-
"migration:run": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli run",
|
|
185
|
-
"migration:revert": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli revert",
|
|
186
|
-
"migration:status": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli status",
|
|
187
|
-
"migration:run:all": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli run:all",
|
|
188
|
-
"seed:run": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli run",
|
|
189
|
-
"seed:clear": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli clear",
|
|
190
|
-
"seed:status": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli status"
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Setup Swagger
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
import { NestFactory } from '@nestjs/core';
|
|
199
|
-
import { setupSwaggerDocs } from '@flusys/nestjs-core/docs';
|
|
200
|
-
|
|
201
|
-
async function bootstrap() {
|
|
202
|
-
const app = await NestFactory.create(AppModule);
|
|
203
|
-
setupSwaggerDocs(app, { title: 'My API', version: '1.0' });
|
|
204
|
-
await app.listen(3000);
|
|
205
|
-
}
|
|
27
|
+
const port = envConfig.getPort(); // number
|
|
28
|
+
const db = envConfig.getTypeOrmConfig(); // { host, port, username, password, database }
|
|
29
|
+
const jwt = envConfig.getJwtConfig(); // { secret, expiration, refreshSecret, ... }
|
|
30
|
+
const origins = envConfig.getOrigins(); // string[]
|
|
31
|
+
const isProd = envConfig.isProduction(); // boolean
|
|
32
|
+
public tryGetValue(key: string, throwOnMissing = false): string // get env value
|
|
206
33
|
```
|
|
207
34
|
|
|
208
35
|
---
|
|
209
36
|
|
|
210
|
-
##
|
|
211
|
-
|
|
212
|
-
A singleton pre-instantiated as `envConfig`. Loads `.env` on import via `dotenv`.
|
|
213
|
-
|
|
214
|
-
### Restricted Keys
|
|
37
|
+
## 2. Migrations
|
|
215
38
|
|
|
216
|
-
|
|
39
|
+
### Create `src/persistence/migration.config.ts`
|
|
217
40
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|--------|---------|-------------|
|
|
224
|
-
| `tryGetValue(key, throwOnMissing?)` | `string` | Get any non-restricted env var |
|
|
225
|
-
| `getNumber(key, throwOnMissing?)` | `number` | Get env var as number |
|
|
226
|
-
| `getBoolean(key, throwOnMissing?)` | `boolean` | Get env var as boolean |
|
|
227
|
-
| `getPort()` | `number` | `PORT` (default: 3000) |
|
|
228
|
-
| `isProduction()` | `boolean` | `MODE !== 'DEV'` (case-insensitive) |
|
|
229
|
-
| `getFrontendUrl()` | `string` | `FRONTEND_URL` |
|
|
230
|
-
| `getOrigins()` | `string[]` | `ALLOW_ORIGINS` split by comma |
|
|
231
|
-
| `getTypeOrmConfig()` | `IDatabaseConfig` | DB connection config |
|
|
232
|
-
| `getJwtConfig()` | `IJwtConfig` | JWT secrets and expirations |
|
|
233
|
-
| `getRedisUrl()` | `string` | `REDIS_URL` (default: `redis://localhost:6379`) |
|
|
234
|
-
| `getMailConfig()` | `IMailConfig` | `MAIL_FROM`, `MAIL_APP_PASSWORD` |
|
|
235
|
-
| `getTenantId()` | `string \| null` | `TENANT_ID` or null |
|
|
236
|
-
| `useTenantMode()` | `boolean` | `USE_TENANT_MODE` |
|
|
237
|
-
| `getLogConfig()` | `ILogConfig` | Logging configuration |
|
|
238
|
-
| `getEnv()` | `Record<string, string>` | Full `process.env` snapshot |
|
|
239
|
-
|
|
240
|
-
---
|
|
241
|
-
|
|
242
|
-
## Migration CLI
|
|
243
|
-
|
|
244
|
-
### Migration Config File
|
|
41
|
+
```typescript
|
|
42
|
+
import { createMigrationDataSource, IMigrationConfig } from '@flusys/nestjs-core';
|
|
43
|
+
import { envConfig } from '@flusys/nestjs-core/config';
|
|
44
|
+
import { getAuthEntitiesByConfig } from '@flusys/nestjs-auth';
|
|
45
|
+
import { getIAMEntitiesByConfig } from '@flusys/nestjs-iam';
|
|
245
46
|
|
|
246
|
-
|
|
47
|
+
const bootstrapConfig = {
|
|
48
|
+
databaseMode: 'single' as const,
|
|
49
|
+
enableCompanyFeature: true,
|
|
50
|
+
permissionMode: 'FULL' as const,
|
|
51
|
+
};
|
|
247
52
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const config: IMigrationConfig = {
|
|
254
|
-
defaultDatabaseConfig: {
|
|
255
|
-
type: 'postgres',
|
|
256
|
-
host: process.env.DB_HOST ?? 'localhost',
|
|
257
|
-
port: Number(process.env.DB_PORT ?? 5432),
|
|
258
|
-
username: process.env.DB_USER ?? 'postgres',
|
|
259
|
-
password: process.env.DB_PASSWORD ?? '',
|
|
260
|
-
database: process.env.DB_NAME ?? 'myapp',
|
|
261
|
-
},
|
|
53
|
+
export const migrationConfig: IMigrationConfig = {
|
|
54
|
+
defaultDatabaseConfig: envConfig.getTypeOrmConfig(),
|
|
55
|
+
bootstrapAppConfig: bootstrapConfig,
|
|
56
|
+
migrationsPath: `${__dirname}/migrations`,
|
|
57
|
+
migrationsTableName: 'migrations',
|
|
262
58
|
entities: [
|
|
263
|
-
...
|
|
264
|
-
...
|
|
265
|
-
// ... other module entities
|
|
59
|
+
...getAuthEntitiesByConfig(bootstrapConfig),
|
|
60
|
+
...getIAMEntitiesByConfig(bootstrapConfig),
|
|
266
61
|
],
|
|
267
|
-
migrationsPath: 'src/migrations',
|
|
268
|
-
migrationsTableName: 'migrations',
|
|
269
62
|
};
|
|
270
63
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
# Generate a new migration (compares entities to current DB schema)
|
|
278
|
-
npm run migration:generate -- -n CreateUsersTable
|
|
279
|
-
|
|
280
|
-
# Run all pending migrations
|
|
281
|
-
npm run migration:run
|
|
282
|
-
|
|
283
|
-
# Revert the last applied migration
|
|
284
|
-
npm run migration:revert
|
|
285
|
-
|
|
286
|
-
# Show migration status (which are applied, which are pending)
|
|
287
|
-
npm run migration:status
|
|
288
|
-
|
|
289
|
-
# Multi-tenant: run migrations for all tenants
|
|
290
|
-
npm run migration:run:all
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### Programmatic API
|
|
294
|
-
|
|
295
|
-
```typescript
|
|
296
|
-
import {
|
|
297
|
-
createMigrationDataSource,
|
|
298
|
-
runMigrations,
|
|
299
|
-
revertMigration,
|
|
300
|
-
migrationStatus,
|
|
301
|
-
generateMigration,
|
|
302
|
-
runForAllTenants,
|
|
303
|
-
} from '@flusys/nestjs-core';
|
|
304
|
-
|
|
305
|
-
// Create a DataSource for migration operations
|
|
306
|
-
const dataSource = await createMigrationDataSource(config, tenantId);
|
|
307
|
-
|
|
308
|
-
// Run pending migrations
|
|
309
|
-
await runMigrations(dataSource);
|
|
310
|
-
|
|
311
|
-
// Revert last migration
|
|
312
|
-
await revertMigration(dataSource);
|
|
313
|
-
|
|
314
|
-
// Check status
|
|
315
|
-
const status = await migrationStatus(dataSource);
|
|
316
|
-
|
|
317
|
-
// Generate a new migration file
|
|
318
|
-
await generateMigration(config, 'MigrationName');
|
|
319
|
-
|
|
320
|
-
// Multi-tenant: run for all configured tenants
|
|
321
|
-
await runForAllTenants(config, runMigrations);
|
|
64
|
+
// Required for TypeORM CLI
|
|
65
|
+
export default createMigrationDataSource({
|
|
66
|
+
config: migrationConfig,
|
|
67
|
+
tenantId: process.env.TENANT_ID,
|
|
68
|
+
});
|
|
322
69
|
```
|
|
323
70
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
## Seed System
|
|
327
|
-
|
|
328
|
-
### BaseSeeder
|
|
329
|
-
|
|
330
|
-
Extend `BaseSeeder` to create custom seeders:
|
|
71
|
+
### Add scripts to `package.json`
|
|
331
72
|
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
await repo.save([
|
|
344
|
-
{ email: 'admin@example.com', name: 'Admin User' },
|
|
345
|
-
]);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
async clear(dataSource: DataSource): Promise<void> {
|
|
349
|
-
await dataSource.getRepository(User).delete({});
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"scripts": {
|
|
76
|
+
"migration": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli --config=src/persistence/migration.config.ts",
|
|
77
|
+
"migration:generate": "npm run migration -- generate",
|
|
78
|
+
"migration:run": "npm run migration -- run",
|
|
79
|
+
"migration:revert": "npm run migration -- revert",
|
|
80
|
+
"migration:status": "npm run migration -- status",
|
|
81
|
+
"migration:run:all": "npm run migration -- run:all",
|
|
82
|
+
"migration:revert:all": "npm run migration -- revert:all",
|
|
83
|
+
"migration:status:all": "npm run migration -- status:all"
|
|
350
84
|
}
|
|
351
85
|
}
|
|
352
86
|
```
|
|
353
87
|
|
|
354
|
-
###
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
import { SeedRunner, seedConfig } from '@flusys/nestjs-core';
|
|
358
|
-
|
|
359
|
-
// Register seeders
|
|
360
|
-
seedConfig.register([UserSeeder, RoleSeeder, PermissionSeeder]);
|
|
361
|
-
|
|
362
|
-
// Run all seeders (respects order and dependencies)
|
|
363
|
-
const runner = new SeedRunner(dataSource);
|
|
364
|
-
const result = await runner.run();
|
|
365
|
-
console.log(`Seeded ${result.count} records`);
|
|
366
|
-
|
|
367
|
-
// Clear all seeded data (in reverse order)
|
|
368
|
-
await runner.clear();
|
|
369
|
-
|
|
370
|
-
// Check seeder status
|
|
371
|
-
const status = await runner.status();
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
### DataGenerator
|
|
375
|
-
|
|
376
|
-
Generates realistic test data from TypeORM entity metadata using Faker.js:
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
import { DataGenerator } from '@flusys/nestjs-core';
|
|
380
|
-
|
|
381
|
-
const generator = new DataGenerator(dataSource);
|
|
382
|
-
|
|
383
|
-
// Auto-detect field types and generate appropriate data
|
|
384
|
-
const fakeUser = generator.generate(User, {
|
|
385
|
-
overrides: { email: 'specific@email.com' },
|
|
386
|
-
count: 10, // generate 10 records
|
|
387
|
-
});
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
**Automatic field pattern detection:**
|
|
391
|
-
|
|
392
|
-
| Pattern | Generated value |
|
|
393
|
-
|---------|----------------|
|
|
394
|
-
| `email` | `faker.internet.email()` |
|
|
395
|
-
| `name`, `title` | `faker.person.fullName()` |
|
|
396
|
-
| `phone` | `faker.phone.number()` |
|
|
397
|
-
| `address` | `faker.location.streetAddress()` |
|
|
398
|
-
| `url`, `website` | `faker.internet.url()` |
|
|
399
|
-
| `description`, `text` | `faker.lorem.paragraph()` |
|
|
400
|
-
| `slug` | `faker.helpers.slugify()` |
|
|
401
|
-
| `uuid`, `id` | `faker.string.uuid()` |
|
|
402
|
-
| `boolean`, `isActive` | `faker.datatype.boolean()` |
|
|
403
|
-
| `date`, `createdAt` | `faker.date.recent()` |
|
|
404
|
-
| `number`, `price` | `faker.number.int()` |
|
|
405
|
-
|
|
406
|
-
### Seed CLI
|
|
88
|
+
### Run
|
|
407
89
|
|
|
408
90
|
```bash
|
|
409
|
-
#
|
|
410
|
-
npm run
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
npm run
|
|
414
|
-
|
|
415
|
-
# Show seeder status
|
|
416
|
-
npm run seed:status
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
---
|
|
420
|
-
|
|
421
|
-
## Swagger Documentation
|
|
422
|
-
|
|
423
|
-
### setupSwaggerDocs
|
|
424
|
-
|
|
425
|
-
Sets up a single global Swagger UI for the whole application:
|
|
426
|
-
|
|
427
|
-
```typescript
|
|
428
|
-
import { setupSwaggerDocs } from '@flusys/nestjs-core/docs';
|
|
429
|
-
|
|
430
|
-
setupSwaggerDocs(app, {
|
|
431
|
-
title: 'My API',
|
|
432
|
-
description: 'API documentation',
|
|
433
|
-
version: '1.0.0',
|
|
434
|
-
path: 'api/docs', // default: 'api/docs'
|
|
435
|
-
bearerAuthEnabled: true, // default: true
|
|
436
|
-
persistAuthorization: true, // default: true
|
|
437
|
-
});
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### setupModuleSwaggerDocs
|
|
441
|
-
|
|
442
|
-
Sets up module-scoped Swagger documentation at separate URLs — one per feature module:
|
|
443
|
-
|
|
444
|
-
```typescript
|
|
445
|
-
import { setupModuleSwaggerDocs } from '@flusys/nestjs-core/docs';
|
|
446
|
-
|
|
447
|
-
setupModuleSwaggerDocs(app, [
|
|
448
|
-
{
|
|
449
|
-
title: 'Authentication API',
|
|
450
|
-
description: 'Auth endpoints',
|
|
451
|
-
version: '1.0.0',
|
|
452
|
-
path: 'api/docs/auth',
|
|
453
|
-
includeTags: ['Authentication', 'Users', 'Companies'],
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
title: 'IAM API',
|
|
457
|
-
description: 'Permissions and roles',
|
|
458
|
-
version: '1.0.0',
|
|
459
|
-
path: 'api/docs/iam',
|
|
460
|
-
includeTags: ['Roles', 'Actions', 'Permissions'],
|
|
461
|
-
},
|
|
462
|
-
{
|
|
463
|
-
title: 'Storage API',
|
|
464
|
-
description: 'File management',
|
|
465
|
-
version: '1.0.0',
|
|
466
|
-
path: 'api/docs/storage',
|
|
467
|
-
includeTags: ['Files', 'Folders'],
|
|
468
|
-
},
|
|
469
|
-
]);
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### IModuleSwaggerOptions
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
interface IModuleSwaggerOptions {
|
|
476
|
-
title: string;
|
|
477
|
-
description?: string;
|
|
478
|
-
version?: string;
|
|
479
|
-
path: string;
|
|
480
|
-
includeTags?: string[]; // Whitelist specific controller tags
|
|
481
|
-
excludeTags?: string[]; // Blacklist specific controller tags
|
|
482
|
-
includeSchemas?: string[]; // Whitelist specific DTO schemas
|
|
483
|
-
excludeSchemas?: string[]; // Blacklist specific DTO schemas
|
|
484
|
-
bearerAuthEnabled?: boolean;
|
|
485
|
-
persistAuthorization?: boolean;
|
|
486
|
-
}
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
---
|
|
490
|
-
|
|
491
|
-
## Database Utilities
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
import { buildDataSourceOptions, getMigrationsFolderPath, getActiveTenants } from '@flusys/nestjs-core';
|
|
495
|
-
|
|
496
|
-
// Build a TypeORM DataSourceOptions object
|
|
497
|
-
const options = buildDataSourceOptions({
|
|
498
|
-
config: databaseConfig,
|
|
499
|
-
entities: [...authEntities, ...iamEntities],
|
|
500
|
-
migrationsPath: 'src/migrations',
|
|
501
|
-
migrationsTableName: 'migrations',
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
// Get migrations folder path (supports tenant-specific subdirectories)
|
|
505
|
-
const migrationsPath = getMigrationsFolderPath('src/migrations', 'tenant-1');
|
|
506
|
-
|
|
507
|
-
// Get all active tenant configs
|
|
508
|
-
const tenants = getActiveTenants(migrationConfig);
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
---
|
|
512
|
-
|
|
513
|
-
## Core Interfaces
|
|
514
|
-
|
|
515
|
-
These interfaces are used as contracts across all FLUSYS feature modules:
|
|
516
|
-
|
|
517
|
-
```typescript
|
|
518
|
-
// Entity contracts
|
|
519
|
-
interface IIdentity { id: string; createdAt: Date; updatedAt: Date; deletedAt?: Date | null; }
|
|
520
|
-
|
|
521
|
-
// Bootstrap configuration (fixed at startup)
|
|
522
|
-
interface IBootstrapAppConfig {
|
|
523
|
-
databaseMode: 'single' | 'multi-tenant';
|
|
524
|
-
enableCompanyFeature: boolean;
|
|
525
|
-
enableEmailVerification?: boolean;
|
|
526
|
-
permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// DataSource configuration
|
|
530
|
-
interface IDatabaseConfig {
|
|
531
|
-
type: 'postgres' | 'mysql' | 'mariadb' | 'sqlite' | 'mssql';
|
|
532
|
-
host: string;
|
|
533
|
-
port: number;
|
|
534
|
-
username: string;
|
|
535
|
-
password: string;
|
|
536
|
-
database: string;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Multi-tenant config
|
|
540
|
-
interface ITenantDatabaseConfig extends IDatabaseConfig { id: string; }
|
|
541
|
-
|
|
542
|
-
// Module options for dynamic modules
|
|
543
|
-
interface IDynamicModuleConfig {
|
|
544
|
-
global?: boolean;
|
|
545
|
-
includeController?: boolean;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// DataSource service options (base for all module configs)
|
|
549
|
-
interface IDataSourceServiceOptions {
|
|
550
|
-
defaultDatabaseConfig?: IDatabaseConfig;
|
|
551
|
-
tenantDefaultDatabaseConfig?: IDatabaseConfig;
|
|
552
|
-
tenants?: ITenantDatabaseConfig[];
|
|
553
|
-
}
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
---
|
|
557
|
-
|
|
558
|
-
## Injection Tokens & Constants
|
|
559
|
-
|
|
560
|
-
```typescript
|
|
561
|
-
import {
|
|
562
|
-
MIGRATION_CONFIG_TOKEN,
|
|
563
|
-
SEED_CONFIG_TOKEN,
|
|
564
|
-
DATASOURCE_TOKEN,
|
|
565
|
-
} from '@flusys/nestjs-core';
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
---
|
|
569
|
-
|
|
570
|
-
## Multi-Tenant Support
|
|
571
|
-
|
|
572
|
-
`nestjs-core` provides the foundation for multi-tenant architectures:
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
import { buildDataSourceOptions, getDatabaseForTenant, getActiveTenants } from '@flusys/nestjs-core';
|
|
576
|
-
|
|
577
|
-
// Get database config for a specific tenant
|
|
578
|
-
const tenantDb = getDatabaseForTenant(migrationConfig, 'tenant-id');
|
|
91
|
+
# Single database
|
|
92
|
+
npm run migration:generate -- --name=CreateUsersTable
|
|
93
|
+
npm run migration:run
|
|
94
|
+
npm run migration:revert
|
|
95
|
+
npm run migration:status
|
|
579
96
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
});
|
|
97
|
+
# Tenant-specific (prefix with TENANT_ID)
|
|
98
|
+
TENANT_ID=tenant-1 npm run migration:generate -- --name=CreateUsersTable
|
|
99
|
+
TENANT_ID=tenant-1 npm run migration:run
|
|
100
|
+
TENANT_ID=tenant-1 npm run migration:revert
|
|
101
|
+
TENANT_ID=tenant-1 npm run migration:status
|
|
586
102
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
103
|
+
# All tenants at once
|
|
104
|
+
npm run migration:run:all
|
|
105
|
+
npm run migration:revert:all
|
|
106
|
+
npm run migration:status:all
|
|
591
107
|
```
|
|
592
108
|
|
|
593
109
|
---
|
|
594
110
|
|
|
595
|
-
##
|
|
596
|
-
|
|
597
|
-
**`Cannot find migration config file`**
|
|
598
|
-
|
|
599
|
-
Ensure `migration.config.ts` exists at the project root and exports a default `IMigrationConfig` object. The CLI looks for it relative to the current working directory.
|
|
600
|
-
|
|
601
|
-
---
|
|
602
|
-
|
|
603
|
-
**`RESTRICTED_KEY` error from `tryGetValue`**
|
|
111
|
+
## 3. Swagger
|
|
604
112
|
|
|
605
|
-
|
|
113
|
+
`setupSwaggerDocs` and `setupModuleSwaggerDocs` accept the same `IModuleSwaggerOptions` shape.
|
|
606
114
|
|
|
607
115
|
```typescript
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
// Correct
|
|
612
|
-
envConfig.getJwtConfig().secret
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
---
|
|
616
|
-
|
|
617
|
-
**`SnakeNamingStrategy` column name mismatch**
|
|
618
|
-
|
|
619
|
-
All columns use `snake_case` by default. A TypeScript property `createdAt` maps to column `created_at`. If your existing schema uses camelCase, override the naming strategy in `buildDataSourceOptions`.
|
|
620
|
-
|
|
621
|
-
---
|
|
116
|
+
import { NestFactory } from '@nestjs/core';
|
|
117
|
+
import { setupSwaggerDocs, setupModuleSwaggerDocs } from '@flusys/nestjs-core/docs';
|
|
118
|
+
import { AuthModule } from '@flusys/nestjs-auth';
|
|
622
119
|
|
|
623
|
-
|
|
120
|
+
async function bootstrap() {
|
|
121
|
+
const app = await NestFactory.create(AppModule);
|
|
624
122
|
|
|
625
|
-
|
|
123
|
+
// All available options (one entry showing every field)
|
|
124
|
+
setupModuleSwaggerDocs(app, [
|
|
125
|
+
{
|
|
126
|
+
title: 'Auth API', // required
|
|
127
|
+
description: 'Auth endpoints', // required
|
|
128
|
+
version: '1.0', // optional, default '1.0'
|
|
129
|
+
path: 'api/docs/auth', // required — URL where docs are served
|
|
130
|
+
bearerAuth: true, // adds Authorization header to Swagger UI
|
|
131
|
+
modules: [AuthModule], // scope to specific NestJS modules only
|
|
132
|
+
|
|
133
|
+
// Exclude controllers by @ApiTags name
|
|
134
|
+
excludeTags: ['Internal', 'Health'],
|
|
135
|
+
|
|
136
|
+
// Exclude specific paths (supports * and ** wildcards)
|
|
137
|
+
excludePaths: ['/api/auth/internal/*', '/api/health'],
|
|
138
|
+
|
|
139
|
+
// Exclude properties from a DTO schema
|
|
140
|
+
excludeSchemaProperties: [
|
|
141
|
+
{ schemaName: 'CreateUserDto', properties: ['passwordHash', 'salt'] },
|
|
142
|
+
],
|
|
143
|
+
|
|
144
|
+
// Exclude query parameters from specific endpoints
|
|
145
|
+
excludeQueryParameters: [
|
|
146
|
+
{ pathPattern: '/api/auth/*', method: 'post', parameters: ['debug'] },
|
|
147
|
+
],
|
|
148
|
+
|
|
149
|
+
// Exclude named examples from responses
|
|
150
|
+
excludeExamples: [
|
|
151
|
+
{ pathPattern: '/api/auth/login', examples: ['AdminExample'] },
|
|
152
|
+
],
|
|
153
|
+
|
|
154
|
+
// Add a custom header to every request in Swagger UI
|
|
155
|
+
globalHeaders: [
|
|
156
|
+
{ name: 'x-tenant-id', description: 'Tenant identifier', required: false, example: 'tenant-1' },
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Minimal entry
|
|
161
|
+
{ title: 'IAM API', description: 'Roles and permissions', path: 'api/docs/iam' },
|
|
162
|
+
]);
|
|
626
163
|
|
|
627
|
-
|
|
628
|
-
export class ProductSeeder extends BaseSeeder {
|
|
629
|
-
name = 'ProductSeeder';
|
|
630
|
-
dependencies = ['CategorySeeder']; // CategorySeeder must run first
|
|
164
|
+
await app.listen(3000);
|
|
631
165
|
}
|
|
632
166
|
```
|
|
633
167
|
|
|
634
|
-
---
|
|
635
168
|
|
|
636
169
|
## License
|
|
637
170
|
|
|
638
171
|
MIT © FLUSYS
|
|
639
|
-
|
|
640
|
-
---
|
|
641
|
-
|
|
642
|
-
> Part of the **FLUSYS** framework — a full-stack monorepo powering Angular 21 + NestJS 11 applications.
|