@venizia/ignis-docs 0.0.8 → 0.2.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 (180) hide show
  1. package/README.md +7 -7
  2. package/content/best-practices/api-usage-examples.md +15 -12
  3. package/content/best-practices/architectural-patterns.md +70 -78
  4. package/content/best-practices/architecture-decisions.md +91 -60
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +56 -44
  6. package/content/best-practices/code-style-standards/constants-configuration.md +11 -11
  7. package/content/best-practices/code-style-standards/control-flow.md +5 -2
  8. package/content/best-practices/code-style-standards/documentation.md +13 -13
  9. package/content/best-practices/code-style-standards/function-patterns.md +9 -10
  10. package/content/best-practices/code-style-standards/index.md +1 -1
  11. package/content/best-practices/code-style-standards/naming-conventions.md +10 -8
  12. package/content/best-practices/code-style-standards/route-definitions.md +30 -12
  13. package/content/best-practices/code-style-standards/tooling.md +8 -5
  14. package/content/best-practices/code-style-standards/type-safety.md +13 -12
  15. package/content/best-practices/common-pitfalls.md +56 -37
  16. package/content/best-practices/contribution-workflow.md +13 -14
  17. package/content/best-practices/data-modeling.md +46 -22
  18. package/content/best-practices/deployment-strategies.md +28 -27
  19. package/content/best-practices/error-handling.md +48 -24
  20. package/content/best-practices/index.md +5 -5
  21. package/content/best-practices/performance-optimization.md +40 -31
  22. package/content/best-practices/security-guidelines.md +52 -23
  23. package/content/best-practices/testing-strategies.md +65 -51
  24. package/content/best-practices/troubleshooting-tips.md +24 -24
  25. package/content/extensions/components/{swagger.md → api-reference.md} +40 -31
  26. package/content/extensions/components/authentication/api.md +19 -19
  27. package/content/extensions/components/authentication/errors.md +7 -7
  28. package/content/extensions/components/authentication/index.md +10 -8
  29. package/content/extensions/components/authentication/usage.md +101 -6
  30. package/content/extensions/components/authorization/api.md +45 -25
  31. package/content/extensions/components/authorization/errors.md +6 -6
  32. package/content/extensions/components/authorization/index.md +11 -10
  33. package/content/extensions/components/authorization/usage.md +21 -21
  34. package/content/extensions/components/health-check.md +1 -1
  35. package/content/extensions/components/index.md +5 -5
  36. package/content/extensions/components/mail/errors.md +15 -15
  37. package/content/extensions/components/mail/index.md +1 -2
  38. package/content/extensions/components/mail/usage.md +1 -1
  39. package/content/extensions/components/request-tracker.md +1 -1
  40. package/content/extensions/components/socket-io/api.md +9 -9
  41. package/content/extensions/components/socket-io/errors.md +5 -5
  42. package/content/extensions/components/socket-io/index.md +8 -8
  43. package/content/extensions/components/socket-io/usage.md +1 -1
  44. package/content/extensions/components/static-asset/api.md +17 -4
  45. package/content/extensions/components/static-asset/errors.md +4 -4
  46. package/content/extensions/components/static-asset/index.md +26 -28
  47. package/content/extensions/components/static-asset/usage.md +13 -12
  48. package/content/extensions/components/template/index.md +2 -2
  49. package/content/extensions/components/template/setup-page.md +1 -1
  50. package/content/extensions/components/websocket/api.md +3 -3
  51. package/content/extensions/components/websocket/errors.md +5 -5
  52. package/content/extensions/components/websocket/index.md +5 -5
  53. package/content/extensions/components/websocket/usage.md +3 -3
  54. package/content/extensions/helpers/cron/index.md +2 -2
  55. package/content/extensions/helpers/crypto/index.md +1 -1
  56. package/content/extensions/helpers/env/index.md +27 -12
  57. package/content/extensions/helpers/error/index.md +81 -25
  58. package/content/extensions/helpers/index.md +2 -3
  59. package/content/extensions/helpers/inversion/index.md +15 -7
  60. package/content/extensions/helpers/kafka/compile-binary.md +92 -0
  61. package/content/extensions/helpers/kafka/examples.md +1 -1
  62. package/content/extensions/helpers/kafka/index.md +3 -0
  63. package/content/extensions/helpers/logger/index.md +32 -2
  64. package/content/extensions/helpers/network/index.md +6 -0
  65. package/content/extensions/helpers/queue/index.md +14 -17
  66. package/content/extensions/helpers/redis/index.md +548 -323
  67. package/content/extensions/helpers/socket-io/index.md +14 -10
  68. package/content/extensions/helpers/storage/api.md +44 -8
  69. package/content/extensions/helpers/storage/index.md +43 -7
  70. package/content/extensions/helpers/template/index.md +6 -3
  71. package/content/extensions/helpers/types/index.md +11 -8
  72. package/content/extensions/helpers/websocket/api.md +9 -9
  73. package/content/extensions/helpers/websocket/index.md +7 -7
  74. package/content/extensions/helpers/worker-thread/index.md +2 -2
  75. package/content/extensions/index.md +3 -4
  76. package/content/extensions/src-details/mcp-server.md +18 -24
  77. package/content/guides/core-concepts/application/bootstrapping.md +11 -14
  78. package/content/guides/core-concepts/application/index.md +3 -3
  79. package/content/guides/core-concepts/components.md +19 -10
  80. package/content/guides/core-concepts/dependency-injection.md +6 -3
  81. package/content/guides/core-concepts/grpc-controllers.md +6 -5
  82. package/content/guides/core-concepts/persistent/datasources.md +42 -43
  83. package/content/guides/core-concepts/persistent/index.md +16 -7
  84. package/content/guides/core-concepts/persistent/models.md +24 -20
  85. package/content/guides/core-concepts/persistent/postgres-drivers.md +201 -0
  86. package/content/guides/core-concepts/persistent/repositories.md +40 -23
  87. package/content/guides/core-concepts/persistent/search-meilisearch.md +185 -0
  88. package/content/guides/core-concepts/persistent/search-typesense.md +431 -0
  89. package/content/guides/core-concepts/persistent/transactions.md +61 -25
  90. package/content/guides/core-concepts/rest-controllers.md +12 -9
  91. package/content/guides/core-concepts/services.md +330 -60
  92. package/content/guides/get-started/5-minute-quickstart.md +15 -15
  93. package/content/guides/get-started/philosophy.md +36 -36
  94. package/content/guides/get-started/setup.md +3 -3
  95. package/content/guides/index.md +3 -3
  96. package/content/guides/migrations/redis-helpers-migration.md +177 -0
  97. package/content/guides/migrations/scoped-rbac-migration.md +17 -17
  98. package/content/guides/migrations/unified-connectors-migration.md +113 -0
  99. package/content/guides/reference/glossary.md +19 -12
  100. package/content/guides/reference/mcp-docs-server.md +22 -18
  101. package/content/guides/tutorials/building-a-crud-api.md +37 -44
  102. package/content/guides/tutorials/complete-installation.md +17 -17
  103. package/content/guides/tutorials/ecommerce-api.md +163 -124
  104. package/content/guides/tutorials/realtime-chat.md +181 -135
  105. package/content/guides/tutorials/testing.md +65 -523
  106. package/content/index.md +2 -180
  107. package/content/public/apple-touch-icon.png +0 -0
  108. package/content/public/og-image.png +0 -0
  109. package/content/public/site.webmanifest +11 -0
  110. package/content/references/base/application.md +4 -5
  111. package/content/references/base/bootstrapping.md +18 -5
  112. package/content/references/base/components.md +149 -120
  113. package/content/references/base/connectors.md +178 -0
  114. package/content/references/base/controllers.md +41 -30
  115. package/content/references/base/datasources.md +163 -92
  116. package/content/references/base/dependency-injection.md +34 -22
  117. package/content/references/base/filter-system/application-usage.md +17 -14
  118. package/content/references/base/filter-system/array-operators.md +7 -2
  119. package/content/references/base/filter-system/comparison-operators.md +3 -0
  120. package/content/references/base/filter-system/default-filter.md +89 -71
  121. package/content/references/base/filter-system/fields-order-pagination.md +22 -22
  122. package/content/references/base/filter-system/index.md +6 -3
  123. package/content/references/base/filter-system/json-filtering.md +20 -1
  124. package/content/references/base/filter-system/list-operators.md +1 -1
  125. package/content/references/base/filter-system/logical-operators.md +33 -1
  126. package/content/references/base/filter-system/null-operators.md +30 -1
  127. package/content/references/base/filter-system/quick-reference.md +23 -4
  128. package/content/references/base/filter-system/tips.md +5 -5
  129. package/content/references/base/filter-system/use-cases.md +12 -12
  130. package/content/references/base/grpc-controllers.md +13 -13
  131. package/content/references/base/index.md +24 -12
  132. package/content/references/base/middlewares.md +265 -327
  133. package/content/references/base/models.md +63 -49
  134. package/content/references/base/providers.md +136 -130
  135. package/content/references/base/repositories/advanced.md +59 -58
  136. package/content/references/base/repositories/index.md +115 -91
  137. package/content/references/base/repositories/mixins.md +55 -291
  138. package/content/references/base/repositories/relations.md +54 -64
  139. package/content/references/base/repositories/soft-deletable.md +31 -30
  140. package/content/references/base/services.md +296 -93
  141. package/content/references/configuration/environment-variables.md +49 -31
  142. package/content/references/configuration/index.md +6 -6
  143. package/content/references/index.md +17 -12
  144. package/content/references/quick-reference.md +65 -106
  145. package/content/references/utilities/crypto.md +65 -23
  146. package/content/references/utilities/index.md +3 -3
  147. package/content/references/utilities/jsx.md +6 -4
  148. package/content/references/utilities/module.md +68 -20
  149. package/content/references/utilities/parse.md +4 -14
  150. package/content/references/utilities/promise.md +9 -7
  151. package/content/references/utilities/schema.md +5 -3
  152. package/dist/mcp-server/common/guards.d.ts +8 -0
  153. package/dist/mcp-server/common/guards.d.ts.map +1 -0
  154. package/dist/mcp-server/common/guards.js +14 -0
  155. package/dist/mcp-server/common/guards.js.map +1 -0
  156. package/dist/mcp-server/common/index.d.ts +1 -0
  157. package/dist/mcp-server/common/index.d.ts.map +1 -1
  158. package/dist/mcp-server/common/index.js +1 -0
  159. package/dist/mcp-server/common/index.js.map +1 -1
  160. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  161. package/dist/mcp-server/helpers/docs.helper.js +4 -2
  162. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  163. package/dist/mcp-server/helpers/github.helper.js +1 -1
  164. package/dist/mcp-server/index.js +7 -2
  165. package/dist/mcp-server/index.js.map +1 -1
  166. package/dist/mcp-server/tools/base.tool.d.ts +6 -2
  167. package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
  168. package/dist/mcp-server/tools/base.tool.js.map +1 -1
  169. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  171. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  172. package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
  173. package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
  174. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  175. package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
  176. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
  177. package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
  178. package/package.json +9 -9
  179. package/content/extensions/helpers/testing/index.md +0 -510
  180. package/content/references/base/middleware.md +0 -347
@@ -2,101 +2,371 @@
2
2
 
3
3
  Services contain your application's business logic, orchestrating data flow and executing use cases.
4
4
 
5
- > **Deep Dive:** See [Services Reference](../../references/base/services.md) for advanced patterns.
5
+ > **Deep Dive:** See [Services Reference](../../references/base/services.md) for the full API reference.
6
6
 
7
7
  ## The Business Logic Layer
8
8
 
9
- Services contain the core business logic of your application. They orchestrate the flow of data and execute the application's use cases. A service's primary responsibilities are:
9
+ Services sit between controllers and repositories. A controller receives an HTTP request and immediately delegates to a service; the service applies business rules, calls one or more repositories, and returns the result.
10
10
 
11
- - **Encapsulating Business Rules**: Centralizing logic such as calculations, data validation, and process workflows.
12
- - **Coordinating Operations**: Using repositories to fetch and persist data, or orchestrating other services to execute complex business workflows.
13
- - **Reusing Business Logic**: Services can inject other services to reuse established logic, ensuring "Don't Repeat Yourself" (DRY) principles are maintained across the application.
14
- - **Isolating Controllers**: Keeping controllers thin by handling all the complex logic, so controllers are only responsible for handling the HTTP request and response.
11
+ Primary responsibilities:
15
12
 
16
- ### Creating a Service
13
+ - **Encapsulate business rules** - validation, state-machine transitions, authorization guards, calculations
14
+ - **Coordinate repositories** - fetch related data, combine writes, enforce consistency
15
+ - **Manage transactions** - begin, commit, or roll back across multiple repository calls
16
+ - **Compose services** - inject and call other services to avoid duplicating logic
17
17
 
18
- To create a service, extend the `BaseService` class and inject the repositories or other services it depends on.
18
+ Controllers stay thin. Repositories stay dumb. Everything in between is a service.
19
+
20
+ ---
21
+
22
+ ## Creating a Service
23
+
24
+ Extend `BaseService` and call `super({ scope: ClassName.name })` in the constructor:
19
25
 
20
26
  ```typescript
21
27
  import { BaseService, inject } from '@venizia/ignis';
22
- import { ConfigurationRepository } from '../repositories';
28
+ import { getError, HTTP } from '@venizia/ignis-helpers';
23
29
  import { UserRepository } from '../repositories';
24
- import { LoggingService } from './logging.service'; // Example of another service
25
- import { TConfiguration } from '../models/entities';
26
30
 
27
- export class ConfigurationService extends BaseService {
31
+ export class UserService extends BaseService {
32
+ constructor(
33
+ @inject({ key: 'repositories.UserRepository' })
34
+ private userRepository: UserRepository,
35
+ ) {
36
+ super({ scope: UserService.name });
37
+ }
38
+
39
+ async getUser(opts: { id: string }) {
40
+ const user = await this.userRepository.findById({ id: opts.id });
41
+
42
+ if (!user) {
43
+ throw getError({
44
+ statusCode: HTTP.ResultCodes.RS_4.NotFound,
45
+ message: 'User not found',
46
+ });
47
+ }
48
+
49
+ return user;
50
+ }
51
+ }
52
+ ```
53
+
54
+ **`scope`** is the tag written into every log line produced by this service. Use `ClassName.name` - it's the project convention and avoids string drift when renaming the class.
55
+
56
+ ---
57
+
58
+ ## Registering a Service
59
+
60
+ Registration is always imperative - call `this.service(ClassName)` inside an application lifecycle method. Do not add `@injectable` to services; `this.service()` handles the binding.
61
+
62
+ ```typescript
63
+ import { BaseApplication } from '@venizia/ignis';
64
+ import { PostgresDataSource } from './datasources';
65
+ import { UserRepository } from './repositories';
66
+ import { UserService } from './services';
67
+
68
+ export class Application extends BaseApplication {
69
+ preConfigure(): void {
70
+ // Register dependencies first, then the service
71
+ this.dataSource(PostgresDataSource);
72
+ this.repository(UserRepository);
73
+ this.service(UserService); // binds as 'services.UserService'
74
+ }
75
+ }
76
+ ```
77
+
78
+ `this.service(UserService)` binds the class at the key `services.UserService`. Any other binding that injects `@inject({ key: 'services.UserService' })` resolves an instance from this binding. Service bindings are **transient** by default - each resolution creates a new instance. If your service must be shared (e.g., it holds state), set the scope explicitly: `this.service(UserService).setScope(BindingScopes.SINGLETON)`.
79
+
80
+ ---
81
+
82
+ ## Injecting Dependencies
83
+
84
+ Use `@inject({ key })` on each constructor parameter. Two equivalent forms:
85
+
86
+ ### Plain string keys (concise)
87
+
88
+ ```typescript
89
+ constructor(
90
+ @inject({ key: 'repositories.UserRepository' })
91
+ private userRepository: UserRepository,
92
+
93
+ @inject({ key: 'services.NotificationService' })
94
+ private notificationService: NotificationService,
95
+ ) {
96
+ super({ scope: UserService.name });
97
+ }
98
+ ```
99
+
100
+ ### `BindingKeys.build` (refactor-safe)
101
+
102
+ ```typescript
103
+ import { BindingKeys, BindingNamespaces } from '@venizia/ignis';
104
+
105
+ constructor(
106
+ @inject({
107
+ key: BindingKeys.build({
108
+ namespace: BindingNamespaces.REPOSITORY, // 'repositories'
109
+ key: UserRepository.name, // 'UserRepository'
110
+ }),
111
+ })
112
+ private userRepository: UserRepository,
113
+ ) {
114
+ super({ scope: UserService.name });
115
+ }
116
+ ```
117
+
118
+ Both produce the same runtime key (`repositories.UserRepository`). `BindingKeys.build` is preferred in larger codebases because a class rename caught by the TypeScript compiler automatically updates the key.
119
+
120
+ ---
121
+
122
+ ## Logging
123
+
124
+ `BaseService` inherits `this.logger` from `BaseHelper`. Scope log lines to the current method:
125
+
126
+ ```typescript
127
+ async signIn(opts: { username: string }): Promise<string> {
128
+ this.logger.for('signIn').info('SignIn called | username: %s', opts.username);
129
+
130
+ const user = await this.userRepository.findByUsername(opts.username);
131
+
132
+ if (!user) {
133
+ this.logger.for('signIn').warn('User not found | username: %s', opts.username);
134
+ throw getError({ statusCode: HTTP.ResultCodes.RS_4.Unauthorized, message: 'Invalid credentials' });
135
+ }
136
+
137
+ this.logger.for('signIn').info('SignIn successful | userId: %s', user.id);
138
+ return await this.generateToken({ userId: user.id });
139
+ }
140
+ ```
141
+
142
+ `this.logger.for('signIn')` adds a `[signIn]` tag to each line without creating a new logger object.
143
+
144
+ ---
145
+
146
+ ## Service-to-Service Composition
147
+
148
+ Services can inject other services the same way they inject repositories. This is the primary mechanism for logic reuse.
149
+
150
+ ```typescript
151
+ export class RepositoryTestService extends BaseService {
152
+ constructor(
153
+ @inject({
154
+ key: BindingKeys.build({
155
+ namespace: BindingNamespaces.SERVICE,
156
+ key: CrudTestService.name,
157
+ }),
158
+ })
159
+ private readonly crudTestService: CrudTestService,
160
+
161
+ @inject({
162
+ key: BindingKeys.build({
163
+ namespace: BindingNamespaces.SERVICE,
164
+ key: TransactionTestService.name,
165
+ }),
166
+ })
167
+ private readonly transactionTestService: TransactionTestService,
168
+ ) {
169
+ super({ scope: RepositoryTestService.name });
170
+ }
171
+
172
+ async runAll(): Promise<void> {
173
+ await this.crudTestService.run();
174
+ await this.transactionTestService.run();
175
+ }
176
+ }
177
+ ```
178
+
179
+ Register all participating services in `preConfigure()`:
180
+
181
+ ```typescript
182
+ this.service(CrudTestService);
183
+ this.service(TransactionTestService);
184
+ this.service(RepositoryTestService);
185
+ ```
186
+
187
+ The DI container resolves the dependency graph automatically - registration order within the same lifecycle phase does not matter.
188
+
189
+ ---
190
+
191
+ ## Worked Example: Authentication Service
192
+
193
+ The following is representative of `examples/vert/src/services/authentication.service.ts`. It shows the complete pattern: multiple injected dependencies, method-scoped logging, error handling, and calling other services.
194
+
195
+ ```typescript
196
+ import { BaseService, IAuthService, inject, JWKSIssuerTokenService, TContext } from '@venizia/ignis';
197
+ import { getError, HTTP } from '@venizia/ignis-helpers';
198
+ import { compare, genSalt, hash } from 'bcrypt';
199
+ import { Env } from 'hono';
200
+
201
+ export class AuthenticationService
202
+ extends BaseService
203
+ implements IAuthService<Env, TSignInRequest, TSignInResponse, ...>
204
+ {
28
205
  constructor(
29
- @inject({ key: 'repositories.ConfigurationRepository' })
30
- private configurationRepository: ConfigurationRepository,
206
+ // Inject a repository by string key
31
207
  @inject({ key: 'repositories.UserRepository' })
32
208
  private userRepository: UserRepository,
33
- @inject({ key: 'services.LoggingService' })
34
- private loggingService: LoggingService, // Injecting another service for reuse
209
+
210
+ // Inject a built-in framework service by string key
211
+ @inject({ key: 'services.JWKSIssuerTokenService' })
212
+ private jwksTokenService: JWKSIssuerTokenService,
35
213
  ) {
36
- super({ scope: ConfigurationService.name });
214
+ super({ scope: AuthenticationService.name });
215
+ }
216
+
217
+ async signIn(_context: TContext<Env>, opts: TSignInRequest): Promise<TSignInResponse> {
218
+ this.logger.for('signIn').info('SignIn called | identifier: %j', opts.identifier);
219
+
220
+ const user = await this.userRepository.findByUsername(opts.identifier.value);
221
+
222
+ if (!user) {
223
+ throw getError({
224
+ statusCode: HTTP.ResultCodes.RS_4.Unauthorized,
225
+ message: 'Invalid credentials',
226
+ });
227
+ }
228
+
229
+ const isValid = await compare(opts.credential.value, user.password);
230
+ if (!isValid) {
231
+ throw getError({
232
+ statusCode: HTTP.ResultCodes.RS_4.Unauthorized,
233
+ message: 'Invalid credentials',
234
+ });
235
+ }
236
+
237
+ const token = await this.jwksTokenService.generate({
238
+ payload: { userId: user.id, email: user.email },
239
+ });
240
+
241
+ this.logger.for('signIn').info('SignIn successful | userId: %s', user.id);
242
+ return { token: { value: token, type: 'Bearer' } };
243
+ }
244
+
245
+ async signUp(_context: TContext<Env>, opts: TSignUpRequest): Promise<TSignUpResponse> {
246
+ this.logger.for('signUp').info('SignUp called | username: %s', opts.username);
247
+
248
+ const existing = await this.userRepository.findByUsername(opts.username);
249
+ if (existing) {
250
+ throw getError({
251
+ statusCode: HTTP.ResultCodes.RS_4.Conflict,
252
+ message: 'Username already exists',
253
+ });
254
+ }
255
+
256
+ const salt = await genSalt();
257
+ const hashedPassword = await hash(opts.credential, salt);
258
+
259
+ await this.userRepository.create({ data: { username: opts.username, password: hashedPassword } });
260
+
261
+ return { message: 'User registered successfully' };
37
262
  }
263
+ }
264
+ ```
38
265
 
39
- async createConfigurationForUser(opts: {
40
- userId: string;
41
- data: Partial<TConfiguration>;
42
- }): Promise<TConfiguration> {
43
- // Call another service logic
44
- await this.loggingService.audit({ message: `Creating config for user: ${opts.userId}` });
266
+ Registration:
45
267
 
46
- // Business logic: Check if the user exists
47
- const user = await this.userRepository.findById({ id: opts.userId });
48
- // ...
268
+ ```typescript
269
+ // application.ts
270
+ preConfigure(): void {
271
+ this.dataSource(PostgresDataSource);
272
+ this.repository(UserRepository);
273
+ this.service(AuthenticationService); // 'services.AuthenticationService'
274
+ }
49
275
  ```
50
276
 
51
- ### BaseService API
277
+ ---
52
278
 
53
- `BaseService` is intentionally minimal. It extends `BaseHelper` to provide scoped logging:
279
+ ## Transaction Orchestration
280
+
281
+ Use a datasource reference to begin a transaction, then pass the transaction handle through repository `options`:
54
282
 
55
283
  ```typescript
56
- export abstract class BaseService extends BaseHelper implements IService {
57
- constructor(opts: { scope: string }) {
58
- super({ scope: opts.scope });
284
+ export class CheckoutService extends BaseService {
285
+ constructor(
286
+ @inject({ key: 'datasources.PostgresDataSource' })
287
+ private dataSource: PostgresDataSource,
288
+
289
+ @inject({ key: 'repositories.OrderRepository' })
290
+ private orderRepository: OrderRepository,
291
+
292
+ @inject({ key: 'repositories.InventoryRepository' })
293
+ private inventoryRepository: InventoryRepository,
294
+ ) {
295
+ super({ scope: CheckoutService.name });
296
+ }
297
+
298
+ async placeOrder(opts: { userId: string; items: OrderItem[] }): Promise<Order> {
299
+ const log = this.logger.for('placeOrder');
300
+ const transaction = await this.dataSource.beginTransaction();
301
+
302
+ try {
303
+ const { data: order } = await this.orderRepository.create({
304
+ data: { userId: opts.userId },
305
+ options: { transaction },
306
+ });
307
+
308
+ for (const item of opts.items) {
309
+ await this.inventoryRepository.updateById({
310
+ id: item.productId,
311
+ data: { stock: item.quantity },
312
+ options: { transaction },
313
+ });
314
+ }
315
+
316
+ await transaction.commit();
317
+ log.info('Order placed | orderId: %s', order.id);
318
+ return order;
319
+ } catch (error) {
320
+ await transaction.rollback();
321
+ log.error('Order failed, rolled back | error: %s', error);
322
+ throw error;
323
+ }
59
324
  }
60
325
  }
61
326
  ```
62
327
 
63
- 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).
328
+ Always call `rollback()` in `catch` - an uncommitted transaction holds a database connection until it is released.
64
329
 
65
- ## How Services Fit into the Architecture
330
+ ---
66
331
 
67
- 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.
332
+ ## Architecture Diagram
68
333
 
69
334
  ```mermaid
70
335
  graph LR
71
- A[Client Request] --> B(Controller);
72
- B --> C1{Service A};
73
- C1 --> C2{Service B};
74
- C1 --> D1[Repository A];
75
- C2 --> D2[Repository B];
76
- D1 --> E((Database));
77
- D2 --> E;
78
-
79
- subgraph "Presentation Layer"
336
+ A[HTTP Request] --> B(Controller)
337
+ B --> C{Service A}
338
+ C --> D{Service B}
339
+ C --> E[Repository A]
340
+ D --> F[Repository B]
341
+ E --> G((Database))
342
+ F --> G
343
+
344
+ subgraph "Presentation"
80
345
  B
81
346
  end
82
- subgraph "Business Logic Layer"
83
- C1
84
- C2
85
- end
86
- subgraph "Data Access Layer"
87
- D1
88
- D2
347
+ subgraph "Business Logic"
348
+ C
349
+ D
89
350
  end
90
- subgraph "Data Store"
351
+ subgraph "Data Access"
91
352
  E
353
+ F
92
354
  end
93
355
  ```
94
356
 
95
- This layered architecture makes your application:
357
+ Controllers call services. Services call other services and repositories. Repositories call the database. No layer reaches past its immediate neighbor.
358
+
359
+ ---
360
+
361
+ ## Provider vs Service
362
+
363
+ **Services** contain business logic and are resolved from the DI container (transient scope by default).
364
+
365
+ **Providers** implement the Factory pattern - their `value(container)` method produces a configured value or instance on demand (mail transport, cache driver, middleware). Use a Provider when you need to select between multiple implementations at runtime.
366
+
367
+ See [Providers Reference](/references/base/providers) for the full comparison and examples.
96
368
 
97
- - **More Organized:** Each layer has a clear and distinct responsibility.
98
- - **Easier to Test:** You can test your business logic in isolation by providing mock repositories to your services, without needing a live database.
99
- - **More Flexible:** You can change your database or data access implementation (e.g., switch from PostgreSQL to MySQL) by only changing the repository and datasource layer, with no changes to your business logic.
369
+ ---
100
370
 
101
371
  ## See Also
102
372
 
@@ -107,13 +377,13 @@ This layered architecture makes your application:
107
377
 
108
378
  - **References:**
109
379
  - [BaseService API](/references/base/services) - Complete API reference
110
- - [Providers](/references/base/providers) - Factory pattern for runtime instantiation
380
+ - [Providers](/references/base/providers) - Factory pattern
111
381
  - [Logger Helper](/extensions/helpers/logger/) - Logging in services
112
382
 
113
383
  - **Best Practices:**
114
- - [Architectural Patterns](/best-practices/architectural-patterns) - Service layer design
115
- - [Testing](/guides/tutorials/testing) - Unit testing services
384
+ - [Architectural Patterns](/best-practices/architectural-patterns)
385
+ - [Testing](/guides/tutorials/testing)
116
386
 
117
387
  - **Tutorials:**
118
- - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - Service examples
119
- - [E-commerce API](/guides/tutorials/ecommerce-api) - Complex business logic
388
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api)
389
+ - [E-commerce API](/guides/tutorials/ecommerce-api)
@@ -1,6 +1,6 @@
1
1
  # 5-Minute Quickstart
2
2
 
3
- Build your first Ignis API endpoint in 5 minutes. No database, no complex setup - just a working "Hello World" API.
3
+ Build your first IGNIS API endpoint in 5 minutes. No database, no complex setup - just a working "Hello World" API.
4
4
 
5
5
  **Time to Complete:** ~5 minutes
6
6
 
@@ -64,7 +64,7 @@ node_modules
64
64
  ## Step 3: Write Your API (2 minutes)
65
65
 
66
66
  :::info What is a Decorator?
67
- A decorator is a TypeScript feature that adds behavior to classes, methods, or properties. It's the `@something` syntax you see before definitions (like `@controller`, `@get`, `@inject`). Decorators in Ignis handle routing, dependency injection, and API documentation automatically.
67
+ A decorator is a TypeScript feature that adds behavior to classes, methods, or properties. It's the `@something` syntax you see before definitions (like `@controller`, `@get`, `@inject`). Decorators in IGNIS handle routing, dependency injection, and API documentation automatically.
68
68
 
69
69
  [Learn more →](/guides/reference/glossary#decorators)
70
70
  :::
@@ -86,7 +86,7 @@ import {
86
86
  get,
87
87
  IApplicationInfo,
88
88
  jsonContent,
89
- SwaggerComponent,
89
+ ApiReferenceComponent,
90
90
  } from "@venizia/ignis";
91
91
  import { HTTP } from "@venizia/ignis-helpers";
92
92
  import { Context } from "hono";
@@ -115,7 +115,7 @@ class HelloController extends BaseRestController {
115
115
  },
116
116
  })
117
117
  sayHello(c: Context) {
118
- return c.json({ message: "Hello from Ignis!" }, HTTP.ResultCodes.RS_2.Ok);
118
+ return c.json({ message: "Hello from IGNIS!" }, HTTP.ResultCodes.RS_2.Ok);
119
119
  }
120
120
  }
121
121
 
@@ -130,7 +130,7 @@ class App extends BaseApplication {
130
130
  }
131
131
 
132
132
  preConfigure() {
133
- this.component(SwaggerComponent);
133
+ this.component(ApiReferenceComponent);
134
134
  this.controller(HelloController);
135
135
  }
136
136
 
@@ -222,7 +222,7 @@ Visit `http://localhost:3000/api/hello` in your browser!
222
222
  **Response:**
223
223
 
224
224
  ```json
225
- { "message": "Hello from Ignis!" }
225
+ { "message": "Hello from IGNIS!" }
226
226
  ```
227
227
 
228
228
  ## View API Docs
@@ -240,27 +240,27 @@ Open `http://localhost:3000/doc/explorer` to see interactive Swagger UI document
240
240
  | `Zod schema` | Validates request/response and auto-generates OpenAPI docs |
241
241
  | `BaseRestController` | Provides lifecycle hooks, route binding, and OpenAPI integration for REST controllers |
242
242
  | `BaseApplication` | Manages dependency injection, middleware, and server startup |
243
- | `SwaggerComponent` | Generates interactive API docs at `/doc/explorer` |
243
+ | `ApiReferenceComponent` | Generates interactive API docs at `/doc/explorer` |
244
244
  | `app.start()` | Runs the full lifecycle (preConfigure → register resources → middlewares) then starts HTTP server on port 3000 |
245
245
 
246
246
  ### Why Development Configs?
247
247
 
248
248
  You might wonder why we set up TypeScript, ESLint, and Prettier configs in a "quickstart". Here's why:
249
249
 
250
- **Ignis is opinionated about code quality.** We believe clean, consistent code from day one prevents technical debt later. The `@venizia/dev-configs` package provides pre-configured settings that:
250
+ **IGNIS is opinionated about code quality.** We believe clean, consistent code from day one prevents technical debt later. The `@venizia/dev-configs` package provides pre-configured settings that:
251
251
 
252
252
  | Config | Purpose |
253
253
  |--------|---------|
254
- | `tsconfig.json` | Strict TypeScript settings optimized for Ignis decorators and path aliases |
254
+ | `tsconfig.json` | Strict TypeScript settings optimized for IGNIS decorators and path aliases |
255
255
  | `eslint.config.mjs` | Catches common errors, enforces best practices, works with TypeScript |
256
- | `.prettierrc.mjs` | Consistent formatting across your team no more style debates |
256
+ | `.prettierrc.mjs` | Consistent formatting across your team - no more style debates |
257
257
 
258
- **Benefits of starting with Ignis code style:**
258
+ **Benefits of starting with IGNIS code style:**
259
259
 
260
- - **Consistency** Same patterns across all Ignis projects
261
- - **IDE Support** Better autocomplete, error detection, and refactoring
262
- - **Team Ready** New developers can onboard faster with familiar structure
263
- - **CI/CD Friendly** Lint and format checks work out of the box
260
+ - **Consistency** - Same patterns across all IGNIS projects
261
+ - **IDE Support** - Better autocomplete, error detection, and refactoring
262
+ - **Team Ready** - New developers can onboard faster with familiar structure
263
+ - **CI/CD Friendly** - Lint and format checks work out of the box
264
264
 
265
265
  > [!TIP]
266
266
  > All configs extend from `@venizia/dev-configs`, so you get updates automatically. Customize by overriding specific rules in your local config files.