@venizia/ignis-docs 0.0.7-2 → 0.0.8-0

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 (161) hide show
  1. package/dist/mcp-server/common/paths.d.ts +4 -2
  2. package/dist/mcp-server/common/paths.d.ts.map +1 -1
  3. package/dist/mcp-server/common/paths.js +8 -6
  4. package/dist/mcp-server/common/paths.js.map +1 -1
  5. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
  6. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
  7. package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
  8. package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
  9. package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
  10. package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
  11. package/package.json +1 -1
  12. package/wiki/best-practices/api-usage-examples.md +9 -9
  13. package/wiki/best-practices/architectural-patterns.md +19 -3
  14. package/wiki/best-practices/architecture-decisions.md +6 -6
  15. package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
  16. package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
  17. package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
  18. package/wiki/best-practices/code-style-standards/index.md +2 -2
  19. package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
  20. package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
  21. package/wiki/best-practices/data-modeling.md +1 -1
  22. package/wiki/best-practices/deployment-strategies.md +1 -1
  23. package/wiki/best-practices/error-handling.md +2 -2
  24. package/wiki/best-practices/performance-optimization.md +3 -3
  25. package/wiki/best-practices/security-guidelines.md +2 -2
  26. package/wiki/best-practices/troubleshooting-tips.md +1 -1
  27. package/wiki/{references → extensions}/components/authentication/api.md +12 -20
  28. package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
  29. package/wiki/{references → extensions}/components/authentication/index.md +5 -8
  30. package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
  31. package/wiki/{references → extensions}/components/authorization/api.md +62 -13
  32. package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
  33. package/wiki/{references → extensions}/components/authorization/index.md +93 -6
  34. package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
  35. package/wiki/{references → extensions}/components/health-check.md +5 -4
  36. package/wiki/{references → extensions}/components/index.md +2 -0
  37. package/wiki/{references → extensions}/components/mail/index.md +1 -1
  38. package/wiki/{references → extensions}/components/request-tracker.md +1 -1
  39. package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
  40. package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
  41. package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
  42. package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
  43. package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
  44. package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
  45. package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
  46. package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
  47. package/wiki/{references → extensions}/components/swagger.md +3 -3
  48. package/wiki/{references → extensions}/components/template/index.md +4 -4
  49. package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
  50. package/wiki/{references → extensions}/components/template/single-page.md +1 -1
  51. package/wiki/{references → extensions}/components/websocket/api.md +7 -6
  52. package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
  53. package/wiki/{references → extensions}/components/websocket/index.md +17 -11
  54. package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
  55. package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
  56. package/wiki/{references → extensions}/helpers/env/index.md +9 -5
  57. package/wiki/{references → extensions}/helpers/error/index.md +2 -7
  58. package/wiki/{references → extensions}/helpers/index.md +18 -6
  59. package/wiki/{references → extensions}/helpers/kafka/admin.md +33 -16
  60. package/wiki/extensions/helpers/kafka/consumer.md +384 -0
  61. package/wiki/extensions/helpers/kafka/examples.md +361 -0
  62. package/wiki/extensions/helpers/kafka/index.md +639 -0
  63. package/wiki/{references → extensions}/helpers/kafka/producer.md +100 -96
  64. package/wiki/extensions/helpers/kafka/schema-registry.md +214 -0
  65. package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
  66. package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
  67. package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
  68. package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
  69. package/wiki/{references → extensions}/helpers/template/index.md +1 -1
  70. package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
  71. package/wiki/{references → extensions}/helpers/types/index.md +63 -16
  72. package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
  73. package/wiki/extensions/index.md +48 -0
  74. package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
  75. package/wiki/guides/core-concepts/application/index.md +95 -35
  76. package/wiki/guides/core-concepts/components-guide.md +23 -19
  77. package/wiki/guides/core-concepts/components.md +34 -10
  78. package/wiki/guides/core-concepts/dependency-injection.md +99 -34
  79. package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
  80. package/wiki/guides/core-concepts/persistent/datasources.md +27 -8
  81. package/wiki/guides/core-concepts/persistent/models.md +43 -1
  82. package/wiki/guides/core-concepts/persistent/repositories.md +75 -8
  83. package/wiki/guides/core-concepts/persistent/transactions.md +38 -8
  84. package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +30 -33
  85. package/wiki/guides/core-concepts/services.md +19 -5
  86. package/wiki/guides/get-started/5-minute-quickstart.md +6 -7
  87. package/wiki/guides/get-started/philosophy.md +1 -1
  88. package/wiki/guides/index.md +2 -2
  89. package/wiki/guides/reference/glossary.md +7 -7
  90. package/wiki/guides/reference/mcp-docs-server.md +1 -1
  91. package/wiki/guides/tutorials/building-a-crud-api.md +2 -2
  92. package/wiki/guides/tutorials/complete-installation.md +17 -14
  93. package/wiki/guides/tutorials/ecommerce-api.md +18 -18
  94. package/wiki/guides/tutorials/realtime-chat.md +8 -8
  95. package/wiki/guides/tutorials/testing.md +2 -2
  96. package/wiki/index.md +4 -3
  97. package/wiki/references/base/application.md +341 -21
  98. package/wiki/references/base/bootstrapping.md +43 -13
  99. package/wiki/references/base/components.md +259 -8
  100. package/wiki/references/base/controllers.md +556 -253
  101. package/wiki/references/base/datasources.md +159 -79
  102. package/wiki/references/base/dependency-injection.md +299 -48
  103. package/wiki/references/base/filter-system/application-usage.md +18 -2
  104. package/wiki/references/base/filter-system/array-operators.md +14 -6
  105. package/wiki/references/base/filter-system/comparison-operators.md +9 -3
  106. package/wiki/references/base/filter-system/default-filter.md +28 -3
  107. package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
  108. package/wiki/references/base/filter-system/index.md +169 -11
  109. package/wiki/references/base/filter-system/json-filtering.md +51 -18
  110. package/wiki/references/base/filter-system/list-operators.md +4 -3
  111. package/wiki/references/base/filter-system/logical-operators.md +7 -2
  112. package/wiki/references/base/filter-system/null-operators.md +50 -0
  113. package/wiki/references/base/filter-system/quick-reference.md +82 -243
  114. package/wiki/references/base/filter-system/range-operators.md +7 -1
  115. package/wiki/references/base/filter-system/tips.md +34 -7
  116. package/wiki/references/base/filter-system/use-cases.md +6 -5
  117. package/wiki/references/base/grpc-controllers.md +984 -0
  118. package/wiki/references/base/index.md +32 -24
  119. package/wiki/references/base/middleware.md +347 -0
  120. package/wiki/references/base/models.md +390 -46
  121. package/wiki/references/base/providers.md +14 -14
  122. package/wiki/references/base/repositories/advanced.md +84 -69
  123. package/wiki/references/base/repositories/index.md +447 -12
  124. package/wiki/references/base/repositories/mixins.md +103 -98
  125. package/wiki/references/base/repositories/relations.md +129 -45
  126. package/wiki/references/base/repositories/soft-deletable.md +104 -23
  127. package/wiki/references/base/services.md +94 -14
  128. package/wiki/references/index.md +12 -10
  129. package/wiki/references/quick-reference.md +98 -65
  130. package/wiki/references/utilities/crypto.md +21 -4
  131. package/wiki/references/utilities/date.md +25 -7
  132. package/wiki/references/utilities/index.md +26 -24
  133. package/wiki/references/utilities/jsx.md +54 -54
  134. package/wiki/references/utilities/module.md +8 -6
  135. package/wiki/references/utilities/parse.md +16 -9
  136. package/wiki/references/utilities/performance.md +22 -7
  137. package/wiki/references/utilities/promise.md +19 -16
  138. package/wiki/references/utilities/request.md +48 -26
  139. package/wiki/references/utilities/schema.md +69 -6
  140. package/wiki/references/utilities/statuses.md +131 -140
  141. package/wiki/references/helpers/kafka/consumer.md +0 -473
  142. package/wiki/references/helpers/kafka/examples.md +0 -234
  143. package/wiki/references/helpers/kafka/index.md +0 -482
  144. /package/wiki/{references → extensions}/components/mail/api.md +0 -0
  145. /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
  146. /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
  147. /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
  148. /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
  149. /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
  150. /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
  151. /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
  152. /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
  153. /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
  154. /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
  155. /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
  156. /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
  157. /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
  158. /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
  159. /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
  160. /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
  161. /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
@@ -15,8 +15,10 @@ A repository that overrides delete operations to set a `deletedAt` timestamp ins
15
15
 
16
16
  ### 1. Define Model with Soft Delete
17
17
 
18
+ Use the `generateTzColumnDefs` enricher with the `deleted` option enabled to add a `deletedAt` column:
19
+
18
20
  ```typescript
19
- import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';
21
+ import { pgTable, text } from 'drizzle-orm/pg-core';
20
22
  import {
21
23
  BaseEntity,
22
24
  model,
@@ -34,17 +36,19 @@ import {
34
36
  export class Category extends BaseEntity<typeof Category.schema> {
35
37
  static override schema = pgTable('Category', {
36
38
  ...generateIdColumnDefs({ id: { dataType: 'string' } }),
37
- ...generateTzColumnDefs(),
39
+ ...generateTzColumnDefs({
40
+ deleted: { enable: true, columnName: 'deleted_at', withTimezone: true },
41
+ }),
38
42
  name: text('name').notNull(),
39
- deletedAt: timestamp('deleted_at', { mode: 'date', withTimezone: true }),
40
43
  });
41
44
  }
42
45
  ```
43
46
 
44
47
  > [!IMPORTANT]
45
- > - The model **must** have a `deletedAt` column (`Date | null`).
46
- > - Set `defaultFilter: { where: { deletedAt: null } }` so soft-deleted records are excluded by default.
48
+ > - The model **must** have a `deletedAt` column (`Date | null`). The `SoftDeletableRepository` requires `TSoftDeletableTableSchema` which enforces `{ deletedAt: AnyPgColumn<{ data: Date | null }> }`.
49
+ > - Set `defaultFilter: { where: { deletedAt: null } }` in `@model` settings so soft-deleted records are excluded by default.
47
50
  > - Optionally add `deletedAt` to `hiddenProperties` to hide it from API responses.
51
+ > - Use `generateTzColumnDefs` with `deleted: { enable: true, ... }` to add the column, or define it manually with `timestamp('deleted_at', { mode: 'date', withTimezone: true })`.
48
52
 
49
53
  ### 2. Create Repository
50
54
 
@@ -60,16 +64,22 @@ export class CategoryRepository extends SoftDeletableRepository<typeof Category.
60
64
 
61
65
  ## Delete Operations
62
66
 
63
- All delete methods set `deletedAt = new Date()` instead of removing the row. They internally call the corresponding `update` method.
67
+ All delete methods set `deletedAt = new Date()` instead of removing the row. They internally call the corresponding `update` method (`updateById` or `updateAll`).
64
68
 
65
69
  ### deleteById
66
70
 
67
71
  ```typescript
68
- // Soft delete sets deletedAt timestamp
72
+ // Soft delete - sets deletedAt timestamp
69
73
  const result = await repo.deleteById({ id: '123' });
70
74
  // { count: 1, data: { id: '123', name: 'Electronics', deletedAt: '2026-03-06T...' } }
71
75
 
72
- // Hard delete — physically removes the row
76
+ // Without returning data
77
+ const result = await repo.deleteById({
78
+ id: '123',
79
+ options: { shouldReturn: false },
80
+ });
81
+
82
+ // Hard delete - physically removes the row
73
83
  const result = await repo.deleteById({
74
84
  id: '123',
75
85
  options: { shouldHardDelete: true },
@@ -95,10 +105,16 @@ const result = await repo.deleteAll({
95
105
  ### deleteBy
96
106
 
97
107
  ```typescript
98
- // Soft delete by where condition (requires non-empty where)
108
+ // Soft delete by where condition (alias for deleteAll)
99
109
  const result = await repo.deleteBy({
100
110
  where: { name: 'Obsolete' },
101
111
  });
112
+
113
+ // Hard delete by where condition
114
+ const result = await repo.deleteBy({
115
+ where: { name: 'Obsolete' },
116
+ options: { shouldHardDelete: true },
117
+ });
102
118
  ```
103
119
 
104
120
 
@@ -137,7 +153,7 @@ const result = await repo.restoreAll({
137
153
  ### restoreBy
138
154
 
139
155
  ```typescript
140
- // Alias for restoreAll with required where
156
+ // Alias for restoreAll
141
157
  const result = await repo.restoreBy({
142
158
  where: { status: 'archived' },
143
159
  });
@@ -148,7 +164,7 @@ const result = await repo.restoreBy({
148
164
 
149
165
  ### findById with isStrict
150
166
 
151
- `SoftDeletableRepository` overrides `findById` to support a `isStrict` option that throws a `404 Not Found` error when the record doesn't exist:
167
+ `SoftDeletableRepository` overrides `findById` to support an `isStrict` option that throws a `404 Not Found` error when the record doesn't exist:
152
168
 
153
169
  ```typescript
154
170
  // Returns null if not found (default)
@@ -159,8 +175,11 @@ const category = await repo.findById({
159
175
  id: '123',
160
176
  options: { isStrict: true },
161
177
  });
178
+ // Throws: [CategoryRepository][findById] Entity with id 123 not found (HTTP 404)
162
179
  ```
163
180
 
181
+ All other read operations (`find`, `findOne`, `count`, `existsWith`) work as normal. The default filter (`{ deletedAt: null }`) automatically excludes soft-deleted records. Use `shouldSkipDefaultFilter: true` to include them.
182
+
164
183
 
165
184
  ## Options Reference
166
185
 
@@ -170,30 +189,36 @@ const category = await repo.findById({
170
189
  |--------|------|---------|-------------|
171
190
  | `shouldHardDelete` | `boolean` | `false` | Bypass soft delete and physically remove the row |
172
191
  | `shouldReturn` | `boolean` | `true` | Return the updated/deleted record |
173
- | `force` | `boolean` | `false` | Allow empty `where` condition (deleteAll/deleteBy) |
174
- | `transaction` | `ITransaction` | | Transaction context |
192
+ | `force` | `boolean` | `false` | Allow empty `where` condition (`deleteAll`/`deleteBy`) |
193
+ | `transaction` | `ITransaction` | - | Transaction context |
194
+ | `log` | `{ use: boolean; level?: TLogLevel }` | - | Enable operation logging |
195
+ | `shouldSkipDefaultFilter` | `boolean` | `false` | Bypass the default filter |
175
196
 
176
197
  ### Restore Options
177
198
 
178
199
  | Option | Type | Default | Description |
179
200
  |--------|------|---------|-------------|
180
201
  | `shouldReturn` | `boolean` | `true` | Return the restored record |
181
- | `force` | `boolean` | `false` | Allow empty `where` condition (restoreAll) |
182
- | `transaction` | `ITransaction` | | Transaction context |
202
+ | `force` | `boolean` | `false` | Allow empty `where` condition (`restoreAll`) |
203
+ | `transaction` | `ITransaction` | - | Transaction context |
204
+
205
+ > [!NOTE]
206
+ > Restore operations automatically set `shouldSkipDefaultFilter: true` internally so they can find soft-deleted records that the default filter would normally hide. You do not need to set this yourself.
183
207
 
184
208
 
185
209
  ## How It Works
186
210
 
187
- | Operation | Behavior |
188
- |-----------|----------|
189
- | `deleteById` | `UPDATE SET deletedAt = NOW() WHERE id = ?` |
190
- | `deleteAll` | `UPDATE SET deletedAt = NOW() WHERE ...` |
191
- | `restoreById` | `UPDATE SET deletedAt = NULL WHERE id = ?` (skips default filter) |
192
- | `restoreAll` | `UPDATE SET deletedAt = NULL WHERE ...` (skips default filter) |
193
- | `find` / `findOne` | Default filter automatically excludes `deletedAt IS NOT NULL` |
211
+ | Operation | SQL Behavior |
212
+ |-----------|-------------|
213
+ | `deleteById` | `UPDATE SET deletedAt = NOW() WHERE id = ?` (via `updateById`) |
214
+ | `deleteAll` / `deleteBy` | `UPDATE SET deletedAt = NOW() WHERE ...` (via `updateAll`) |
215
+ | `restoreById` | `UPDATE SET deletedAt = NULL WHERE id = ?` (via `updateById` with `shouldSkipDefaultFilter: true`) |
216
+ | `restoreAll` / `restoreBy` | `UPDATE SET deletedAt = NULL WHERE ...` (via `updateAll` with `shouldSkipDefaultFilter: true`) |
217
+ | `find` / `findOne` / `count` | Default filter automatically adds `WHERE deletedAt IS NULL` |
218
+ | `deleteById({ shouldHardDelete: true })` | `DELETE FROM ... WHERE id = ?` (delegates to parent `PersistableRepository`) |
194
219
 
195
220
  > [!TIP]
196
- > Restore operations automatically set `shouldSkipDefaultFilter: true` so they can find soft-deleted records that would normally be hidden by the default filter.
221
+ > The `shouldHardDelete` option bypasses soft delete entirely and delegates to the parent `DefaultCRUDRepository`'s delete implementation, which performs a real SQL `DELETE`.
197
222
 
198
223
 
199
224
  ## With Transactions
@@ -211,3 +236,59 @@ try {
211
236
  await tx.rollback();
212
237
  }
213
238
  ```
239
+
240
+
241
+ ## Type Constraint
242
+
243
+ `SoftDeletableRepository` enforces that the schema includes a `deletedAt` column at the type level:
244
+
245
+ ```typescript
246
+ export type TSoftDeletableTableSchema = TTableSchemaWithId & {
247
+ deletedAt: AnyPgColumn<{ data: Date | null }>;
248
+ };
249
+
250
+ export class SoftDeletableRepository<
251
+ EntitySchema extends TSoftDeletableTableSchema = TSoftDeletableTableSchema,
252
+ // ...
253
+ > extends DefaultCRUDRepository<EntitySchema, ...> { }
254
+ ```
255
+
256
+ If your schema does not have a `deletedAt` column, you will get a TypeScript compilation error when extending `SoftDeletableRepository`.
257
+
258
+
259
+ ## Class Hierarchy
260
+
261
+ ```
262
+ AbstractRepository
263
+ -> ReadableRepository
264
+ -> PersistableRepository
265
+ -> DefaultCRUDRepository
266
+ -> SoftDeletableRepository <-- you are here
267
+ ```
268
+
269
+
270
+ ## Quick Reference
271
+
272
+ | Want to... | Code |
273
+ |------------|------|
274
+ | Soft delete by ID | `repo.deleteById({ id })` |
275
+ | Hard delete by ID | `repo.deleteById({ id, options: { shouldHardDelete: true } })` |
276
+ | Soft delete by condition | `repo.deleteAll({ where, options: { force: true } })` |
277
+ | Restore by ID | `repo.restoreById({ id })` |
278
+ | Restore by condition | `repo.restoreAll({ where })` |
279
+ | Find including deleted | `repo.find({ filter, options: { shouldSkipDefaultFilter: true } })` |
280
+ | Strict findById (404) | `repo.findById({ id, options: { isStrict: true } })` |
281
+
282
+
283
+ ## Next Steps
284
+
285
+ - [Advanced Features](./advanced.md) - Transactions, hidden properties
286
+ - [Repository Mixins](./mixins.md) - Default filter and fields visibility
287
+ - [Repository Overview](./index.md) - Repository basics
288
+
289
+ ## See Also
290
+
291
+ - **Related Concepts:**
292
+ - [Repositories Overview](./index) - Core repository operations
293
+ - [Default Filter](../filter-system/default-filter) - Automatic filtering
294
+ - [Models](/guides/core-concepts/persistent/models) - Entity definitions with enrichers
@@ -17,34 +17,69 @@ Technical reference for `BaseService` - the foundation for business logic layers
17
17
  | **Extends `BaseHelper`** | Auto-configured scoped logger (`this.logger`) |
18
18
  | **DI Integration** | Fits into framework's dependency injection system |
19
19
  | **Business Logic Layer** | Bridge between Controllers and Repositories |
20
+ | **No built-in CRUD** | Services are for business logic, not data access — that's what Repositories are for |
20
21
 
21
22
  ## `BaseService` Class
22
23
 
23
- Abstract class that all application services should extend.
24
+ Abstract class that all application services should extend. It implements the `IService` interface (currently a marker interface with no required methods).
25
+
26
+ ### Class Definition
27
+
28
+ ```typescript
29
+ import { BaseHelper } from '@venizia/ignis-helpers';
30
+ import { IService } from './types';
31
+
32
+ export abstract class BaseService extends BaseHelper implements IService {
33
+ constructor(opts: { scope: string }) {
34
+ super({ scope: opts.scope });
35
+ }
36
+ }
37
+ ```
24
38
 
25
39
  ### Key Features
26
40
 
27
41
  | Feature | Description |
28
42
  | :--- | :--- |
29
43
  | **Standardization** | Common base for all services, fits framework architecture |
30
- | **Logging** | Extends `BaseHelper` - auto-configured logger at `this.logger` (scope = class name) |
44
+ | **Logging** | Extends `BaseHelper` from `@venizia/ignis-helpers` auto-configured logger at `this.logger` (scope = class name) |
31
45
  | **Clarity** | Signals the class contains business logic |
32
46
 
33
- ### Class Definition
47
+ ### Constructor
34
48
 
35
- The implementation is straightforward:
49
+ The constructor requires an options object with a `scope` string, which is typically set to the class name:
36
50
 
37
51
  ```typescript
38
- import { BaseHelper } from '../helpers';
39
- import { IService } from './types';
40
-
41
- export abstract class BaseService extends BaseHelper implements IService {
42
- constructor(opts: { scope: string }) {
43
- super({ scope: opts.scope });
52
+ class UserService extends BaseService {
53
+ constructor() {
54
+ super({ scope: UserService.name });
44
55
  }
45
56
  }
46
57
  ```
47
58
 
59
+ ## `IService` Interface
60
+
61
+ The `IService` interface is a marker interface with no required methods. It exists to provide a type-level contract for services.
62
+
63
+ ```typescript
64
+ export interface IService {}
65
+ ```
66
+
67
+ ## No Built-in CRUD Service
68
+
69
+ Ignis intentionally does not provide a `BaseCrudService`. CRUD operations belong in the Repository layer (`DefaultCRUDRepository`). Services are for business logic that orchestrates one or more repositories, performs validation, handles transactions, or coordinates cross-cutting concerns.
70
+
71
+ ## Registration
72
+
73
+ Services are registered with the DI container using the `app.service()` method or via the boot system's auto-discovery:
74
+
75
+ ```typescript
76
+ // Manual registration (in preConfigure or registerComponents)
77
+ app.service(UserService); // Binds as 'services.UserService'
78
+
79
+ // Or via boot system auto-discovery:
80
+ // Place file at src/services/user.service.ts → auto-discovered and bound
81
+ ```
82
+
48
83
  ## How Services Fit into the Architecture
49
84
 
50
85
  Services are the core of your application's logic. They act as a bridge between the presentation layer (Controllers) and the data access layer (Repositories).
@@ -64,12 +99,12 @@ Services are the core of your application's logic. They act as a bridge between
64
99
  ### Example
65
100
 
66
101
  ```typescript
67
- import { BaseService, inject } from '@venizia/ignis';
102
+ import { BaseService, inject, injectable } from '@venizia/ignis';
68
103
  import { getError } from '@venizia/ignis-helpers';
69
104
  import { UserRepository } from '../repositories/user.repository';
70
105
  import { TUser } from '../models/entities';
71
106
 
72
- // 1. Service is decorated with `@injectable` (or registered via `app.service()`)
107
+ // 1. Service is decorated with @injectable (or registered via app.service())
73
108
  @injectable()
74
109
  export class UserService extends BaseService {
75
110
  // 2. Dependencies (like UserRepository) are injected
@@ -94,15 +129,60 @@ export class UserService extends BaseService {
94
129
  // 5. Returns transformed data
95
130
  return {
96
131
  id: user.id,
97
- name: user.name, // Assuming a 'name' field exists
132
+ name: user.name,
98
133
  email: user.email,
99
134
  };
100
135
  }
101
136
  }
102
137
  ```
103
138
 
104
- By adhering to this pattern, you keep your code organized, testable, and maintainable. You can easily test `UserService` by providing a mock `UserRepository` without needing a real database connection.
139
+ ### Transaction Orchestration
140
+
141
+ A common service pattern is orchestrating transactions across multiple repositories:
142
+
143
+ ```typescript
144
+ @injectable()
145
+ export class OrderService extends BaseService {
146
+ constructor(
147
+ @inject({ key: 'repositories.OrderRepository' })
148
+ private orderRepo: OrderRepository,
149
+
150
+ @inject({ key: 'repositories.InventoryRepository' })
151
+ private inventoryRepo: InventoryRepository,
152
+
153
+ @inject({ key: 'datasources.PostgresDataSource' })
154
+ private dataSource: PostgresDataSource,
155
+ ) {
156
+ super({ scope: OrderService.name });
157
+ }
105
158
 
159
+ async placeOrder(opts: { userId: string; items: OrderItem[] }) {
160
+ const transaction = await this.dataSource.beginTransaction();
161
+ try {
162
+ const order = await this.orderRepo.create({
163
+ data: { userId: opts.userId, items: opts.items },
164
+ options: { transaction },
165
+ });
166
+
167
+ for (const item of opts.items) {
168
+ await this.inventoryRepo.updateById({
169
+ id: item.productId,
170
+ data: { quantity: item.quantity },
171
+ options: { transaction },
172
+ });
173
+ }
174
+
175
+ await transaction.commit();
176
+ return order;
177
+ } catch (error) {
178
+ await transaction.rollback();
179
+ throw error;
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
185
+ By adhering to this pattern, you keep your code organized, testable, and maintainable. You can easily test `UserService` by providing a mock `UserRepository` without needing a real database connection.
106
186
 
107
187
  ## See Also
108
188
 
@@ -9,12 +9,12 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
9
9
  <p>Application, Controller, Service, Repository, Model</p>
10
10
  </a>
11
11
 
12
- <a href="./components/" class="guide-card">
12
+ <a href="/ignis/extensions/components/" class="guide-card">
13
13
  <h3>Components</h3>
14
14
  <p>Auth, Mail, Socket.IO, Swagger, Health Check</p>
15
15
  </a>
16
16
 
17
- <a href="./helpers/" class="guide-card">
17
+ <a href="/ignis/extensions/helpers/" class="guide-card">
18
18
  <h3>Helpers</h3>
19
19
  <p>Logger, Redis, Queue, Storage, Cron, Crypto</p>
20
20
  </a>
@@ -29,7 +29,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
29
29
  <p>Environment variables and settings</p>
30
30
  </a>
31
31
 
32
- <a href="./src-details/" class="guide-card">
32
+ <a href="/ignis/extensions/src-details/" class="guide-card">
33
33
  <h3>Framework Internals</h3>
34
34
  <p>Package structure and architecture</p>
35
35
  </a>
@@ -63,7 +63,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
63
63
  <span class="stage-num">3</span>
64
64
  <h4>Adding Features</h4>
65
65
  </div>
66
- <p><a href="./components/authentication">Auth</a> → <a href="./components/socket-io">Real-time</a> → <a href="./components/mail">Email</a> → <a href="./components/swagger">API Docs</a></p>
66
+ <p><a href="/ignis/extensions/components/authentication/">Auth</a> → <a href="/ignis/extensions/components/socket-io/">Real-time</a> → <a href="/ignis/extensions/components/mail/">Email</a> → <a href="/ignis/extensions/components/swagger">API Docs</a></p>
67
67
  <span class="stage-desc">Pre-built components for common features</span>
68
68
  </div>
69
69
 
@@ -72,7 +72,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
72
72
  <span class="stage-num">4</span>
73
73
  <h4>Infrastructure</h4>
74
74
  </div>
75
- <p><a href="./helpers/logger">Logging</a> → <a href="./helpers/redis">Caching</a> → <a href="./helpers/queue">Queues</a> → <a href="./helpers/cron">Scheduling</a></p>
75
+ <p><a href="/ignis/extensions/helpers/logger/">Logging</a> → <a href="/ignis/extensions/helpers/redis/">Caching</a> → <a href="/ignis/extensions/helpers/queue/">Queues</a> → <a href="/ignis/extensions/helpers/cron/">Scheduling</a></p>
76
76
  <span class="stage-desc">Background jobs, caching, and observability</span>
77
77
  </div>
78
78
 
@@ -90,7 +90,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
90
90
  <span class="stage-num">6</span>
91
91
  <h4>Production Ready</h4>
92
92
  </div>
93
- <p><a href="./base/middlewares">Error Handling</a> → <a href="./components/health-check">Health Checks</a> → <a href="./configuration/environment-variables">Configuration</a> → <a href="./base/bootstrapping">Auto-Discovery</a></p>
93
+ <p><a href="./base/middlewares">Error Handling</a> → <a href="/ignis/extensions/components/health-check">Health Checks</a> → <a href="./configuration/environment-variables">Configuration</a> → <a href="./base/bootstrapping">Auto-Discovery</a></p>
94
94
  <span class="stage-desc">Production deployment, monitoring, and reliability</span>
95
95
  </div>
96
96
 
@@ -99,7 +99,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
99
99
  <span class="stage-num">7</span>
100
100
  <h4>Testing & Quality</h4>
101
101
  </div>
102
- <p><a href="./helpers/testing">Unit Testing</a> → <a href="./base/repositories/advanced">Mocking & Stubs</a> → <a href="./quick-reference">Best Practices</a></p>
102
+ <p><a href="/ignis/extensions/helpers/testing/">Unit Testing</a> → <a href="./base/repositories/advanced">Mocking & Stubs</a> → <a href="./quick-reference">Best Practices</a></p>
103
103
  <span class="stage-desc">Testing strategies, quality assurance, and code review</span>
104
104
  </div>
105
105
 
@@ -113,7 +113,7 @@ Complete reference documentation for the Ignis framework. Find detailed API docs
113
113
  **Define a Controller:**
114
114
  ```typescript
115
115
  @controller({ path: '/users' })
116
- class UserController extends BaseController {
116
+ class UserController extends BaseRestController {
117
117
  @get({ configs: { path: '/:id' } })
118
118
  getUser(c: Context) {
119
119
  return c.json({ id: c.req.param('id') });
@@ -143,11 +143,13 @@ CronHelper.schedule('0 * * * *', async () => {
143
143
  // Core framework
144
144
  import {
145
145
  BaseApplication,
146
- BaseController,
146
+ BaseRestController,
147
+ BaseGrpcController,
147
148
  BaseService,
148
- BaseRepository,
149
+ DefaultCRUDRepository,
149
150
  controller,
150
151
  get, post, put, del,
152
+ rpc, unary, serverStream,
151
153
  inject,
152
154
  } from '@venizia/ignis';
153
155