@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
@@ -55,13 +55,13 @@ Use consistent prefixes based on function purpose:
55
55
  | Prefix | Purpose | Examples |
56
56
  |--------|---------|----------|
57
57
  | `generate*` | Create column definitions / schemas | `generateIdColumnDefs()`, `generateTzColumnDefs()` |
58
- | `build*` | Construct complex objects | `buildPrimitiveCondition()`, `buildJsonOrderBy()` |
59
- | `to*` | Convert/transform data | `toCamel()`, `toBoolean()`, `toStringDecimal()` |
58
+ | `build*` | Construct complex objects | `buildValueCondition()`, `buildJsonOrderBy()` |
59
+ | `to*` | Convert/transform data | `toCamel()`, `toBoolean()` |
60
60
  | `is*` | Boolean validation/check | `isWeekday()`, `isInt()`, `isFloat()`, `isPromiseLike()` |
61
61
  | `extract*` | Pull out specific parts | `extractTimestamp()`, `extractWorkerId()`, `extractSequence()` |
62
62
  | `enrich*` | Enhance with additional data | `enrichUserAudit()`, `enrichWithMetadata()` |
63
63
  | `get*` | Retrieve/fetch data | `getSchema()`, `getConnector()`, `getError()` |
64
- | `resolve*` | Determine/compute value | `resolveValue()`, `resolvePath()` |
64
+ | `resolve*` | Determine/compute value | `resolveValue()`, `resolveClass()` |
65
65
 
66
66
  **Examples:**
67
67
 
@@ -71,13 +71,12 @@ const idCols = generateIdColumnDefs({ id: { dataType: 'string' } });
71
71
  const tzCols = generateTzColumnDefs();
72
72
 
73
73
  // Builders - construct complex query objects
74
- const condition = buildPrimitiveCondition(column, operator, value);
74
+ const condition = buildValueCondition(column, value);
75
75
  const orderBy = buildJsonOrderBy(schema, path, direction);
76
76
 
77
77
  // Converters - transform data types
78
78
  const camelCase = toCamel('snake_case');
79
79
  const bool = toBoolean('true');
80
- const decimal = toStringDecimal(123.456, 2);
81
80
 
82
81
  // Validators - boolean checks
83
82
  if (isWeekday(date)) { /* ... */ }
@@ -94,9 +93,9 @@ const workerId = extractWorkerId(snowflakeId);
94
93
  Every class extending a base class should set its scope using `ClassName.name`:
95
94
 
96
95
  ```typescript
97
- export class JWTTokenService extends BaseService {
96
+ export class PaymentService extends BaseService {
98
97
  constructor() {
99
- super({ scope: JWTTokenService.name });
98
+ super({ scope: PaymentService.name });
100
99
  }
101
100
  }
102
101
 
@@ -135,7 +134,7 @@ await executeWithPerformanceMeasure({
135
134
  await syncAllUsers();
136
135
  },
137
136
  });
138
- // Logs: [DataSync] Sync user records | Took: 1234.56 (ms)
137
+ // Logs: [DataSync] DONE | Sync user records | Took: 1234.56 (ms)
139
138
  ```
140
139
 
141
140
  **Method-scoped logging pattern:**
@@ -144,13 +143,13 @@ await executeWithPerformanceMeasure({
144
143
  class UserService {
145
144
  private logger = Logger.get('UserService');
146
145
 
147
- async createUser(data: CreateUserDto) {
146
+ async createUser(data: TCreateUserRequest) {
148
147
  // Use .for() to add method context to all logs
149
148
  this.logger.for('createUser').info('Creating user: %j', data);
150
149
  // Output: [UserService-createUser] Creating user: {...}
151
150
 
152
151
  try {
153
- const user = await this.userRepo.create({ data });
152
+ const { data: user } = await this.userRepository.create({ data });
154
153
  this.logger.for('createUser').info('User created: %s', user.id);
155
154
  return user;
156
155
  } catch (error) {
@@ -1,6 +1,6 @@
1
1
  # Code Style Standards
2
2
 
3
- Maintain consistent code style using **Prettier** (formatting) and **ESLint** (code quality). Ignis provides centralized configurations via the `@venizia/dev-configs` package.
3
+ Maintain consistent code style using **Prettier** (formatting) and **ESLint** (code quality). IGNIS provides centralized configurations via the `@venizia/dev-configs` package.
4
4
 
5
5
  ## Quick Reference
6
6
 
@@ -57,9 +57,9 @@ export * from './types';
57
57
  |------|---------|---------|
58
58
  | Components | `[Feature]Component` | `HealthCheckComponent`, `AuthComponent` |
59
59
  | Controllers | `[Feature]Controller` | `UserController`, `AuthController` |
60
- | Services | `[Feature]Service` | `JWTTokenService`, `PaymentService` |
60
+ | Services | `[Feature]Service` | `JWSTokenService`, `PaymentService` |
61
61
  | Repositories | `[Feature]Repository` | `UserRepository`, `OrderRepository` |
62
- | Strategies | `[Feature]Strategy` | `JWTAuthenticationStrategy` |
62
+ | Strategies | `[Feature]Strategy` | `JWSAuthenticationStrategy`, `BasicAuthenticationStrategy` |
63
63
  | Factories | `[Feature]Factory` | `UIProviderFactory` |
64
64
 
65
65
  ## File Names
@@ -90,15 +90,17 @@ interface IHealthCheckOptions {
90
90
  }
91
91
 
92
92
  interface IAuthService {
93
- signIn(context: Context): Promise<void>;
93
+ signIn(context: Context, opts: TSignInRequest): Promise<AnyObject>;
94
94
  }
95
95
 
96
96
  // Type aliases use 'T' prefix
97
97
  type TSignInRequest = z.infer<typeof SignInRequestSchema>;
98
- type TRouteContext = Context<Env, Path, Input>;
98
+ type TAuthStrategy = TConstValue<typeof AuthenticateStrategy>;
99
99
 
100
100
  // Generic constraints
101
- type TTableSchemaWithId = { id: PgColumn };
101
+ type TTableSchemaWithId<TC extends TableConfig = TableConfig> = PgTable<TC> & {
102
+ id: TIdColumn;
103
+ };
102
104
  ```
103
105
 
104
106
  ## Binding Keys
@@ -123,14 +125,14 @@ Use underscore prefix (`_`) for private and protected class fields to distinguis
123
125
  ```typescript
124
126
  class MyRepository extends DefaultCRUDRepository {
125
127
  // Private fields with underscore prefix
126
- private _dataSource: IDataSource;
127
- private _entity: BaseEntity;
128
+ private _dataSource: AbstractDataSource;
129
+ private _entity: AbstractEntity;
128
130
  private _hiddenProperties: Set<string> | null = null;
129
131
 
130
132
  // Protected fields also use underscore prefix
131
133
  protected _schemaFactory?: ReturnType<typeof createSchemaFactory>;
132
134
 
133
- constructor(dataSource: IDataSource) {
135
+ constructor(dataSource: AbstractDataSource) {
134
136
  // 'dataSource' (param) vs '_dataSource' (field)
135
137
  this._dataSource = dataSource;
136
138
  }
@@ -1,6 +1,6 @@
1
1
  # Route Definitions
2
2
 
3
- Ignis supports multiple methods for defining routes. Choose based on your needs.
3
+ IGNIS supports multiple methods for defining routes. Choose based on your needs.
4
4
 
5
5
  ## Method 1: Config-Driven Routes
6
6
 
@@ -15,12 +15,14 @@ export class UserRestPaths {
15
15
  }
16
16
 
17
17
  // common/route-configs.ts
18
+ // jsonResponse({ schema }) expands to a 200 response plus a '4xx | 5xx' error fallback
18
19
  export const RouteConfigs = {
19
20
  GET_USERS: {
20
21
  method: HTTP.Methods.GET,
21
22
  path: UserRestPaths.ROOT,
22
23
  responses: jsonResponse({
23
- [HTTP.ResultCodes.RS_2.Ok]: UserListSchema,
24
+ description: 'List of users',
25
+ schema: UserListSchema,
24
26
  }),
25
27
  },
26
28
  GET_USER_BY_ID: {
@@ -30,8 +32,8 @@ export const RouteConfigs = {
30
32
  params: z.object({ id: z.string() }),
31
33
  },
32
34
  responses: jsonResponse({
33
- [HTTP.ResultCodes.RS_2.Ok]: UserSchema,
34
- [HTTP.ResultCodes.RS_4.NotFound]: ErrorSchema,
35
+ description: 'User detail',
36
+ schema: UserSchema,
35
37
  }),
36
38
  },
37
39
  } as const;
@@ -42,6 +44,9 @@ export const RouteConfigs = {
42
44
  ```typescript
43
45
  @controller({ path: '/users' })
44
46
  export class UserController extends BaseRestController {
47
+ constructor() {
48
+ super({ scope: UserController.name });
49
+ }
45
50
 
46
51
  @api({ configs: RouteConfigs.GET_USERS })
47
52
  list(context: TRouteContext) {
@@ -58,14 +63,18 @@ export class UserController extends BaseRestController {
58
63
 
59
64
  ## Method 3: Using `bindRoute` (Programmatic)
60
65
 
66
+ Register routes in the `binding()` lifecycle method:
67
+
61
68
  ```typescript
62
69
  @controller({ path: '/health' })
63
70
  export class HealthCheckController extends BaseRestController {
64
71
  constructor() {
65
72
  super({ scope: HealthCheckController.name });
73
+ }
66
74
 
75
+ override binding(): ValueOrPromise<void> {
67
76
  this.bindRoute({ configs: RouteConfigs.GET_HEALTH }).to({
68
- handler: context => context.json({ status: 'ok' }),
77
+ handler: context => context.json({ status: 'ok' }, HTTP.ResultCodes.RS_2.Ok),
69
78
  });
70
79
  }
71
80
  }
@@ -78,11 +87,13 @@ export class HealthCheckController extends BaseRestController {
78
87
  export class HealthCheckController extends BaseRestController {
79
88
  constructor() {
80
89
  super({ scope: HealthCheckController.name });
90
+ }
81
91
 
92
+ override binding(): ValueOrPromise<void> {
82
93
  this.defineRoute({
83
94
  configs: RouteConfigs.POST_PING,
84
95
  handler: context => {
85
- const { message } = context.req.valid('json');
96
+ const { message } = context.req.valid<{ message: string }>('json');
86
97
  return context.json({ echo: message }, HTTP.ResultCodes.RS_2.Ok);
87
98
  },
88
99
  });
@@ -124,6 +135,8 @@ const UserSchema = z.object({
124
135
  ## Request Validation
125
136
 
126
137
  ```typescript
138
+ // Use an explicit status-code map (with jsonContent) when the success
139
+ // code is not 200 - jsonResponse() always keys the success response at 200
127
140
  export const RouteConfigs = {
128
141
  CREATE_USER: {
129
142
  method: HTTP.Methods.POST,
@@ -134,11 +147,16 @@ export const RouteConfigs = {
134
147
  description: 'User data',
135
148
  }),
136
149
  },
137
- responses: jsonResponse({
138
- [HTTP.ResultCodes.RS_2.Created]: UserSchema,
139
- [HTTP.ResultCodes.RS_4.BadRequest]: ErrorSchema,
140
- [HTTP.ResultCodes.RS_4.Conflict]: ErrorSchema,
141
- }),
150
+ responses: {
151
+ [HTTP.ResultCodes.RS_2.Created]: jsonContent({
152
+ description: 'Created user',
153
+ schema: UserSchema,
154
+ }),
155
+ ['4xx | 5xx']: jsonContent({
156
+ description: 'Error Response',
157
+ schema: ErrorSchema,
158
+ }),
159
+ },
142
160
  },
143
161
  } as const;
144
162
  ```
@@ -147,4 +165,4 @@ export const RouteConfigs = {
147
165
 
148
166
  - [API Usage Examples](../api-usage-examples) - Full API patterns
149
167
  - [Controllers Reference](../../references/base/controllers) - Controller API
150
- - [Swagger Component](../../extensions/components/swagger) - OpenAPI setup
168
+ - [Swagger Component](../../extensions/components/api-reference) - OpenAPI setup
@@ -1,6 +1,6 @@
1
1
  # Tooling Configuration
2
2
 
3
- Ignis provides centralized development configurations via the `@venizia/dev-configs` package.
3
+ IGNIS provides centralized development configurations via the `@venizia/dev-configs` package.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,7 +10,7 @@ bun add -d @venizia/dev-configs
10
10
 
11
11
  This package provides:
12
12
  - **ESLint rules** - Pre-configured for Node.js/TypeScript projects
13
- - **Prettier settings** - Consistent formatting across all Ignis projects
13
+ - **Prettier settings** - Consistent formatting across all IGNIS projects
14
14
  - **TypeScript configs** - Shared base and common configurations
15
15
 
16
16
  ## Prettier Configuration
@@ -29,8 +29,9 @@ export default prettierConfigs;
29
29
  | Setting | Value | Description |
30
30
  |---------|-------|-------------|
31
31
  | `bracketSpacing` | `true` | `{ foo: bar }` |
32
- | `singleQuote` | `false` | `"string"` (double quotes) |
32
+ | `singleQuote` | `true` | `'string'` (single quotes) |
33
33
  | `printWidth` | `100` | Maximum line length |
34
+ | `tabWidth` | `2` | 2-space indentation |
34
35
  | `trailingComma` | `'all'` | `[1, 2, 3,]` |
35
36
  | `arrowParens` | `'avoid'` | `x => x` not `(x) => x` |
36
37
  | `semi` | `true` | Semicolons required |
@@ -65,6 +66,7 @@ export default eslintConfigs;
65
66
  **Includes:**
66
67
  - Pre-configured rules for Node.js/TypeScript (via `@minimaltech/eslint-node`)
67
68
  - Disables `@typescript-eslint/no-explicit-any` by default
69
+ - Enforces mandatory braces: `curly: ['error', 'all']` and `unicorn/switch-case-braces: ['error', 'always']`
68
70
 
69
71
  **Customization:**
70
72
  ```javascript
@@ -113,9 +115,10 @@ Use the centralized TypeScript configs:
113
115
 
114
116
  | Option | Value | Purpose |
115
117
  |--------|-------|---------|
116
- | `target` | `ES2022` | Modern JavaScript features |
117
- | `experimentalDecorators` | `true` | Required for Ignis decorators |
118
+ | `target` | `ES2024` | Modern JavaScript features |
119
+ | `experimentalDecorators` | `true` | Required for IGNIS decorators |
118
120
  | `emitDecoratorMetadata` | `true` | Metadata reflection for DI |
121
+ | `useDefineForClassFields` | `false` | Decorator-compatible class fields |
119
122
  | `strict` | `true` | Strict type checking |
120
123
  | `skipLibCheck` | `true` | Faster compilation |
121
124
 
@@ -77,16 +77,17 @@ type RouteKey = keyof typeof RouteConfigs; // 'GET_USERS' | 'GET_USER_BY_ID'
77
77
 
78
78
  ```typescript
79
79
  export class DefaultCRUDRepository<
80
- Schema extends TTableSchemaWithId = TTableSchemaWithId
80
+ EntitySchema extends TTableSchemaWithId = TTableSchemaWithId
81
81
  > {
82
- // Schema is constrained to have an 'id' column
82
+ // EntitySchema is constrained to have an 'id' column
83
83
  }
84
84
 
85
85
  export interface IAuthService<
86
+ E extends Env = Env,
86
87
  SIRQ extends TSignInRequest = TSignInRequest,
87
88
  SIRS = AnyObject,
88
89
  > {
89
- signIn(context: Context, opts: SIRQ): Promise<SIRS>;
90
+ signIn(context: TContext<E>, opts: SIRQ): Promise<SIRS>;
90
91
  }
91
92
  ```
92
93
 
@@ -96,21 +97,21 @@ Use TypeScript method overloads when return types depend on input options:
96
97
 
97
98
  ```typescript
98
99
  class Repository<T, R> {
99
- // Overload 1: shouldReturn: false → data is null
100
- create(opts: { data: T; options: { shouldReturn: false } }): Promise<{ count: number; data: null }>;
100
+ // Overload 1: shouldReturn: false → no data returned
101
+ create(opts: { data: T; options: { shouldReturn: false } }): Promise<{ count: number; data: undefined | null }>;
101
102
  // Overload 2: shouldReturn: true (default) → data is R
102
103
  create(opts: { data: T; options?: { shouldReturn?: true } }): Promise<{ count: number; data: R }>;
103
104
  // Implementation signature
104
- create(opts: { data: T; options?: { shouldReturn?: boolean } }): Promise<{ count: number; data: R | null }> {
105
+ create(opts: { data: T; options?: { shouldReturn?: boolean } }): Promise<{ count: number; data: R | undefined | null }> {
105
106
  // implementation
106
107
  }
107
108
  }
108
109
 
109
110
  // Usage
110
- const result1 = await repo.create({ data: user, options: { shouldReturn: false } });
111
- // result1.data is typed as null
111
+ const result1 = await userRepository.create({ data: user, options: { shouldReturn: false } });
112
+ // result1.data is typed as undefined | null
112
113
 
113
- const result2 = await repo.create({ data: user });
114
+ const result2 = await userRepository.create({ data: user });
114
115
  // result2.data is typed as R (the entity type)
115
116
  ```
116
117
 
@@ -151,10 +152,10 @@ function processResult<T>(result: TResult<T>) {
151
152
  if (result.success) {
152
153
  // TypeScript knows result.data exists
153
154
  return result.data;
154
- } else {
155
- // TypeScript knows result.error exists
156
- throw new Error(result.error);
157
155
  }
156
+
157
+ // TypeScript knows result.error exists
158
+ throw getError({ message: result.error });
158
159
  }
159
160
  ```
160
161
 
@@ -1,6 +1,6 @@
1
1
  # Common Pitfalls
2
2
 
3
- Avoid these common mistakes when building Ignis applications.
3
+ Avoid these common mistakes when building IGNIS applications.
4
4
 
5
5
  ## 1. Forgetting to Register Resources
6
6
 
@@ -55,7 +55,7 @@ export class Application extends BaseApplication {
55
55
  })
56
56
 
57
57
  // ❌ BAD - typo in string (note: "Repository" is misspelled)
58
- @inject({ key: 'repositories.ConfigurationRepository' })
58
+ @inject({ key: 'repositories.ConfigurationRepositry' })
59
59
  ```
60
60
 
61
61
  ## 3. Business Logic in Controllers
@@ -66,7 +66,7 @@ export class Application extends BaseApplication {
66
66
 
67
67
  - **Bad:**
68
68
  ```typescript
69
- import { ApplicationError, getError } from '@venizia/ignis-helpers';
69
+ import { getError, HTTP } from '@venizia/ignis-helpers';
70
70
 
71
71
  // In a Controller
72
72
  async createUser(c: Context) {
@@ -79,7 +79,9 @@ export class Application extends BaseApplication {
79
79
  }
80
80
 
81
81
  const company = await this.companyRepository.findOrCreate(companyName);
82
- const user = await this.userRepository.create({ name, email, companyId: company.id });
82
+ const user = await this.userRepository.create({
83
+ data: { name, email, companyId: company.id },
84
+ });
83
85
 
84
86
  return c.json(user, HTTP.ResultCodes.RS_2.Ok);
85
87
  }
@@ -99,7 +101,7 @@ export class Application extends BaseApplication {
99
101
  // All the complex logic now resides in the service
100
102
  const existingUser = await this.userRepository.findByEmail(data.email);
101
103
  // ...
102
- return await this.userRepository.create(...);
104
+ return await this.userRepository.create({ data });
103
105
  }
104
106
  ```
105
107
 
@@ -142,7 +144,7 @@ This ensures that the route configuration object is treated as a readonly litera
142
144
 
143
145
  **Problem:** Attempting to update or delete all records without an explicit `where` condition.
144
146
 
145
- **Solution:** Ignis prevents accidental bulk data destruction. You must either provide a `where` condition or explicitly set `force: true`.
147
+ **Solution:** IGNIS prevents accidental bulk data destruction. You must either provide a `where` condition or explicitly set `force: true`.
146
148
 
147
149
  ```typescript
148
150
  // ❌ BAD - Will throw error
@@ -150,7 +152,8 @@ await userRepository.updateBy({
150
152
  data: { status: 'INACTIVE' },
151
153
  where: {}, // Empty where = targets ALL records
152
154
  });
153
- // Error: [updateBy] DENY to perform updateBy | Empty where condition
155
+ // Error: [_update] Entity: User | DENY to perform update | Empty where condition
156
+ // (updateBy is an alias that delegates to updateAll)
154
157
 
155
158
  // ✅ GOOD - Explicit where condition
156
159
  await userRepository.updateBy({
@@ -175,26 +178,27 @@ await userRepository.updateBy({
175
178
 
176
179
  **Error Message:**
177
180
  ```
178
- [UserRepository] Schema key mismatch | Entity name 'User' not found in connector.query | Available keys: [Configuration, Post]
181
+ [UserRepository] Schema key mismatch | Entity name 'User' not found in connector.query | Available keys: [Configuration, Post] | Ensure the model's TABLE_NAME matches the schema registration key
179
182
  ```
180
183
 
181
- **Solution:** Ensure your entity class name matches the table name in `pgTable()`:
184
+ **Solution:** The schema registration key follows the precedence `@model tableName metadata > static TABLE_NAME > class name`, while the repository looks the query interface up by the entity **class name**. Do not set `TABLE_NAME` (or `tableName` metadata) to a value that differs from the class name:
182
185
 
183
186
  ```typescript
184
- // ❌ BAD - Class name 'User' doesn't match table name 'users'
187
+ // ❌ BAD - Schema is registered under 'users', but looked up as 'User'
185
188
  @model({ type: 'entity' })
186
- export class User extends BaseEntity<typeof User.schema> {
187
- static override schema = pgTable('users', { /* ... */ }); // Lowercase 'users'
189
+ export class User extends BasePostgresEntity<typeof User.schema> {
190
+ static override TABLE_NAME = 'users'; // Differs from class name!
191
+ static override schema = pgTable('User', { /* ... */ });
188
192
  }
189
193
 
190
- // ✅ GOOD - Class name matches table name
194
+ // ✅ GOOD - No TABLE_NAME override; registration key defaults to the class name
191
195
  @model({ type: 'entity' })
192
- export class User extends BaseEntity<typeof User.schema> {
193
- static override schema = pgTable('User', { /* ... */ }); // Matches class name
196
+ export class User extends BasePostgresEntity<typeof User.schema> {
197
+ static override schema = pgTable('User', { /* ... */ });
194
198
  }
195
199
  ```
196
200
 
197
- **Why this matters:** The framework uses `entity.name` (class name) to look up the query interface in `connector.query`. If they don't match, the repository can't find its table.
201
+ **Why this matters:** The framework uses `entity.name` (class name) to look up the query interface in `connector.query`, but registers the schema under the resolved table name. If they don't match, the repository can't find its table. The first argument of `pgTable()` is the physical SQL table name and is independent of this lookup - by convention it matches the class name.
198
202
 
199
203
  ## 8. Validation Error Response Structure
200
204
 
@@ -205,9 +209,12 @@ export class User extends BaseEntity<typeof User.schema> {
205
209
  ```json
206
210
  {
207
211
  "statusCode": 422,
208
- "message": "ValidationError",
212
+ "message": "Invalid email",
213
+ "messageCode": "invalid_string",
209
214
  "requestId": "abc123",
210
215
  "details": {
216
+ "url": "http://localhost:3000/users",
217
+ "path": "/users",
211
218
  "cause": [
212
219
  {
213
220
  "path": "email",
@@ -252,10 +259,10 @@ try {
252
259
 
253
260
  ```typescript
254
261
  // ❌ BAD - Direct import causes circular dependency
255
- import { UserService } from './user.service';
262
+ import { User } from './user.model';
256
263
 
257
264
  @model({ type: 'entity' })
258
- export class Order extends BaseEntity<typeof Order.schema> {
265
+ export class Order extends BasePostgresEntity<typeof Order.schema> {
259
266
  static override relations = (): TRelationConfig[] => [
260
267
  { schema: User.schema, ... }, // User imports Order, Order imports User
261
268
  ];
@@ -263,7 +270,7 @@ export class Order extends BaseEntity<typeof Order.schema> {
263
270
 
264
271
  // ✅ GOOD - Lazy import breaks the cycle
265
272
  @model({ type: 'entity' })
266
- export class Order extends BaseEntity<typeof Order.schema> {
273
+ export class Order extends BasePostgresEntity<typeof Order.schema> {
267
274
  static override relations = (): TRelationConfig[] => {
268
275
  const { User } = require('./user.model'); // Lazy require
269
276
  return [{ schema: User.schema, ... }];
@@ -283,15 +290,15 @@ export class Order extends BaseEntity<typeof Order.schema> {
283
290
 
284
291
  ```typescript
285
292
  // ❌ BAD - No error handling
286
- const tx = await repo.beginTransaction();
287
- await repo.create({ data, options: { transaction: tx } });
293
+ const tx = await userRepository.beginTransaction();
294
+ await userRepository.create({ data, options: { transaction: tx } });
288
295
  await tx.commit(); // If create fails, commit is never called but neither is rollback
289
296
 
290
297
  // ✅ GOOD - Proper transaction handling
291
- const tx = await repo.beginTransaction();
298
+ const tx = await userRepository.beginTransaction();
292
299
  try {
293
- await repo.create({ data, options: { transaction: tx } });
294
- await otherRepo.update({ data: other, options: { transaction: tx } });
300
+ await userRepository.create({ data, options: { transaction: tx } });
301
+ await orderRepository.updateById({ id, data: other, options: { transaction: tx } });
295
302
  await tx.commit();
296
303
  } catch (error) {
297
304
  await tx.rollback();
@@ -342,40 +349,52 @@ async createOrder(c: Context) {
342
349
 
343
350
  **Problem:** Relations return empty arrays or `null` unexpectedly.
344
351
 
345
- **Cause:** Mismatch between `fields` and `references` in relation metadata.
352
+ **Cause:** Mismatch between `fields` and `references` in relation metadata (or defining them on the wrong side).
346
353
 
347
- **Solution:** Double-check that foreign keys point to the correct columns:
354
+ **Solution:** `fields`/`references` belong on the `RelationTypes.ONE` side (the entity holding the foreign key). The `RelationTypes.MANY` side only takes a `relationName` pointing at the matching `one` relation:
348
355
 
349
356
  ```typescript
350
- // ❌ BAD - fields and references swapped
357
+ // ❌ BAD - fields and references swapped on the ONE side (on Post)
351
358
  static override relations = (): TRelationConfig[] => [
352
359
  {
353
- name: 'posts',
354
- type: RelationTypes.MANY,
355
- schema: Post.schema,
360
+ name: 'author',
361
+ type: RelationTypes.ONE,
362
+ schema: User.schema,
356
363
  metadata: {
357
- fields: [Post.schema.authorId], // Wrong! This should be User.schema.id
358
- references: [User.schema.id], // Wrong! This should be Post.schema.authorId
364
+ fields: [User.schema.id], // Wrong! This should be Post.schema.authorId
365
+ references: [Post.schema.authorId], // Wrong! This should be User.schema.id
359
366
  },
360
367
  },
361
368
  ];
362
369
 
363
370
  // ✅ GOOD - Correct configuration
364
- // "User has many Posts where User.id = Post.authorId"
371
+ // On Post: "Post belongs to one User where Post.authorId = User.id"
372
+ static override relations = (): TRelationConfig[] => [
373
+ {
374
+ name: 'author',
375
+ type: RelationTypes.ONE,
376
+ schema: User.schema,
377
+ metadata: {
378
+ fields: [Post.schema.authorId], // Current entity's foreign key
379
+ references: [User.schema.id], // Related entity's key
380
+ },
381
+ },
382
+ ];
383
+
384
+ // On User: "User has many Posts" - MANY side references the one relation by name
365
385
  static override relations = (): TRelationConfig[] => [
366
386
  {
367
387
  name: 'posts',
368
388
  type: RelationTypes.MANY,
369
389
  schema: Post.schema,
370
390
  metadata: {
371
- fields: [User.schema.id], // Parent's key
372
- references: [Post.schema.authorId], // Child's foreign key
391
+ relationName: 'author', // Points to the 'one' relation name on Post
373
392
  },
374
393
  },
375
394
  ];
376
395
  ```
377
396
 
378
- **Rule of thumb:** `fields` is the key on the current entity, `references` is the key on the related entity.
397
+ **Rule of thumb:** on the `ONE` side, `fields` is the foreign key on the current entity, `references` is the key on the related entity. The `MANY` side only names its inverse relation.
379
398
 
380
399
  ## 13. Overwriting Data with Partial Updates
381
400
 
@@ -1,6 +1,6 @@
1
1
  # Contribution Workflow
2
2
 
3
- Guidelines for contributing to Ignis - help us maintain quality and streamline the process.
3
+ Guidelines for contributing to IGNIS - help us maintain quality and streamline the process.
4
4
 
5
5
  ## Git Branching Strategy
6
6
 
@@ -42,7 +42,7 @@ git remote add upstream https://github.com/VENIZIA-AI/ignis.git
42
42
 
43
43
  ## Package Build Order
44
44
 
45
- Ignis is a monorepo with interdependent packages. Understanding the dependency chain is critical for development:
45
+ IGNIS is a monorepo with interdependent packages. Understanding the dependency chain is critical for development:
46
46
 
47
47
  ```
48
48
  dev-configs → inversion → helpers → boot → core
@@ -97,7 +97,7 @@ make update-boot
97
97
  make update-helpers
98
98
  make update-inversion
99
99
  make update-dev-configs
100
- make update-docs
100
+ make update-docs-mcp
101
101
  ```
102
102
 
103
103
  ## 2. Development Workflow
@@ -107,8 +107,8 @@ make update-docs
107
107
  ```bash
108
108
  # Sync with upstream
109
109
  git fetch upstream
110
- git checkout main
111
- git merge upstream/main
110
+ git checkout develop
111
+ git merge upstream/develop
112
112
 
113
113
  # Create feature branch
114
114
  git checkout -b feature/your-feature-name
@@ -128,7 +128,7 @@ git checkout -b feature/your-feature-name
128
128
  - Follow [Code Style Standards](./code-style-standards/)
129
129
  - Follow [Architectural Patterns](./architectural-patterns.md)
130
130
  - Add tests for new features/fixes
131
- - Update docs in `packages/docs/wiki` if needed
131
+ - Update docs in `docs/wiki/content/` if needed
132
132
 
133
133
  ### Step 3: Commit
134
134
 
@@ -155,14 +155,13 @@ git commit -m "chore: upgrade Hono to v4.0"
155
155
  ```bash
156
156
  # Lint and format (from root)
157
157
  make lint
158
- # Or: bun run lint:fix
158
+ # Or run `bun run lint:fix` inside a package directory
159
159
 
160
- # Build all packages
160
+ # Build all packages (from root)
161
161
  make build
162
- # Or: bun run build
163
162
 
164
- # Run tests
165
- bun run test
163
+ # Run tests (from a package directory, e.g. packages/core or packages/boot)
164
+ cd packages/core && bun test
166
165
  ```
167
166
 
168
167
  ## 3. Submit Pull Request
@@ -187,7 +186,7 @@ git push origin feature/your-feature-name
187
186
  - Code is linted and formatted
188
187
  - Documentation updated
189
188
  - Commit messages follow conventions
190
- - Branch is up-to-date with `main`
189
+ - Branch is up-to-date with `develop`
191
190
 
192
191
  ## 4. Review Process
193
192
 
@@ -195,7 +194,7 @@ git push origin feature/your-feature-name
195
194
  1. Maintainer reviews your PR (usually within 2-3 days)
196
195
  2. Feedback or change requests may be provided
197
196
  3. Address feedback and push updates
198
- 4. Once approved, maintainer merges to `main`
197
+ 4. Once approved, maintainer merges to `develop`
199
198
 
200
199
  **Responding to feedback:**
201
200
  ```bash
@@ -205,4 +204,4 @@ git commit -m "fix: address review feedback"
205
204
  git push origin feature/your-feature-name
206
205
  ```
207
206
 
208
- **Thank you for contributing to Ignis!**
207
+ **Thank you for contributing to IGNIS!**