@venizia/ignis-docs 0.0.7 → 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 (158) 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 +13 -1
  60. package/wiki/{references → extensions}/helpers/kafka/consumer.md +28 -28
  61. package/wiki/{references → extensions}/helpers/kafka/examples.md +19 -19
  62. package/wiki/{references → extensions}/helpers/kafka/index.md +51 -48
  63. package/wiki/{references → extensions}/helpers/kafka/producer.md +18 -18
  64. package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
  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 → extensions}/components/mail/api.md +0 -0
  142. /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
  143. /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
  144. /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
  145. /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
  146. /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
  147. /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
  148. /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
  149. /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
  150. /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
  151. /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
  152. /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
  153. /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
  154. /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
  155. /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
  156. /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
  157. /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
  158. /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
@@ -71,13 +71,26 @@ export class UserRepository extends ReadableRepository<typeof User.schema> {
71
71
  > - After the first argument, you can inject any additional dependencies you need
72
72
  > - When `@inject` is at param index 0, auto-injection is skipped
73
73
 
74
- ## Repository Types
74
+ ## Repository Hierarchy
75
+
76
+ ```
77
+ AbstractRepository (base + mixins: FieldsVisibilityMixin + DefaultFilterMixin)
78
+
79
+ ReadableRepository (read-only: find, findOne, findById, count, existsWith)
80
+
81
+ PersistableRepository (+ create, updateById, updateAll)
82
+
83
+ DefaultCRUDRepository (+ deleteById, deleteAll) — recommended default
84
+
85
+ SoftDeletableRepository (overrides delete to set deletedAt timestamp)
86
+ ```
75
87
 
76
88
  | Type | Description |
77
89
  |------|-------------|
78
- | `DefaultCRUDRepository` | Full read/write operations |
79
- | `ReadableRepository` | Read-only operations |
80
- | `PersistableRepository` | Write operations only |
90
+ | `ReadableRepository` | Read-only operations. Write operations throw errors. |
91
+ | `PersistableRepository` | Read + write operations (create, update). Extends ReadableRepository. |
92
+ | `DefaultCRUDRepository` | Full CRUD including delete. Extends PersistableRepository. **Recommended for most use cases.** |
93
+ | `SoftDeletableRepository` | Extends DefaultCRUDRepository. Overrides delete to set `deletedAt` timestamp instead of physically removing records. |
81
94
 
82
95
  ## Querying Data
83
96
 
@@ -134,6 +147,32 @@ await repo.updateById({
134
147
  await repo.deleteById({ id: 'uuid-here' });
135
148
  ```
136
149
 
150
+ ## Extra Options
151
+
152
+ All repository operations accept an `options` parameter with these fields:
153
+
154
+ | Option | Type | Description |
155
+ | :--- | :--- | :--- |
156
+ | `transaction` | `ITransaction` | Transaction context for atomic operations |
157
+ | `shouldReturn` | `boolean` | Whether to return created/updated data (default: `true`) |
158
+ | `shouldQueryRange` | `boolean` | Return `{ data, range: { total, skip, limit } }` for pagination |
159
+ | `shouldSkipDefaultFilter` | `boolean` | Bypass the model's default filter (e.g., soft delete) |
160
+
161
+ ```typescript
162
+ // Create without returning data (faster for bulk inserts)
163
+ await repo.create({
164
+ data: bulkData,
165
+ options: { shouldReturn: false }
166
+ });
167
+
168
+ // Query with pagination range
169
+ const result = await repo.find({
170
+ filter: { limit: 20, skip: 0 },
171
+ options: { shouldQueryRange: true }
172
+ });
173
+ // result = { data: [...], range: { total: 150, skip: 0, limit: 20 } }
174
+ ```
175
+
137
176
  ## Querying with Relations
138
177
 
139
178
  Use `include` to fetch related data. The relation name must match what you defined in `static relations`:
@@ -162,6 +201,34 @@ export class Application extends BaseApplication {
162
201
  }
163
202
  ```
164
203
 
204
+ ## SoftDeletableRepository
205
+
206
+ For soft-delete patterns, use `SoftDeletableRepository` which overrides delete operations to set a `deletedAt` timestamp instead of physically removing records:
207
+
208
+ ```typescript
209
+ import { SoftDeletableRepository, repository, model, BaseEntity } from '@venizia/ignis';
210
+ import { pgTable, timestamp } from 'drizzle-orm/pg-core';
211
+
212
+ @model({
213
+ type: 'entity',
214
+ settings: {
215
+ hiddenProperties: ['deletedAt'],
216
+ defaultFilter: { where: { deletedAt: null } },
217
+ },
218
+ })
219
+ export class Category extends BaseEntity<typeof Category.schema> {
220
+ static override schema = pgTable('Category', {
221
+ ...generateIdColumnDefs({ id: { dataType: 'string' } }),
222
+ ...generateTzColumnDefs(),
223
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
224
+ name: text('name').notNull(),
225
+ });
226
+ }
227
+
228
+ @repository({ dataSource: PostgresDataSource, model: Category })
229
+ export class CategoryRepository extends SoftDeletableRepository<typeof Category.schema> {}
230
+ ```
231
+
165
232
  ## Repository Template
166
233
 
167
234
  ```typescript
@@ -177,7 +244,7 @@ export class MyModelRepository extends DefaultCRUDRepository<typeof MyModel.sche
177
244
 
178
245
  ### Performance: Core API Optimization
179
246
 
180
- Ignis automatically optimizes "flat" queries (no relations, no field selection) by using Drizzle's Core API. This provides **~15-20% faster** queries for simple reads.
247
+ Ignis automatically optimizes "flat" queries (no relations, no field selection) by using Drizzle's Core API. This provides **~15-20% faster** queries for simple reads. The `canUseCoreAPI()` method on `ReadableRepository` determines when this optimization applies.
181
248
 
182
249
  ### Modular Persistence with Components
183
250
 
@@ -186,9 +253,9 @@ Bundle related persistence resources into Components for better organization:
186
253
  ```typescript
187
254
  export class UserManagementComponent extends BaseComponent {
188
255
  override binding() {
189
- this.application.dataSource(PostgresDataSource);
190
- this.application.repository(UserRepository);
191
- this.application.repository(ProfileRepository);
256
+ this._application.dataSource(PostgresDataSource);
257
+ this._application.repository(UserRepository);
258
+ this._application.repository(ProfileRepository);
192
259
  }
193
260
  }
194
261
  ```
@@ -4,10 +4,10 @@ Ignis supports explicit transaction objects that can be passed across multiple s
4
4
 
5
5
  ## Using Transactions
6
6
 
7
- To use transactions, start one from a repository or datasource, and then pass it to subsequent operations via the `options` parameter.
7
+ To use transactions, start one from a datasource (via the repository's `beginTransaction` method), and then pass it to subsequent operations via the `options` parameter.
8
8
 
9
9
  ```typescript
10
- // 1. Start a transaction
10
+ // 1. Start a transaction from the datasource (accessed through a repository)
11
11
  const tx = await userRepo.beginTransaction({
12
12
  isolationLevel: 'SERIALIZABLE' // Optional, defaults to 'READ COMMITTED'
13
13
  });
@@ -38,6 +38,20 @@ try {
38
38
  }
39
39
  ```
40
40
 
41
+ ## Transaction Object
42
+
43
+ The transaction object returned by `beginTransaction()` has the following properties:
44
+
45
+ | Property/Method | Type | Description |
46
+ | :--- | :--- | :--- |
47
+ | `connector` | `TNodePostgresConnector` | A Drizzle connector bound to the transaction's database client |
48
+ | `isolationLevel` | `TIsolationLevel` | The isolation level of this transaction |
49
+ | `isActive` | `boolean` | Whether the transaction is still active (not yet committed/rolled back) |
50
+ | `commit()` | `Promise<void>` | Commit the transaction and release the connection |
51
+ | `rollback()` | `Promise<void>` | Rollback the transaction and release the connection |
52
+
53
+ Calling `commit()` or `rollback()` on an already-ended transaction throws an error.
54
+
41
55
  ## Isolation Levels
42
56
 
43
57
  Ignis supports standard PostgreSQL isolation levels:
@@ -48,10 +62,12 @@ Ignis supports standard PostgreSQL isolation levels:
48
62
  | `REPEATABLE READ` | Queries see a snapshot as of the start of the transaction. | Reports, consistent reads across multiple queries. |
49
63
  | `SERIALIZABLE` | Strictest level. Emulates serial execution. | Financial transactions, critical data integrity. |
50
64
 
65
+ Note: `READ UNCOMMITTED` is technically accepted but behaves as `READ COMMITTED` in PostgreSQL.
66
+
51
67
  ## Best Practices
52
68
 
53
- 1. **Always use `try...catch...finally`**: Ensure `rollback()` is called on error to release the connection.
54
- 2. **Keep it short**: Long-running transactions hold database locks and connections.
69
+ 1. **Always use `try...catch`**: Ensure `rollback()` is called on error to release the connection back to the pool.
70
+ 2. **Keep it short**: Long-running transactions hold database connections from the pool and can cause connection exhaustion.
55
71
  3. **Pass explicit options**: When calling other services inside a transaction, ensure they accept and use the `transaction` option.
56
72
 
57
73
  ```typescript
@@ -109,19 +125,19 @@ export class OrderService extends BaseService {
109
125
 
110
126
  ```typescript
111
127
  @controller({ path: '/orders' })
112
- export class OrderController extends BaseController {
128
+ export class OrderController extends BaseRestController {
113
129
  constructor(
114
130
  @inject({ key: 'repositories.OrderRepository' })
115
131
  private _orderRepository: OrderRepository,
116
132
  @inject({ key: 'services.OrderService' })
117
133
  private _orderService: OrderService,
118
134
  ) {
119
- super({ scope: OrderController.name, path: '/orders' });
135
+ super({ scope: OrderController.name });
120
136
  }
121
137
 
122
138
  @post({ configs: OrderRoutes.CREATE })
123
139
  async createOrder(c: TRouteContext) {
124
- const body = c.req.valid<{ order: any; items: any[] }>('json'); // Use explicit types for better safety
140
+ const body = c.req.valid<{ order: any; items: any[] }>('json');
125
141
 
126
142
  const tx = await this._orderRepository.beginTransaction({
127
143
  isolationLevel: 'SERIALIZABLE',
@@ -144,6 +160,20 @@ export class OrderController extends BaseController {
144
160
  }
145
161
  ```
146
162
 
163
+ ## How Transactions Work Internally
164
+
165
+ When you pass a `transaction` option to a repository method, the repository uses the transaction's `connector` (a Drizzle instance bound to the transaction's `PoolClient`) instead of the default datasource connector. This ensures all operations within the transaction use the same database connection and see a consistent view of the data.
166
+
167
+ ```typescript
168
+ // Inside AbstractRepository (simplified)
169
+ protected resolveConnector(opts?: { transaction?: ITransaction }) {
170
+ if (opts?.transaction) {
171
+ return opts.transaction.connector;
172
+ }
173
+ return this.dataSource.connector;
174
+ }
175
+ ```
176
+
147
177
  > **Deep Dive:** See [Repository Reference](../../../references/base/repositories/) for more transaction options and patterns.
148
178
 
149
179
  ## See Also
@@ -151,7 +181,7 @@ export class OrderController extends BaseController {
151
181
  - **Related Concepts:**
152
182
  - [Repositories](/guides/core-concepts/persistent/repositories) - Provide transaction API
153
183
  - [Services](/guides/core-concepts/services) - Orchestrate transactional operations
154
- - [Controllers](/guides/core-concepts/controllers) - Initiate transactions from HTTP handlers
184
+ - [Controllers](/guides/core-concepts/rest-controllers) - Initiate transactions from HTTP handlers
155
185
  - [DataSources](/guides/core-concepts/persistent/datasources) - Database connections
156
186
 
157
187
  - **References:**
@@ -1,23 +1,22 @@
1
- # Controllers
1
+ # REST Controllers
2
2
 
3
- Controllers handle HTTP requests and return responses - they're your API endpoints.
3
+ REST controllers handle incoming HTTP requests and return JSON responses -- they are your API endpoints. This is the default transport in Ignis and covers the majority of use cases.
4
4
 
5
- > **Deep Dive:** See [Controllers Reference](../../references/base/controllers.md) for advanced patterns.
5
+ > **Deep Dive:** See [REST Controllers Reference](../../references/base/controllers.md) for the complete API.
6
6
 
7
- ## Creating a Controller
7
+ ## Creating a REST Controller
8
8
 
9
- Extend `BaseController` and use decorators to define routes:
9
+ Extend `BaseRestController` and use decorators to define routes:
10
10
 
11
11
  ```typescript
12
- import { BaseController, controller, get, jsonResponse, z } from '@venizia/ignis';
12
+ import { BaseRestController, controller, get, jsonResponse, z, TRouteContext } from '@venizia/ignis';
13
13
  import { HTTP } from '@venizia/ignis-helpers';
14
- import { Context } from 'hono';
15
14
 
16
15
  @controller({ path: '/users' })
17
- export class UserController extends BaseController {
16
+ export class UserController extends BaseRestController {
18
17
  constructor() {
19
- // It's good practice to pass a scope for logging
20
- super({ scope: UserController.name, path: '/users' });
18
+ // scope is used for logging; path can be omitted if @controller provides it
19
+ super({ scope: UserController.name });
21
20
  }
22
21
 
23
22
  @get({
@@ -29,12 +28,13 @@ export class UserController extends BaseController {
29
28
  }),
30
29
  },
31
30
  })
32
- getAllUsers(c: Context) {
31
+ getAllUsers(c: TRouteContext) {
33
32
  return c.json([{ id: '1', name: 'John Doe' }], HTTP.ResultCodes.RS_2.Ok);
34
33
  }
35
34
  }
36
35
  ```
37
- Notice that the `binding()` method is no longer needed when using decorators.
36
+
37
+ Notice that the `binding()` method is no longer needed when using decorators. The path is resolved from the `@controller` decorator metadata first, then falls back to the constructor `path` option.
38
38
 
39
39
  ## Controller Lifecycle
40
40
 
@@ -42,8 +42,8 @@ Controllers have a simple and predictable lifecycle managed by the application.
42
42
 
43
43
  | Stage | Method | Description |
44
44
  | :--- | :--- | :--- |
45
- | **1. Instantiation** | `constructor(opts)` | The controller is created by the DI container. Dependencies are injected, and you call `super()` to initialize the internal Hono router. |
46
- | **2. Configuration**| `registerControllers` phase | The application automatically discovers and registers all routes defined with decorators (`@get`, `@post`, etc.) on your controller methods. If you have routes defined manually inside `binding()`, that method is also called during this phase. **Note:** If you exclusively use decorators for routing, the `binding()` method can be omitted from your controller. |
45
+ | **1. Instantiation** | `constructor(opts)` | The controller is created by the DI container. Dependencies are injected, and `super()` initializes the internal `OpenAPIHono` router. The `path` is resolved from `@controller` decorator metadata, falling back to the constructor option. |
46
+ | **2. Configuration**| `configure()` | The application calls `configure()` which invokes `binding()` (for manual routes) and `registerRoutesFromRegistry()` (for decorator routes). This method is **idempotent** -- calling it multiple times has no effect after the first call. |
47
47
 
48
48
  ## Defining Routes with Decorators (Recommended)
49
49
 
@@ -71,14 +71,13 @@ The `opts` object contains a `configs` property that defines the route's path, r
71
71
  For optimal organization and type safety, define your route configurations in a constant with `as const`. This allows TypeScript to precisely infer the types for your request data and expected responses within your handler methods.
72
72
 
73
73
  ```typescript
74
- import { BaseController, controller, get, post, jsonContent, jsonResponse, TRouteContext } from '@venizia/ignis';
74
+ import { BaseRestController, controller, get, post, jsonContent, jsonResponse, TRouteContext } from '@venizia/ignis';
75
75
  import { HTTP } from '@venizia/ignis-helpers';
76
76
  import { z } from '@hono/zod-openapi';
77
77
 
78
78
  // Define route configs as const for type inference
79
79
  const TestRoutes = {
80
80
  GET_DATA: {
81
- method: HTTP.Methods.GET,
82
81
  path: '/',
83
82
  responses: jsonResponse({
84
83
  description: 'A simple message',
@@ -86,7 +85,6 @@ const TestRoutes = {
86
85
  }),
87
86
  },
88
87
  CREATE_ITEM: {
89
- method: HTTP.Methods.POST,
90
88
  path: '/',
91
89
  request: {
92
90
  body: jsonContent({
@@ -102,9 +100,9 @@ const TestRoutes = {
102
100
  } as const; // Crucial for strict type inference!
103
101
 
104
102
  @controller({ path: '/my-items' })
105
- export class MyItemsController extends BaseController {
103
+ export class MyItemsController extends BaseRestController {
106
104
  constructor() {
107
- super({ scope: MyItemsController.name, path: '/my-items' });
105
+ super({ scope: MyItemsController.name });
108
106
  }
109
107
 
110
108
  @get({ configs: TestRoutes.GET_DATA })
@@ -171,7 +169,7 @@ import { HTTP } from '@venizia/ignis-helpers';
171
169
  const GetUsersRoute = {
172
170
  path: '/',
173
171
  method: 'get',
174
- authStrategies: [Authentication.STRATEGY_JWT],
172
+ authenticate: { strategies: [Authentication.STRATEGY_JWT] },
175
173
  responses: jsonResponse({
176
174
  description: 'List of all users',
177
175
  schema: z.array(z.object({ id: z.number(), name: z.string() })),
@@ -197,7 +195,7 @@ import { HTTP } from '@venizia/ignis-helpers';
197
195
  // ... inside the binding() method
198
196
 
199
197
  const GetUserByIdRoute = {
200
- path: '/:id',
198
+ path: '/{id}',
201
199
  method: 'get',
202
200
  responses: jsonResponse({
203
201
  description: 'A single user',
@@ -264,12 +262,12 @@ The `ControllerFactory.defineCrudController` method automatically sets up the fo
264
262
  | :--- | :--- | :--- | :--- |
265
263
  | `count` | `GET` | `/count` | Get the number of records matching a filter. |
266
264
  | `find` | `GET` | `/` | Retrieve all records matching a filter. |
267
- | `findById` | `GET` | `/:id` | Retrieve a single record by its ID. |
265
+ | `findById` | `GET` | `/{id}` | Retrieve a single record by its ID. |
268
266
  | `findOne` | `GET` | `/find-one` | Retrieve a single record matching a filter. |
269
267
  | `create` | `POST` | `/` | Create a new record. |
270
- | `updateById` | `PATCH` | `/:id` | Update a single record by its ID. |
268
+ | `updateById` | `PATCH` | `/{id}` | Update a single record by its ID. |
271
269
  | `updateBy` | `PATCH` | `/` | Update multiple records matching a `where` filter. |
272
- | `deleteById` | `DELETE` | `/:id` | Delete a single record by its ID. |
270
+ | `deleteById` | `DELETE` | `/{id}` | Delete a single record by its ID. |
273
271
  | `deleteBy` | `DELETE` | `/` | Delete multiple records matching a `where` filter. |
274
272
 
275
273
  :::info Customization
@@ -357,7 +355,7 @@ export const MainLayout: FC<PropsWithChildren<MainLayoutProps>> = ({ title, chil
357
355
  </header>
358
356
  <main>{children}</main>
359
357
  <footer>
360
- <p 2025 My App</p>
358
+ <p>&copy; 2025 My App</p>
361
359
  </footer>
362
360
  </body>
363
361
  </html>
@@ -373,7 +371,7 @@ When you define Zod schemas in your route's `request` configuration (whether wit
373
371
 
374
372
  ```typescript
375
373
  import { z } from '@hono/zod-openapi';
376
- import { jsonContent, put } from '@venizia/ignis';
374
+ import { jsonContent, put, TRouteContext } from '@venizia/ignis';
377
375
  import { HTTP } from '@venizia/ignis-helpers';
378
376
 
379
377
  // ... inside a controller class
@@ -382,8 +380,7 @@ const UserSchema = z.object({ name: z.string(), email: z.string().email() });
382
380
 
383
381
  @put({
384
382
  configs: {
385
- path: '/:id',
386
- method: 'put',
383
+ path: '/{id}',
387
384
  request: {
388
385
  params: z.object({ id: z.string() }),
389
386
  query: z.object({ notify: z.string().optional() }),
@@ -392,7 +389,7 @@ const UserSchema = z.object({ name: z.string(), email: z.string().email() });
392
389
  // ... responses
393
390
  },
394
391
  })
395
- updateUser(c: Context) {
392
+ updateUser(c: TRouteContext) {
396
393
  // Access validated data from the request
397
394
  const { id } = c.req.valid('param');
398
395
  const { notify } = c.req.valid('query');
@@ -417,8 +414,7 @@ import { HTTP } from '@venizia/ignis-helpers';
417
414
  // ... inside a controller class
418
415
 
419
416
  const UpdateUserConfig = {
420
- path: '/:id',
421
- method: 'put',
417
+ path: '/{id}',
422
418
  request: {
423
419
  params: z.object({ id: z.string() }),
424
420
  query: z.object({ notify: z.string().optional() }),
@@ -453,11 +449,12 @@ Using `TRouteContext` provides a typed context object. By using `c.req.valid<T>(
453
449
  - [Application](/guides/core-concepts/application/) - Registering controllers
454
450
  - [Services](/guides/core-concepts/services) - Business logic layer called by controllers
455
451
  - [Dependency Injection](/guides/core-concepts/dependency-injection) - Injecting services into controllers
452
+ - [gRPC Controllers](/guides/core-concepts/grpc-controllers) - RPC-based controllers
456
453
 
457
454
  - **References:**
458
- - [BaseController API](/references/base/controllers) - Complete API reference
455
+ - [BaseRestController API](/references/base/controllers) - Complete REST controller API reference
459
456
  - [Middlewares](/references/base/middlewares) - Request interceptors
460
- - [Swagger Component](/references/components/swagger) - Auto-generate API docs
457
+ - [Swagger Component](/extensions/components/swagger) - Auto-generate API docs
461
458
  - [Schema Utilities](/references/utilities/schema) - Request/response helpers
462
459
 
463
460
  - **Tutorials:**
@@ -15,7 +15,7 @@ Services contain the core business logic of your application. They orchestrate t
15
15
 
16
16
  ### Creating a Service
17
17
 
18
- To create a service, you extend the `BaseService` class and inject the repositories or other services it depends on.
18
+ To create a service, extend the `BaseService` class and inject the repositories or other services it depends on.
19
19
 
20
20
  ```typescript
21
21
  import { BaseService, inject } from '@venizia/ignis';
@@ -27,9 +27,9 @@ import { TConfiguration } from '../models/entities';
27
27
 
28
28
  export class ConfigurationService extends BaseService {
29
29
  constructor(
30
- @inject({ key: 'repositories.ConfigurationRepository' })
30
+ @inject({ key: 'repositories.ConfigurationRepository' })
31
31
  private configurationRepository: ConfigurationRepository,
32
- @inject({ key: 'repositories.UserRepository' })
32
+ @inject({ key: 'repositories.UserRepository' })
33
33
  private userRepository: UserRepository,
34
34
  @inject({ key: 'services.LoggingService' })
35
35
  private loggingService: LoggingService, // Injecting another service for reuse
@@ -49,6 +49,20 @@ export class ConfigurationService extends BaseService {
49
49
  // ...
50
50
  ```
51
51
 
52
+ ### BaseService API
53
+
54
+ `BaseService` is intentionally minimal. It extends `BaseHelper` to provide scoped logging:
55
+
56
+ ```typescript
57
+ export abstract class BaseService extends BaseHelper implements IService {
58
+ constructor(opts: { scope: string }) {
59
+ super({ scope: opts.scope });
60
+ }
61
+ }
62
+ ```
63
+
64
+ There is no built-in CRUD service -- implement business logic directly in your service methods. This keeps the service layer focused on your domain-specific operations rather than generic data access patterns (which belong in repositories).
65
+
52
66
  ## How Services Fit into the Architecture
53
67
 
54
68
  Services act as the primary layer for business logic, sitting between controllers and repositories. While controllers are the typical entry point, **services can also inject and call other services**. This enables powerful logic reuse and allows you to build complex use cases by composing smaller, specialized services.
@@ -88,14 +102,14 @@ This layered architecture makes your application:
88
102
  ## See Also
89
103
 
90
104
  - **Related Concepts:**
91
- - [Controllers](/guides/core-concepts/controllers) - Call services to handle requests
105
+ - [Controllers](/guides/core-concepts/rest-controllers) - Call services to handle requests
92
106
  - [Repositories](/guides/core-concepts/persistent/repositories) - Data access layer used by services
93
107
  - [Dependency Injection](/guides/core-concepts/dependency-injection) - Injecting dependencies into services
94
108
 
95
109
  - **References:**
96
110
  - [BaseService API](/references/base/services) - Complete API reference
97
111
  - [Providers](/references/base/providers) - Factory pattern for runtime instantiation
98
- - [Logger Helper](/references/helpers/logger/) - Logging in services
112
+ - [Logger Helper](/extensions/helpers/logger/) - Logging in services
99
113
 
100
114
  - **Best Practices:**
101
115
  - [Architectural Patterns](/best-practices/architectural-patterns) - Service layer design
@@ -81,7 +81,7 @@ Create `src/index.ts`:
81
81
  import { z } from "@hono/zod-openapi";
82
82
  import {
83
83
  BaseApplication,
84
- BaseController,
84
+ BaseRestController,
85
85
  controller,
86
86
  get,
87
87
  IApplicationInfo,
@@ -94,7 +94,7 @@ import appInfo from "./../package.json";
94
94
 
95
95
  // 1. Define a controller
96
96
  @controller({ path: "/hello" })
97
- class HelloController extends BaseController {
97
+ class HelloController extends BaseRestController {
98
98
  constructor() {
99
99
  super({ scope: "HelloController", path: "/hello" });
100
100
  }
@@ -108,7 +108,6 @@ class HelloController extends BaseController {
108
108
  @get({
109
109
  configs: {
110
110
  path: "/",
111
- method: HTTP.Methods.GET,
112
111
  responses: {
113
112
  [HTTP.ResultCodes.RS_2.Ok]: jsonContent({
114
113
  description: "Says hello",
@@ -235,10 +234,10 @@ Open `http://localhost:3000/doc/explorer` to see interactive Swagger UI document
235
234
 
236
235
  | Component | What It Does |
237
236
  |-----------|--------------|
238
- | `@controller` | Registers a class as an API controller at `/api/hello` |
239
- | `@get` | Defines a GET endpoint with OpenAPI metadata |
237
+ | `@controller` | Registers a class as an API controller at `/api/hello`. Supports `transport` field for REST (default) or gRPC |
238
+ | `@get` | Defines a GET endpoint with OpenAPI metadata (auto-sets HTTP method) |
240
239
  | `Zod schema` | Validates request/response and auto-generates OpenAPI docs |
241
- | `BaseController` | Provides lifecycle hooks and route binding capabilities |
240
+ | `BaseRestController` | Provides lifecycle hooks, route binding, and OpenAPI integration for REST controllers |
242
241
  | `BaseApplication` | Manages dependency injection, middleware, and server startup |
243
242
  | `SwaggerComponent` | Generates interactive API docs at `/doc/explorer` |
244
243
  | `app.start()` | Boots the DI container and starts HTTP server on port 3000 |
@@ -296,7 +295,7 @@ You might wonder why we set up TypeScript, ESLint, and Prettier configs in a "qu
296
295
  },
297
296
  })
298
297
  async greet(c: Context) {
299
- const { name } = await c.req.json();
298
+ const { name } = c.req.valid('json');
300
299
  return c.json({ greeting: `Hello, ${name}!` }, HTTP.ResultCodes.RS_2.Ok);
301
300
  }
302
301
  ```
@@ -13,7 +13,7 @@ Ignis combines the structured, enterprise-grade development experience of **Loop
13
13
 
14
14
  ## The Framework Landscape
15
15
 
16
- When building REST APIs with Node.js/Bun, developers choose from three categories of frameworks:
16
+ When building REST APIs and server applications with Node.js/Bun, developers choose from three categories of frameworks:
17
17
 
18
18
  <div class="landscape-grid">
19
19
 
@@ -1,6 +1,6 @@
1
1
  # Getting Started with Ignis
2
2
 
3
- Welcome to Ignis — a TypeScript framework that combines enterprise architecture patterns with Hono's blazing performance. Whether you're building a SaaS backend, REST API, or microservice, these guides will take you from installation to production-ready code with type-safe database operations, auto-generated OpenAPI docs, and clean dependency injection.
3
+ Welcome to Ignis — a TypeScript framework that combines enterprise architecture patterns with Hono's blazing performance. Whether you're building a SaaS backend, REST API, gRPC service, or microservice, these guides will take you from installation to production-ready code with type-safe database operations, auto-generated OpenAPI docs, and clean dependency injection.
4
4
 
5
5
  <div class="guide-cards">
6
6
 
@@ -63,7 +63,7 @@ Welcome to Ignis — a TypeScript framework that combines enterprise architectur
63
63
  <span class="stage-num">3</span>
64
64
  <h4>Understand the Framework</h4>
65
65
  </div>
66
- <p><a href="./core-concepts/application">Application</a> → <a href="./core-concepts/controllers">Controllers</a> → <a href="./core-concepts/services">Services</a> → <a href="./core-concepts/dependency-injection">DI</a></p>
66
+ <p><a href="./core-concepts/application">Application</a> → <a href="./core-concepts/rest-controllers">Controllers</a> → <a href="./core-concepts/services">Services</a> → <a href="./core-concepts/dependency-injection">DI</a></p>
67
67
  <span class="stage-desc">Deep dive into core concepts and architecture patterns</span>
68
68
  </div>
69
69
 
@@ -8,7 +8,7 @@ Quick reference for key terms in Ignis documentation.
8
8
  | Term | Description |
9
9
  |------|-------------|
10
10
  | **Application** | Main entry point extending `BaseApplication`. Registers all components. |
11
- | **Controller** | Handles HTTP requests, defines API endpoints (`@controller`, `@get`, `@post`) |
11
+ | **Controller** | Handles HTTP/gRPC requests, defines API endpoints. REST controllers extend `BaseRestController`, gRPC controllers extend `BaseGrpcController`. Uses `@controller`, `@get`, `@post` decorators |
12
12
  | **Service** | Contains business logic between controllers and repositories |
13
13
  | **Repository** | Database operations for one entity (`find`, `create`, `updateById`, etc.) |
14
14
  | **DataSource** | Database connection configuration (host, port, credentials) |
@@ -36,7 +36,7 @@ const TodoRoutes = {
36
36
  } as const;
37
37
 
38
38
  @controller({ path: '/todos' })
39
- export class TodoController extends BaseController {
39
+ export class TodoController extends BaseRestController {
40
40
  @get({ configs: TodoRoutes.GET_ALL })
41
41
  async getAll(c: TRouteContext) {
42
42
  const todos = await this.repository.find({});
@@ -49,7 +49,7 @@ export class TodoController extends BaseController {
49
49
  export class TodoRepository extends DefaultCRUDRepository<typeof Todo.schema> {}
50
50
  ```
51
51
 
52
- **Related:** [Application](../core-concepts/application/) | [Controllers](../core-concepts/controllers) | [Services](../core-concepts/services) | [Repositories](../../references/base/repositories/)
52
+ **Related:** [Application](../core-concepts/application/) | [Controllers](../core-concepts/rest-controllers) | [Services](../core-concepts/services) | [Repositories](../../references/base/repositories/)
53
53
 
54
54
 
55
55
  ## TypeScript & Pattern Terms
@@ -59,7 +59,7 @@ Annotations starting with `@` that add behavior to classes/methods.
59
59
 
60
60
  | Decorator | Purpose |
61
61
  |-----------|---------|
62
- | `@controller` | Marks class as controller |
62
+ | `@controller` | Marks class as controller. Supports `transport` field (`'rest'` default, `'grpc'`) |
63
63
  | `@model` | Marks class as model/entity |
64
64
  | `@repository` | Marks class as repository |
65
65
  | `@datasource` | Marks class as datasource |
@@ -164,7 +164,7 @@ await repository.find({
164
164
  | Operator | Meaning | Example |
165
165
  |----------|---------|---------|
166
166
  | `eq` | Equal | `{ status: { eq: 'active' } }` |
167
- | `ne` | Not equal | `{ status: { ne: 'deleted' } }` |
167
+ | `neq` | Not equal | `{ status: { neq: 'deleted' } }` |
168
168
  | `gt`, `gte` | Greater than (or equal) | `{ age: { gte: 18 } }` |
169
169
  | `lt`, `lte` | Less than (or equal) | `{ price: { lt: 100 } }` |
170
170
  | `like`, `ilike` | Pattern match | `{ name: { like: '%john%' } }` |
@@ -194,7 +194,7 @@ const TodoRoutes = {
194
194
  } as const;
195
195
 
196
196
  @controller({ path: '/todos' })
197
- class TodoController {
197
+ class TodoController extends BaseRestController {
198
198
  @get({ configs: TodoRoutes.GET_ALL })
199
199
  async getAll(c: TRouteContext) { ... }
200
200
 
@@ -217,7 +217,7 @@ class TodoController {
217
217
  | **Endpoint** | URL path that API responds to (e.g., `GET /todos`) |
218
218
  | **Route Parameter** | Variable in URL marked with `:` (e.g., `:id`) |
219
219
  | **Request Body** | JSON data sent with POST/PATCH requests |
220
- | **OpenAPI/Swagger** | Auto-generated API docs at `/docs` |
220
+ | **OpenAPI/Swagger** | Auto-generated API docs at `/doc/explorer` (default path via SwaggerComponent) |
221
221
 
222
222
 
223
223
  ## Environment & Configuration
@@ -755,7 +755,7 @@ If this works, the issue is specific to `@venizia/ignis-docs`.
755
755
 
756
756
  ## What's Next?
757
757
 
758
- - **Learn the Tools:** Read the [Deep Dive Guide](/references/src-details/mcp-server) to understand all 5 available tools
758
+ - **Learn the Tools:** Read the [Deep Dive Guide](/extensions/src-details/mcp-server) to understand all 5 available tools
759
759
  - **Advanced Usage:** Explore how to chain tools for complex documentation queries
760
760
  - **Contribute:** Help improve the docs or add new features
761
761
 
@@ -598,7 +598,7 @@ this.controller(TodoController); // ← Make sure this is here!
598
598
  path: { base: '/api', isStrict: true }, // All routes start with /api
599
599
  ```
600
600
 
601
- **Debug:** Set `debug.showRoutes: true` in appConfigs to see all registered routes on startup.
601
+ **Debug:** Set `debug: { shouldShowRoutes: true }` in appConfigs to see all registered routes on startup.
602
602
 
603
603
 
604
604
  ### Error: "Invalid JSON" when creating todo
@@ -695,7 +695,7 @@ You now have a fully functional CRUD API! Here's what to explore next:
695
695
  3. [Components](../core-concepts/components.md) - Build reusable modules
696
696
 
697
697
  **Add Features:**
698
- 1. [Authentication](/references/components/authentication/) - Add JWT authentication
698
+ 1. [Authentication](/extensions/components/authentication/) - Add JWT authentication
699
699
  2. [Custom Routes](/best-practices/api-usage-examples.md) - Beyond CRUD operations
700
700
  3. [Relationships](../core-concepts/persistent/) - Link todos to users
701
701