@venizia/ignis-docs 0.2.0 → 0.2.1-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.
Files changed (174) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +24 -13
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +8 -4
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +247 -153
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +109 -323
  26. package/content/extensions/components/authentication/api.md +489 -602
  27. package/content/extensions/components/authentication/errors.md +135 -498
  28. package/content/extensions/components/authentication/index.md +89 -801
  29. package/content/extensions/components/authentication/usage.md +231 -955
  30. package/content/extensions/components/authorization/api.md +991 -644
  31. package/content/extensions/components/authorization/errors.md +204 -208
  32. package/content/extensions/components/authorization/getting-started.md +227 -0
  33. package/content/extensions/components/authorization/index.md +88 -795
  34. package/content/extensions/components/authorization/usage.md +219 -528
  35. package/content/extensions/components/health-check.md +77 -243
  36. package/content/extensions/components/index.md +24 -90
  37. package/content/extensions/components/mail/api.md +553 -285
  38. package/content/extensions/components/mail/errors.md +76 -62
  39. package/content/extensions/components/mail/index.md +111 -463
  40. package/content/extensions/components/mail/usage.md +139 -173
  41. package/content/extensions/components/request-tracker.md +70 -173
  42. package/content/extensions/components/socket-io/api.md +462 -785
  43. package/content/extensions/components/socket-io/errors.md +49 -51
  44. package/content/extensions/components/socket-io/index.md +69 -372
  45. package/content/extensions/components/socket-io/usage.md +212 -105
  46. package/content/extensions/components/static-asset/api.md +461 -141
  47. package/content/extensions/components/static-asset/errors.md +121 -53
  48. package/content/extensions/components/static-asset/index.md +84 -606
  49. package/content/extensions/components/static-asset/usage.md +184 -299
  50. package/content/extensions/components/template/index.md +3 -3
  51. package/content/extensions/components/websocket/api.md +311 -404
  52. package/content/extensions/components/websocket/errors.md +47 -56
  53. package/content/extensions/components/websocket/index.md +75 -407
  54. package/content/extensions/components/websocket/usage.md +120 -338
  55. package/content/extensions/helpers/cron/index.md +52 -160
  56. package/content/extensions/helpers/crypto/index.md +67 -480
  57. package/content/extensions/helpers/crypto/reference.md +528 -0
  58. package/content/extensions/helpers/env/index.md +64 -178
  59. package/content/extensions/helpers/error/index.md +286 -196
  60. package/content/extensions/helpers/index.md +61 -47
  61. package/content/extensions/helpers/inversion/index.md +76 -550
  62. package/content/extensions/helpers/inversion/reference.md +530 -0
  63. package/content/extensions/helpers/kafka/admin.md +23 -3
  64. package/content/extensions/helpers/kafka/compile-binary.md +83 -52
  65. package/content/extensions/helpers/kafka/consumer.md +65 -28
  66. package/content/extensions/helpers/kafka/examples.md +46 -253
  67. package/content/extensions/helpers/kafka/index.md +55 -617
  68. package/content/extensions/helpers/kafka/producer.md +156 -22
  69. package/content/extensions/helpers/kafka/schema-registry.md +59 -79
  70. package/content/extensions/helpers/logger/hf-logger.md +220 -0
  71. package/content/extensions/helpers/logger/index.md +78 -552
  72. package/content/extensions/helpers/logger/pino.md +105 -0
  73. package/content/extensions/helpers/logger/reference.md +937 -0
  74. package/content/extensions/helpers/network/api.md +276 -195
  75. package/content/extensions/helpers/network/index.md +87 -524
  76. package/content/extensions/helpers/queue/index.md +80 -897
  77. package/content/extensions/helpers/queue/reference.md +494 -0
  78. package/content/extensions/helpers/redis/index.md +86 -640
  79. package/content/extensions/helpers/redis/reference.md +784 -0
  80. package/content/extensions/helpers/secrets/index.md +136 -0
  81. package/content/extensions/helpers/socket-io/api.md +325 -204
  82. package/content/extensions/helpers/socket-io/index.md +79 -429
  83. package/content/extensions/helpers/storage/api.md +584 -464
  84. package/content/extensions/helpers/storage/index.md +80 -573
  85. package/content/extensions/helpers/types/index.md +75 -495
  86. package/content/extensions/helpers/types/reference.md +689 -0
  87. package/content/extensions/helpers/uid/index.md +176 -189
  88. package/content/extensions/helpers/websocket/api.md +366 -214
  89. package/content/extensions/helpers/websocket/index.md +68 -503
  90. package/content/extensions/helpers/worker-thread/index.md +62 -396
  91. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  92. package/content/extensions/index.md +38 -39
  93. package/content/extensions/src-details/mcp-server.md +96 -548
  94. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  95. package/content/guides/core-concepts/persistent/index.md +5 -1
  96. package/content/guides/core-concepts/persistent/models.md +1 -1
  97. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  98. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  99. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  100. package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
  101. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  102. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  103. package/content/guides/core-concepts/secrets-vault.md +177 -0
  104. package/content/guides/core-concepts/services.md +1 -1
  105. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  106. package/content/guides/get-started/philosophy.md +135 -670
  107. package/content/guides/get-started/setup.md +53 -74
  108. package/content/guides/migrations/redis-helpers-migration.md +5 -4
  109. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  110. package/content/guides/migrations/unified-connectors-migration.md +8 -7
  111. package/content/guides/tutorials/ecommerce-api.md +3 -8
  112. package/content/guides/tutorials/realtime-chat.md +1 -1
  113. package/content/references/base/application.md +64 -22
  114. package/content/references/base/components.md +3 -3
  115. package/content/references/base/connectors.md +79 -136
  116. package/content/references/base/controllers.md +12 -12
  117. package/content/references/base/datasources-reference.md +600 -0
  118. package/content/references/base/datasources.md +84 -444
  119. package/content/references/base/dependency-injection.md +25 -46
  120. package/content/references/base/filter-system/application-usage.md +95 -123
  121. package/content/references/base/filter-system/array-operators.md +33 -43
  122. package/content/references/base/filter-system/comparison-operators.md +55 -63
  123. package/content/references/base/filter-system/default-filter.md +144 -350
  124. package/content/references/base/filter-system/fields-order-pagination.md +116 -148
  125. package/content/references/base/filter-system/index.md +114 -253
  126. package/content/references/base/filter-system/json-filtering.md +52 -181
  127. package/content/references/base/filter-system/list-operators.md +28 -44
  128. package/content/references/base/filter-system/logical-operators.md +69 -114
  129. package/content/references/base/filter-system/null-operators.md +41 -98
  130. package/content/references/base/filter-system/pattern-matching.md +48 -51
  131. package/content/references/base/filter-system/quick-reference.md +93 -196
  132. package/content/references/base/filter-system/range-operators.md +22 -38
  133. package/content/references/base/filter-system/tips.md +70 -133
  134. package/content/references/base/filter-system/use-cases.md +173 -232
  135. package/content/references/base/grpc-controllers.md +53 -17
  136. package/content/references/base/index.md +5 -3
  137. package/content/references/base/middlewares.md +43 -28
  138. package/content/references/base/models-reference.md +886 -0
  139. package/content/references/base/models.md +81 -1452
  140. package/content/references/base/providers.md +8 -8
  141. package/content/references/base/repositories/advanced.md +281 -419
  142. package/content/references/base/repositories/index.md +84 -644
  143. package/content/references/base/repositories/mixins.md +25 -21
  144. package/content/references/base/repositories/relations.md +194 -375
  145. package/content/references/base/repositories/soft-deletable.md +67 -55
  146. package/content/references/base/secrets.md +267 -0
  147. package/content/references/base/services.md +8 -6
  148. package/content/references/configuration/environment-variables.md +73 -21
  149. package/content/references/configuration/index.md +51 -31
  150. package/content/references/index.md +1 -1
  151. package/content/references/quick-reference.md +3 -16
  152. package/content/references/utilities/crypto.md +35 -76
  153. package/content/references/utilities/date.md +33 -73
  154. package/content/references/utilities/duration.md +85 -0
  155. package/content/references/utilities/index.md +6 -2
  156. package/content/references/utilities/jsx-reference.md +298 -0
  157. package/content/references/utilities/jsx.md +82 -525
  158. package/content/references/utilities/module.md +81 -61
  159. package/content/references/utilities/parse.md +34 -64
  160. package/content/references/utilities/performance.md +33 -58
  161. package/content/references/utilities/promise.md +28 -62
  162. package/content/references/utilities/request.md +58 -218
  163. package/content/references/utilities/retry.md +139 -0
  164. package/content/references/utilities/schema.md +43 -137
  165. package/content/references/utilities/statuses-reference.md +361 -0
  166. package/content/references/utilities/statuses.md +63 -667
  167. package/dist/mcp-server/index.js +0 -0
  168. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  169. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  171. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  172. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  173. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  174. package/package.json +24 -23
@@ -102,6 +102,9 @@ Controller → Service → Repository → DataSource
102
102
  // ✅ Error Handling
103
103
  throw getError({ statusCode: 404, message: 'User not found' });
104
104
 
105
+ // ✅ Scoped Logging (ILogger - never names a provider)
106
+ this.logger.for('createUser').info('User created | id: %s', user.id);
107
+
105
108
  // ✅ Input Validation
106
109
  request: { body: jsonContent({ schema: z.object({ email: z.string().email() }) }) }
107
110
  ```
@@ -120,6 +123,9 @@ async getUser(c: Context) {
120
123
  // ❌ Catching all errors silently
121
124
  try { await riskyOperation(); } catch (e) { /* swallowed */ }
122
125
 
126
+ // ❌ Raw Error - loses statusCode, messageCode and the normalized response shape
127
+ throw new Error('User not found'); // Use getError()
128
+
123
129
  // ❌ Using `any` type
124
130
  const data: any = await fetchData(); // Use proper types!
125
131
  ```
@@ -9,6 +9,7 @@ Identify bottlenecks before optimizing:
9
9
  ```typescript
10
10
  import { executeWithPerformanceMeasure } from '@venizia/ignis-helpers';
11
11
 
12
+ // `logger` is optional and typed `ILogger` - it falls back to `console` when omitted.
12
13
  await executeWithPerformanceMeasure({
13
14
  logger: this.logger,
14
15
  scope: 'DataProcessing',
@@ -148,13 +149,22 @@ if (!cached) {
148
149
 
149
150
  | Setting | Value | Why |
150
151
  |---------|-------|-----|
151
- | `NODE_ENV` | `production` | Enables library optimizations |
152
- | Process Manager | PM2, systemd, Docker | Auto-restart, cluster mode |
153
- | Cluster Mode | CPU cores | Utilize all CPUs |
152
+ | `NODE_ENV` | `production` | Enables library optimizations; also gates error-detail leakage (unset is treated as production) |
153
+ | `APP_ENV_LOGGER_LEVEL` | `info` or `warn` | Keep hot-path logging off the critical path |
154
+ | Process Manager | systemd, Docker, Kubernetes | Auto-restart, supervision |
155
+ | Horizontal Scaling | One process per CPU core | Utilize all CPUs |
156
+
157
+ Bun has no PM2-style cluster mode, and `Bun.serve` is started without `reusePort` - two processes cannot share a port. Scale out with one process per port behind a reverse proxy, or with container replicas:
158
+
159
+ ```bash
160
+ # Each replica binds its own port; nginx / a load balancer fans out across them
161
+ APP_ENV_SERVER_PORT=3000 NODE_ENV=production bun run dist/index.js &
162
+ APP_ENV_SERVER_PORT=3001 NODE_ENV=production bun run dist/index.js &
163
+ ```
154
164
 
155
- **PM2 Cluster Mode:**
156
165
  ```bash
157
- pm2 start dist/index.js -i max # Use all CPU cores
166
+ # Or let the orchestrator do it
167
+ docker compose up -d --scale app=4
158
168
  ```
159
169
 
160
170
  ## 6. Transaction Support
@@ -208,12 +218,12 @@ Connection pooling significantly improves performance by reusing database connec
208
218
  ```typescript
209
219
  import { Pool } from 'pg';
210
220
  import { datasource } from '@venizia/ignis';
211
- import { BasePostgresDataSource } from '@venizia/ignis/postgres';
221
+ import { BaseRelationalDataSource } from '@venizia/ignis/postgres';
212
222
  import { NodePostgresDriver } from '@venizia/ignis/postgres/node-postgres';
213
223
 
214
224
  // IDataSourceConfigs: your settings interface (host/port/user/password/database)
215
225
  @datasource({ driver: NodePostgresDriver })
216
- export class PostgresDataSource extends BasePostgresDataSource<IDataSourceConfigs> {
226
+ export class PostgresDataSource extends BaseRelationalDataSource<IDataSourceConfigs> {
217
227
  override configure(): void {
218
228
  // Keep the pool on `this.client` - NodePostgresDriver above wires the driver and Drizzle
219
229
  // connector from it lazily, on first getConnector()/beginTransaction()
@@ -385,9 +395,9 @@ const logger = HfLogger.get('OrderEngine');
385
395
  const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
386
396
  const MSG_ORDER_FILLED = HfLogger.encodeMessage('Order filled');
387
397
 
388
- // Start background flusher
398
+ // Start background flusher (writes to stdout by default; pass { filePath } or { sink })
389
399
  const flusher = new HfLogFlusher();
390
- flusher.start(100); // Flush every 100ms
400
+ flusher.start(100); // Flush interval in ms - 100 is also the default
391
401
 
392
402
  // In hot path (~100-300ns, zero allocation):
393
403
  logger.log('info', MSG_ORDER_SENT);
@@ -395,11 +405,14 @@ logger.log('info', MSG_ORDER_FILLED);
395
405
  ```
396
406
 
397
407
  **Key points:**
408
+ - `log(level, bytes)` is the zero-allocation path. Passing a string, or any `...args`, falls back to formatting
409
+ - Levels are the same five as `ILogger`: `debug`, `info`, `warn`, `error`, `emerg`
398
410
  - Pre-encode messages at initialization, not in hot path
399
- - Use background flushing to avoid I/O blocking
400
- - HfLogger uses a lock-free ring buffer (64K entries, 16MB)
411
+ - HfLogger uses a lock-free ring buffer (64K entries x 256 bytes = 16MB), allocated lazily on first use
412
+ - Scope truncates at 32 UTF-8 bytes, message at 213 - silently
413
+ - For the standard logger, narrow output with `APP_ENV_LOGGER_LEVEL` in production and keep debug lines behind the `DEBUG` gate (pre-computed at module load, near-zero cost when off)
401
414
 
402
- > **Deep Dive:** See [Logger Helper](../extensions/helpers/logger/) for complete HfLogger API.
415
+ > **Deep Dive:** See [HfLogger](../extensions/helpers/logger/hf-logger.md) for the complete API.
403
416
 
404
417
  ## Performance Checklist
405
418
 
@@ -414,7 +427,7 @@ logger.log('info', MSG_ORDER_FILLED);
414
427
  | **Memory** | Large datasets processed in batches | High |
415
428
  | **Caching** | Expensive queries cached | High |
416
429
  | **Workers** | CPU-intensive tasks offloaded | High |
417
- | **Logging** | HfLogger for hot paths (HFT) | High |
430
+ | **Logging** | HfLogger for hot paths (HFT); `APP_ENV_LOGGER_LEVEL` in production | High |
418
431
  | **Monitoring** | Performance logging enabled | Low |
419
432
 
420
433
  ## See Also
@@ -20,17 +20,17 @@ APP_ENV_POSTGRES_PASSWORD=database_password_here
20
20
 
21
21
  **Generate strong secrets:**
22
22
  ```bash
23
- node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
23
+ bun -e "console.log(Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64'))"
24
24
  ```
25
25
 
26
26
  ### Redaction at Log Time
27
27
 
28
- Never hard-coding a secret is not enough on its own -- an options object holding one still ends up in a log line the moment it is passed to `logger.info('...: %s', opts)`. `@venizia/ignis-helpers` provides two primitives for exactly this:
28
+ Never hard-coding a secret is not enough on its own. An options object holding one still ends up in a log line the moment it is passed to `logger.info('...: %s', opts)`. `@venizia/ignis-helpers` provides two primitives for exactly this:
29
29
 
30
30
  | Function | Use For | Behavior |
31
31
  |----------|---------|----------|
32
- | `redactSecrets(value)` | Any object/array being logged | Recursively replaces every value whose key matches a secret-looking name (`password`, `token`, `apiKey`, `authorization`, HTTP header spellings like `x-api-key`/`cookie`/`proxy-authorization`, etc., case-insensitive) with `'[REDACTED]'` |
33
- | `redactUrlCredentials(url)` | A connection/broker URL string | Strips the password out of a URL's authority section (`mqtts://user:hunter2@broker:8883` becomes `mqtts://user:[REDACTED]@broker:8883`); a value that doesn't parse as a URL is returned unchanged |
32
+ | `redactSecrets(value)` | Any object/array being logged | Recursively replaces every value whose key matches a secret-looking name with `'[REDACTED]'` |
33
+ | `redactUrlCredentials(url)` | A connection/broker URL string | Strips the password out of a URL's authority section: `mqtts://user:hunter2@broker:8883` becomes `mqtts://user:[REDACTED]@broker:8883`. A value that doesn't parse as a URL, or one with no password, is returned unchanged |
34
34
 
35
35
  ```typescript
36
36
  import { redactSecrets, redactUrlCredentials } from '@venizia/ignis-helpers';
@@ -39,7 +39,19 @@ this.logger.info('[connect] Options: %s', redactSecrets(connectionOptions));
39
39
  this.logger.info('[connect] Broker: %s', redactUrlCredentials(brokerUrl));
40
40
  ```
41
41
 
42
- These are the primitives the framework itself uses -- outbound HTTP request configs (`NodeFetcher`/`AxiosFetcher`, see [Network Helper](/extensions/helpers/network/)) and MQTT broker URLs (`MQTTClientHelper`, see [Queue Helper](/extensions/helpers/queue/)) are both redacted this way before they reach a log line.
42
+ `redactSecrets` matches on the **key name**, case-insensitively, at any depth:
43
+
44
+ - Options-object spellings: `password`, `passphrase`, `secret`, `token`, `apiKey`, `privateKey`, `credentials`, `authorization`, `connectionString`, ...
45
+ - Any `*_token` / `*Token` key: `access_token`, `refresh_token`, `vaultToken`, ...
46
+ - Vault wire keys: `client_token`, `secret_id`, `role_id`
47
+ - HTTP header spellings: `x-api-key`, `x-vault-token`, `cookie`, `set-cookie`, `proxy-authorization`, `www-authenticate`
48
+
49
+ It also handles the shapes naive redaction breaks on. An `Error` is reprojected so its non-enumerable `message`/`stack` survive. Cycles become `'[Circular]'`, and buffers/typed arrays are summarized as `[Binary N bytes]` instead of serialized.
50
+
51
+ These are the primitives the framework itself uses. Outbound HTTP request configs (`NodeFetcher`/`AxiosFetcher`, see [Network Helper](/extensions/helpers/network/)) and MQTT broker URLs (`MQTTClientHelper`, see [Queue Helper](/extensions/helpers/queue/)) are both redacted this way before they reach a log line.
52
+
53
+ > [!WARNING]
54
+ > `APP_ENV_LOGGER_DO_REDACT=false` turns both functions into the identity function. It is a local-debugging kill-switch and must never be set in production. The check is fail-closed - only the literal string `false` disables redaction - and is read per call, so it can be flipped at runtime.
43
55
 
44
56
  ## 2. Input Validation
45
57
 
@@ -110,7 +122,7 @@ Configure model properties that should **never be returned** through repository
110
122
  hiddenProperties: ['password', 'apiSecret', 'internalToken'],
111
123
  },
112
124
  })
113
- export class User extends BasePostgresEntity<typeof User.schema> {
125
+ export class User extends BaseRelationalEntity<typeof User.schema> {
114
126
  static override schema = pgTable('User', {
115
127
  ...generateIdColumnDefs({ id: { dataType: 'string' } }),
116
128
  email: text('email').notNull(),
@@ -131,7 +143,7 @@ export class User extends BasePostgresEntity<typeof User.schema> {
131
143
 
132
144
  ```typescript
133
145
  // For authentication - access password via connector
134
- const connector = userRepository.getConnector();
146
+ const connector = userRepository.connector;
135
147
  const [user] = await connector
136
148
  .select({ id: User.schema.id, password: User.schema.password })
137
149
  .from(User.schema)
@@ -339,7 +351,7 @@ const redisHelper = new RedisSingleHelper({
339
351
  name: 'rate-limiter',
340
352
  host: process.env.APP_ENV_REDIS_HOST ?? 'localhost',
341
353
  port: process.env.APP_ENV_REDIS_PORT ?? '6379',
342
- password: process.env.APP_ENV_REDIS_PASSWORD,
354
+ password: process.env.APP_ENV_REDIS_PASSWORD ?? '',
343
355
  });
344
356
 
345
357
  const distributedRateLimiter = async (opts: { key: string; max: number; windowSeconds: number }) => {
@@ -462,6 +474,18 @@ export class AuthService extends BaseService {
462
474
  }
463
475
  ```
464
476
 
477
+ ### Error Responses Are Hardened in Production
478
+
479
+ The global error handler decides what a client sees by environment, and it is **fail-closed**: an unset or unrecognized `NODE_ENV` is treated as production. Only `NODE_ENV` values in the development set relax it.
480
+
481
+ | In production | Behavior |
482
+ |---|---|
483
+ | Unexpected errors | Replaced with a generic `"Internal Server Error"` - raw text may carry SQL, schema names or connection details |
484
+ | Database constraint errors (400) | Base message only; the driver's `Detail:` (which echoes row values like emails), `Table:` and `Constraint:` are stripped |
485
+ | `details.stack` / `details.cause` | Omitted |
486
+
487
+ Deliberate `getError` messages are always returned verbatim, in every environment - so never put internal detail in one. Use `requestId` plus the server log to diagnose what the response no longer shows. See [Error Handling](./error-handling#_5-error-response-format).
488
+
465
489
  **Events to Log:**
466
490
  - Failed login attempts
467
491
  - Successful logins
@@ -471,7 +495,7 @@ export class AuthService extends BaseService {
471
495
  - Admin actions
472
496
 
473
497
  > [!NOTE]
474
- > When logging a request or connection config that might carry credentials, wrap it in `redactSecrets()` (or `redactUrlCredentials()` for a URL) rather than logging it raw -- see [Redaction at Log Time](#redaction-at-log-time) above. This is what the framework's own outbound HTTP and MQTT logging already does automatically.
498
+ > When logging a request or connection config that might carry credentials, wrap it in `redactSecrets()` (or `redactUrlCredentials()` for a URL) rather than logging it raw. See [Redaction at Log Time](#redaction-at-log-time) above. This is what the framework's own outbound HTTP and MQTT logging already does automatically.
475
499
 
476
500
  ## Security Checklist
477
501
 
@@ -489,6 +513,8 @@ Before deploying to production, verify:
489
513
  | **Dependencies** | No known vulnerabilities (`bun audit`) |
490
514
  | **HTTPS** | TLS configured for production |
491
515
  | **Hidden Data** | Sensitive fields use `hiddenProperties` |
516
+ | **Redaction** | `APP_ENV_LOGGER_DO_REDACT` is unset (never `false`) |
517
+ | **Error Leakage** | `NODE_ENV` set to a production value so responses are sanitized |
492
518
 
493
519
  ## See Also
494
520
 
@@ -102,8 +102,8 @@ bun test
102
102
  # Run specific test file
103
103
  bun test src/__tests__/user.service.test.ts
104
104
 
105
- # Run tests matching pattern
106
- bun test --grep "UserService"
105
+ # Run tests whose name matches a pattern
106
+ bun test -t "UserService"
107
107
 
108
108
  # Watch mode
109
109
  bun test --watch
@@ -410,6 +410,11 @@ describe('UserController E2E', () => {
410
410
  });
411
411
 
412
412
  expect(response.status).toBe(409);
413
+
414
+ // Error responses carry one message shape: { text, code, args }.
415
+ // There is no flat top-level messageCode - branch on normalized.code.
416
+ const body = await response.json();
417
+ expect(body.normalized.code).toBeDefined();
413
418
  });
414
419
  });
415
420
 
@@ -50,11 +50,9 @@ This prints all registered routes on startup.
50
50
 
51
51
  **Debug bindings:**
52
52
  ```typescript
53
- // In postConfigure() method
54
- async postConfigure(): Promise<void> {
55
- this.logger.info('Available bindings: %s',
56
- Array.from(this.bindings.keys())
57
- );
53
+ // In your Application class - `bindings` is protected on the container it extends
54
+ override async postConfigure(): Promise<void> {
55
+ this.logger.info('[postConfigure] Available bindings: %j', Array.from(this.bindings.keys()));
58
56
  }
59
57
  ```
60
58
 
@@ -77,16 +75,21 @@ curl -H "Authorization: Bearer YOUR_TOKEN" \
77
75
 
78
76
  **Enable detailed logging:**
79
77
  ```bash
80
- # Enable debug mode via environment variable
78
+ # `debug` is the only gated level - it is dropped unless DEBUG is set
81
79
  DEBUG=true
80
+
81
+ # File logging is OPT-IN. Without this, logs go to console/dgram only
82
+ APP_ENV_LOGGER_FOLDER_PATH=./logs
82
83
  ```
83
84
 
84
85
  **Use method-scoped logging with `.for()`:**
85
86
  ```typescript
87
+ import { ApplicationLogger, type ILogger } from '@venizia/ignis-helpers';
88
+
86
89
  class UserService {
87
- private logger = Logger.get('UserService');
90
+ private logger: ILogger = ApplicationLogger.get('UserService');
88
91
 
89
- async createUser(data: CreateUserDto) {
92
+ async createUser(data: TCreateUserRequest) {
90
93
  this.logger.for('createUser').info('Creating user: %j', data);
91
94
  // Output: [UserService-createUser] Creating user: {...}
92
95
 
@@ -102,16 +105,19 @@ class UserService {
102
105
  }
103
106
  ```
104
107
 
108
+ Annotate against `ILogger`, never a concrete provider class. Acquire a logger via `BaseHelper.logger` (inside any helper, service, controller or repository), `ApplicationLogger.get('Scope')`, or `LoggerFactory.getLogger(['A', 'B'])`.
109
+
105
110
  **Common debugging commands:**
106
111
  ```bash
107
- # View application logs
108
- tail -f logs/app.log
112
+ # View application logs - the rotating files are <APP_ENV_APPLICATION_NAME>-info-<date>.log
113
+ # and -error-<date>.log inside APP_ENV_LOGGER_FOLDER_PATH
114
+ tail -f "$APP_ENV_LOGGER_FOLDER_PATH"/*-info-*.log
109
115
 
110
- # Check TypeScript compilation errors
111
- bun run build
116
+ # Check TypeScript compilation errors (from the repo root)
117
+ make core
112
118
 
113
119
  # Validate environment variables
114
- cat .env | grep APP_ENV
120
+ grep APP_ENV .env
115
121
  ```
116
122
 
117
123
  **Useful debugging patterns:**
@@ -144,10 +150,10 @@ async getUser(c: Context) {
144
150
  **Filtering logs by request:**
145
151
  ```bash
146
152
  # Find all logs for a specific request
147
- grep "abc123" logs/app.log
153
+ grep "abc123" "$APP_ENV_LOGGER_FOLDER_PATH"/*-info-*.log
148
154
 
149
155
  # Extract request timing
150
- grep "\[abc123\]" logs/app.log | grep "Took:"
156
+ grep "\[abc123\]" "$APP_ENV_LOGGER_FOLDER_PATH"/*-info-*.log | grep "Took:"
151
157
  ```
152
158
 
153
159
  **Why this matters:**
@@ -159,12 +165,16 @@ grep "\[abc123\]" logs/app.log | grep "Took:"
159
165
 
160
166
  When Zod validation fails, IGNIS returns a structured error response. Understanding this format helps debug client-side issues.
161
167
 
162
- **Error response structure** (top-level `message`/`messageCode` come from the first issue; the fallback message is `ValidationError`):
168
+ **Error response structure** (`message`/`normalized.code` come from the first issue; the fallback message is `ValidationError`):
163
169
  ```json
164
170
  {
165
171
  "statusCode": 422,
166
172
  "message": "Invalid email address",
167
- "messageCode": "invalid_format",
173
+ "normalized": {
174
+ "text": "Invalid email address",
175
+ "code": "invalid_format",
176
+ "args": {}
177
+ },
168
178
  "requestId": "abc123",
169
179
  "details": {
170
180
  "url": "http://localhost:3000/api/users",