@venizia/ignis-docs 0.0.1-7 → 0.0.1-9

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 (27) hide show
  1. package/package.json +12 -12
  2. package/wiki/changelogs/2025-12-17-refactor.md +22 -0
  3. package/wiki/changelogs/2025-12-18-performance-optimizations.md +192 -0
  4. package/wiki/changelogs/2025-12-18-repository-validation-security.md +445 -0
  5. package/wiki/changelogs/index.md +22 -0
  6. package/wiki/changelogs/v0.0.1-7-initial-architecture.md +137 -0
  7. package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +278 -0
  8. package/wiki/get-started/5-minute-quickstart.md +1 -1
  9. package/wiki/get-started/best-practices/api-usage-examples.md +12 -8
  10. package/wiki/get-started/best-practices/common-pitfalls.md +2 -2
  11. package/wiki/get-started/best-practices/data-modeling.md +14 -20
  12. package/wiki/get-started/building-a-crud-api.md +60 -75
  13. package/wiki/get-started/core-concepts/controllers.md +14 -14
  14. package/wiki/get-started/core-concepts/persistent.md +110 -130
  15. package/wiki/get-started/quickstart.md +1 -1
  16. package/wiki/references/base/controllers.md +40 -16
  17. package/wiki/references/base/datasources.md +195 -33
  18. package/wiki/references/base/dependency-injection.md +5 -5
  19. package/wiki/references/base/models.md +398 -28
  20. package/wiki/references/base/repositories.md +475 -22
  21. package/wiki/references/components/authentication.md +224 -7
  22. package/wiki/references/components/health-check.md +1 -1
  23. package/wiki/references/components/swagger.md +1 -1
  24. package/wiki/references/helpers/inversion.md +8 -3
  25. package/wiki/references/src-details/core.md +6 -5
  26. package/wiki/references/src-details/inversion.md +4 -4
  27. package/wiki/references/utilities/request.md +16 -7
@@ -0,0 +1,445 @@
1
+ # Changelog - 2025-12-18
2
+
3
+ ## Repository Validation & Security Improvements
4
+
5
+ This update adds strict validation to the `@repository` decorator and fixes several security vulnerabilities in the filter operators.
6
+
7
+ ## Overview
8
+
9
+ - **@repository Decorator**: Now requires both `model` AND `dataSource` for schema auto-discovery
10
+ - **Constructor Validation**: First parameter must extend `AbstractDataSource` (enforced via reflection)
11
+ - **DataSource Auto-Discovery**: Schema is automatically built from `@repository` bindings - no manual merging needed!
12
+ - **Filter Security**: Fixed empty IN array bypass, invalid column handling, BETWEEN validation
13
+ - **PostgreSQL Compatibility**: REGEXP now uses PostgreSQL POSIX operators
14
+ - **UUID Generation**: Now uses native PostgreSQL `uuid` type with `gen_random_uuid()`
15
+
16
+ ## Breaking Changes
17
+
18
+ ### 1. Repository Constructor Signature Changed
19
+
20
+ **This is a major breaking change.** The constructor signature for all repository classes has changed.
21
+
22
+ **Before:**
23
+ ```typescript
24
+ constructor(opts: {
25
+ entityClass: TClass<BaseEntity<EntitySchema>>;
26
+ relations: { [relationName: string]: TRelationConfig };
27
+ dataSource: IDataSource;
28
+ })
29
+ ```
30
+
31
+ **After:**
32
+ ```typescript
33
+ constructor(ds?: IDataSource, opts?: { entityClass?: TClass<BaseEntity<EntitySchema>> })
34
+ ```
35
+
36
+ **Key changes:**
37
+ - DataSource is now the first parameter (auto-injected from `@repository` decorator)
38
+ - `relations` parameter removed - now auto-resolved from entity's static `relations` property
39
+ - Both parameters are optional when using `@repository` decorator with `model` and `dataSource`
40
+
41
+ **Migration:**
42
+ ```typescript
43
+ // Before
44
+ @repository({})
45
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
46
+ constructor(
47
+ @inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
48
+ ) {
49
+ super({
50
+ entityClass: User,
51
+ relations: userRelations.definitions,
52
+ dataSource: ds,
53
+ });
54
+ }
55
+ }
56
+
57
+ // After - Zero boilerplate
58
+ @repository({ model: User, dataSource: PostgresDataSource })
59
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
60
+ // No constructor needed!
61
+ }
62
+
63
+ // After - With explicit constructor
64
+ @repository({ model: User, dataSource: PostgresDataSource })
65
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
66
+ constructor(
67
+ @inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
68
+ ) {
69
+ super(ds); // Just pass dataSource, entity and relations auto-resolved
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### 2. @repository Decorator Requires Both `model` AND `dataSource`
75
+
76
+ **Before (would silently fail to register model):**
77
+ ```typescript
78
+ // ❌ This would not register User for schema auto-discovery
79
+ @repository({ model: User })
80
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
81
+ ```
82
+
83
+ **After (throws error):**
84
+ ```typescript
85
+ // Error: [@repository][UserRepository] Invalid metadata | Missing 'dataSource'
86
+ @repository({ model: User })
87
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
88
+
89
+ // ✅ Correct usage
90
+ @repository({ model: User, dataSource: PostgresDataSource })
91
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
92
+ ```
93
+
94
+ ### 2. Constructor First Parameter Must Be DataSource Type
95
+
96
+ When using explicit `@inject` in constructor, the first parameter **must** extend `AbstractDataSource`:
97
+
98
+ **Before (would work with wrong type):**
99
+ ```typescript
100
+ @repository({ model: User, dataSource: PostgresDataSource })
101
+ export class UserRepository extends ReadableRepository<typeof User.schema> {
102
+ constructor(
103
+ @inject({ key: 'datasources.PostgresDataSource' })
104
+ dataSource: any, // ❌ This would compile but is wrong
105
+ ) {
106
+ super(dataSource);
107
+ }
108
+ }
109
+ ```
110
+
111
+ **After (enforced at decorator time):**
112
+ ```typescript
113
+ @repository({ model: User, dataSource: PostgresDataSource })
114
+ export class UserRepository extends ReadableRepository<typeof User.schema> {
115
+ constructor(
116
+ @inject({ key: 'datasources.PostgresDataSource' })
117
+ dataSource: PostgresDataSource, // ✅ Must be concrete DataSource type
118
+ ) {
119
+ super(dataSource);
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### 3. Filter Column Validation
125
+
126
+ Invalid column names now throw errors instead of being silently ignored:
127
+
128
+ **Before:**
129
+ ```typescript
130
+ // Would silently ignore 'invalidColumn'
131
+ await repo.find({ filter: { where: { invalidColumn: 'value' } } });
132
+ ```
133
+
134
+ **After:**
135
+ ```typescript
136
+ // Error: [toWhere] Table: User | Column NOT FOUND | key: 'invalidColumn'
137
+ await repo.find({ filter: { where: { invalidColumn: 'value' } } });
138
+ ```
139
+
140
+ ## Security Fixes
141
+
142
+ ### Empty IN Array Bypass (CVE-like)
143
+
144
+ **Vulnerability:** Empty `IN` arrays would return `true`, bypassing security filters.
145
+
146
+ **Fix:** Empty `IN` arrays now return `sql\`false\``, correctly matching no records.
147
+
148
+ ```typescript
149
+ // Before: WHERE id IN () => true (security bypass!)
150
+ // After: WHERE false => no records (correct)
151
+ await repo.find({ filter: { where: { id: { IN: [] } } } });
152
+ ```
153
+
154
+ ### BETWEEN Validation
155
+
156
+ **Vulnerability:** Invalid `BETWEEN` values could cause unexpected behavior.
157
+
158
+ **Fix:** BETWEEN now validates input is array of exactly 2 elements.
159
+
160
+ ```typescript
161
+ // Throws: [BETWEEN] Invalid value: expected array of 2 elements
162
+ await repo.find({ filter: { where: { age: { BETWEEN: [10] } } } });
163
+ ```
164
+
165
+ ### PostgreSQL REGEXP Compatibility
166
+
167
+ **Issue:** MySQL-style REGEXP operator doesn't work in PostgreSQL.
168
+
169
+ **Fix:** Now uses PostgreSQL POSIX regex operators:
170
+ - `REGEXP` → `~` (case-sensitive)
171
+ - `IREGEXP` → `~*` (case-insensitive, new!)
172
+
173
+ ```typescript
174
+ // PostgreSQL-compatible regex
175
+ await repo.find({ filter: { where: { name: { REGEXP: '^John' } } } });
176
+ await repo.find({ filter: { where: { name: { IREGEXP: '^john' } } } }); // Case-insensitive
177
+ ```
178
+
179
+ ## New Features
180
+
181
+ ### DataSource Schema Auto-Discovery
182
+
183
+ DataSources can now automatically discover their schema from registered `@repository` decorators:
184
+
185
+ ```typescript
186
+ // Before: Manual schema merging required
187
+ @datasource({ driver: 'node-postgres' })
188
+ export class PostgresDataSource extends BaseDataSource<...> {
189
+ constructor() {
190
+ super({
191
+ name: PostgresDataSource.name,
192
+ config: { /* ... */ },
193
+ schema: Object.assign({}, // Manual merge!
194
+ { [User.TABLE_NAME]: userTable },
195
+ userRelations.relations,
196
+ ),
197
+ });
198
+ }
199
+ }
200
+
201
+ // After: Auto-discovery - no schema needed!
202
+ @datasource({ driver: 'node-postgres' })
203
+ export class PostgresDataSource extends BaseDataSource<...> {
204
+ constructor() {
205
+ super({
206
+ name: PostgresDataSource.name,
207
+ config: { /* ... */ },
208
+ // Schema auto-discovered from @repository decorators!
209
+ });
210
+ }
211
+ }
212
+ ```
213
+
214
+ When repositories are defined with `@repository({ model: User, dataSource: PostgresDataSource })`, the framework automatically builds the schema.
215
+
216
+ ### Schema Key Mismatch Validation
217
+
218
+ Added helpful error when entity name doesn't match schema keys:
219
+
220
+ ```typescript
221
+ // Error: [UserRepository] Schema key mismatch | Entity name 'User' not found in connector.query | Available keys: [Configuration, Post]
222
+ ```
223
+
224
+ ### UUID Type Improvement
225
+
226
+ Changed from `text` type with JS-generated UUID to native PostgreSQL `uuid`:
227
+
228
+ ```typescript
229
+ // Before: text('id').primaryKey().$defaultFn(() => crypto.randomUUID())
230
+ // After: uuid('id').defaultRandom().primaryKey()
231
+ ```
232
+
233
+ Benefits:
234
+ - Native PostgreSQL UUID type (16 bytes vs 36 bytes)
235
+ - Uses `gen_random_uuid()` - no extension required
236
+ - Better indexing performance
237
+
238
+ ### Case-Insensitive REGEXP (IREGEXP)
239
+
240
+ Added new `IREGEXP` operator for case-insensitive regex matching:
241
+
242
+ ```typescript
243
+ // Case-sensitive (existing)
244
+ await repo.find({ filter: { where: { name: { REGEXP: '^John' } } } });
245
+
246
+ // Case-insensitive (new!)
247
+ await repo.find({ filter: { where: { name: { IREGEXP: '^john' } } } });
248
+ ```
249
+
250
+ ### BaseEntity Static Schema & Relations
251
+
252
+ Models can now define schema and relations as static properties, enabling cleaner syntax:
253
+
254
+ ```typescript
255
+ // Before - Constructor-based schema
256
+ @model({ type: 'entity' })
257
+ export class User extends BaseEntity<typeof userTable> {
258
+ constructor() {
259
+ super({ name: 'User', schema: userTable });
260
+ }
261
+ }
262
+
263
+ // After - Static schema (recommended)
264
+ @model({ type: 'entity' })
265
+ export class User extends BaseEntity<typeof User.schema> {
266
+ static override schema = userTable;
267
+ static override relations = () => userRelations.definitions;
268
+ static override TABLE_NAME = 'User';
269
+ }
270
+ ```
271
+
272
+ Relations are now auto-resolved from the entity's static `relations` property - no need to pass them in repository constructor.
273
+
274
+ ### Repository Log Option
275
+
276
+ All CRUD operations now support a `log` option for debugging:
277
+
278
+ ```typescript
279
+ // Enable logging for a specific operation
280
+ await repo.create({
281
+ data: { name: 'John' },
282
+ options: {
283
+ log: { use: true, level: 'debug' }
284
+ }
285
+ });
286
+
287
+ // Log output: [_create] Executing with opts: { data: [...], options: {...} }
288
+ ```
289
+
290
+ **Available on:** `create`, `createAll`, `updateById`, `updateAll`, `deleteById`, `deleteAll`
291
+
292
+ ### Improved TypeScript Return Types
293
+
294
+ Repository methods now have better type inference based on `shouldReturn`:
295
+
296
+ ```typescript
297
+ // When shouldReturn: false - returns null
298
+ const result1 = await repo.create({
299
+ data: { name: 'John' },
300
+ options: { shouldReturn: false }
301
+ });
302
+ // Type: Promise<TCount & { data: null }>
303
+
304
+ // When shouldReturn: true (default) - returns the entity
305
+ const result2 = await repo.create({
306
+ data: { name: 'John' },
307
+ options: { shouldReturn: true }
308
+ });
309
+ // Type: Promise<TCount & { data: User }>
310
+
311
+ // TypeScript now correctly infers the return type!
312
+ ```
313
+
314
+ ### IEntity Interface
315
+
316
+ New interface for model classes with static schema and relations:
317
+
318
+ ```typescript
319
+ interface IEntity<Schema extends TTableSchemaWithId = TTableSchemaWithId> {
320
+ TABLE_NAME?: string;
321
+ schema: Schema;
322
+ relations?: TValueOrResolver<Array<TRelationConfig>>;
323
+ }
324
+ ```
325
+
326
+ ## Files Changed
327
+
328
+ ### Core Package - Models
329
+ - `packages/core/src/base/models/base.ts` - Static schema/relations support, IEntity interface
330
+ - `packages/core/src/base/models/common/types.ts` - IEntity interface definition
331
+ - `packages/core/src/base/models/enrichers/id.enricher.ts` - Native PostgreSQL UUID type
332
+ - `packages/core/src/base/models/enrichers/tz.enricher.ts` - Type naming fix
333
+
334
+ ### Core Package - Repositories
335
+ - `packages/core/src/base/repositories/core/base.ts` - Constructor signature change, relations auto-resolution
336
+ - `packages/core/src/base/repositories/core/readable.ts` - Constructor change, getQueryInterface validation
337
+ - `packages/core/src/base/repositories/core/persistable.ts` - Constructor change, log option, TypeScript overloads
338
+ - `packages/core/src/base/repositories/core/default-crud.ts` - Documentation update
339
+ - `packages/core/src/base/repositories/common/types.ts` - TRepositoryLogOptions, TypeScript overloads
340
+ - `packages/core/src/base/repositories/operators/filter.ts` - Column validation, error throwing
341
+ - `packages/core/src/base/repositories/operators/query.ts` - REGEXP/IREGEXP fix, BETWEEN validation, IN empty array fix
342
+
343
+ ### Core Package - DataSources & Metadata
344
+ - `packages/core/src/base/datasources/base.ts` - Schema auto-discovery feature
345
+ - `packages/core/src/base/metadata/persistents.ts` - Repository decorator validation, constructor type validation
346
+
347
+ ### Examples
348
+ - `examples/vert/src/repositories/user.repository.ts` - Updated to proper types
349
+ - `examples/vert/src/repositories/configuration.repository.ts` - Updated patterns
350
+ - `examples/vert/src/datasources/postgres.datasource.ts` - Using auto-discovery
351
+ - `examples/vert/src/models/entities/user.model.ts` - Static schema pattern
352
+ - `examples/vert/src/models/entities/configuration.model.ts` - Static schema pattern
353
+
354
+ ## Migration Guide
355
+
356
+ ### Step 1: Update Repository Constructors (BREAKING)
357
+
358
+ The repository constructor signature has changed:
359
+
360
+ ```typescript
361
+ // Before
362
+ @repository({})
363
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
364
+ constructor(
365
+ @inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
366
+ ) {
367
+ super({
368
+ entityClass: User,
369
+ relations: userRelations.definitions,
370
+ dataSource: ds,
371
+ });
372
+ }
373
+ }
374
+
375
+ // After - Option A: Zero boilerplate (recommended)
376
+ @repository({ model: User, dataSource: PostgresDataSource })
377
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
378
+ // No constructor needed!
379
+ }
380
+
381
+ // After - Option B: With explicit constructor
382
+ @repository({ model: User, dataSource: PostgresDataSource })
383
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
384
+ constructor(
385
+ @inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
386
+ ) {
387
+ super(ds); // Just pass dataSource
388
+ }
389
+ }
390
+ ```
391
+
392
+ ### Step 2: Update Model Definitions (Optional but Recommended)
393
+
394
+ Add static properties to your models for relations auto-resolution:
395
+
396
+ ```typescript
397
+ // Before
398
+ @model({ type: 'entity' })
399
+ export class User extends BaseEntity<typeof userTable> {
400
+ constructor() {
401
+ super({ name: 'User', schema: userTable });
402
+ }
403
+ }
404
+
405
+ // After - Static properties
406
+ @model({ type: 'entity' })
407
+ export class User extends BaseEntity<typeof User.schema> {
408
+ static override schema = userTable;
409
+ static override relations = () => userRelations.definitions;
410
+ static override TABLE_NAME = 'User';
411
+ }
412
+ ```
413
+
414
+ ### Step 3: Update @repository Decorators
415
+
416
+ Ensure all `@repository` decorators have both `model` and `dataSource`:
417
+
418
+ ```typescript
419
+ // Find and update all occurrences
420
+ @repository({ model: YourModel, dataSource: YourDataSource })
421
+ ```
422
+
423
+ ### Step 4: Fix Constructor Types
424
+
425
+ If using explicit `@inject`, ensure first parameter has correct type:
426
+
427
+ ```typescript
428
+ constructor(
429
+ @inject({ key: 'datasources.YourDataSource' })
430
+ dataSource: YourDataSource, // Not 'any' or 'object'
431
+ ) {}
432
+ ```
433
+
434
+ ### Step 5: Review Filter Queries
435
+
436
+ Check for any queries using:
437
+ - Empty `IN` arrays (now return no results instead of all)
438
+ - Invalid column names (now throw errors)
439
+ - `BETWEEN` with non-array or wrong-length values
440
+
441
+ ### Step 6: REGEXP Migration (PostgreSQL Users)
442
+
443
+ Replace MySQL-style REGEXP with PostgreSQL syntax:
444
+ - REGEXP already works (uses `~` operator)
445
+ - For case-insensitive, use new `IREGEXP` (uses `~*` operator)
@@ -0,0 +1,22 @@
1
+ # Changelogs
2
+
3
+ This section tracks the history of significant changes, refactors, and updates to the Ignis framework.
4
+
5
+ ## Version History
6
+
7
+ | Version | Date | Description |
8
+ |---------|------|-------------|
9
+ | [2025-12-18 Performance](./2025-12-18-performance-optimizations.md) | 2025-12-18 | Performance Optimizations (Core API, WeakMap Cache) |
10
+ | [2025-12-18](./2025-12-18-repository-validation-security.md) | 2025-12-18 | Repository Validation & Security Improvements |
11
+ | [2025-12-17](./2025-12-17-refactor.md) | 2025-12-17 | Inversion of Control Refactor |
12
+ | [v0.0.1-8](./v0.0.1-8-model-repo-datasource-refactor.md) | 2025-12-16 | Model-Repository-DataSource Architecture Refactor |
13
+ | [v0.0.1-7](./v0.0.1-7-initial-architecture.md) | 2025-12-16 | Initial Architecture (Pre-Refactor) |
14
+
15
+ ## How to Read Changelogs
16
+
17
+ Each changelog entry includes:
18
+ - **Overview**: Summary of changes
19
+ - **Breaking Changes**: Any changes that require migration
20
+ - **New Features**: New capabilities added
21
+ - **Files Changed**: List of modified files
22
+ - **Migration Guide**: Steps to update existing code (if applicable)
@@ -0,0 +1,137 @@
1
+ # v0.0.1-7 - Initial Architecture (Pre-Refactor)
2
+
3
+ **Release Date**: 2025-12-16
4
+ **Status**: Superseded by v0.0.1-8
5
+
6
+ ## Overview
7
+
8
+ This documents the original architecture of the Ignis framework before the Model-Repository-DataSource refactor. This version required manual schema registration and explicit constructor parameters.
9
+
10
+ ## Architecture Pattern
11
+
12
+ ### Model Definition
13
+
14
+ Models were defined in three separate steps:
15
+
16
+ ```typescript
17
+ // Step 1: Define table schema
18
+ const TABLE_NAME = 'Configuration';
19
+
20
+ export const configurationTable = pgTable(TABLE_NAME, {
21
+ ...generateIdColumnDefs({ id: { dataType: 'string' } }),
22
+ ...generateTzColumnDefs(),
23
+ code: text('code').notNull(),
24
+ group: text('group').notNull(),
25
+ });
26
+
27
+ // Step 2: Define relations separately
28
+ export const configurationRelations = createRelations({
29
+ source: configurationTable,
30
+ relations: [
31
+ {
32
+ name: 'creator',
33
+ type: RelationTypes.ONE,
34
+ schema: userTable,
35
+ metadata: {
36
+ fields: [configurationTable.createdBy],
37
+ references: [userTable.id],
38
+ },
39
+ },
40
+ ],
41
+ });
42
+
43
+ // Step 3: Create model class
44
+ @model({ type: 'entity', skipMigrate: false })
45
+ export class Configuration extends BaseEntity<typeof configurationTable> {
46
+ static readonly TABLE_NAME = Configuration.name;
47
+
48
+ constructor() {
49
+ super({
50
+ name: Configuration.TABLE_NAME,
51
+ schema: configurationTable,
52
+ });
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### DataSource Definition
58
+
59
+ DataSources required manual schema registration:
60
+
61
+ ```typescript
62
+ @datasource({})
63
+ export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
64
+ constructor() {
65
+ super({
66
+ name: PostgresDataSource.name,
67
+ driver: 'node-postgres',
68
+ config: { /* connection config */ },
69
+
70
+ // Manual schema registration - verbose and error-prone
71
+ schema: Object.assign(
72
+ {},
73
+ {
74
+ [User.TABLE_NAME]: userTable,
75
+ [Configuration.TABLE_NAME]: configurationTable,
76
+ },
77
+ {
78
+ userRelations: userRelations.relations,
79
+ configurationRelations: configurationRelations.relations,
80
+ },
81
+ ),
82
+ });
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### Repository Definition
88
+
89
+ Repositories required explicit constructor injection:
90
+
91
+ ```typescript
92
+ @repository({})
93
+ export class ConfigurationRepository extends DefaultCRUDRepository<typeof configurationTable> {
94
+ constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
95
+ super({
96
+ dataSource,
97
+ entityClass: Configuration,
98
+ relations: configurationRelations.definitions,
99
+ });
100
+ }
101
+ }
102
+ ```
103
+
104
+ ## Pain Points
105
+
106
+ 1. **Verbose Model Definition**: Three separate declarations (table, relations, class) for each model
107
+ 2. **Manual Schema Registration**: DataSource required explicit registration of every model and relation
108
+ 3. **Unclear Repository Role**: Repository just wrapped datasource without defining the model-datasource binding
109
+ 4. **Declaration Order Issues**: Had to declare table before relations, relations before class
110
+ 5. **No Auto-Discovery**: Adding a new model required updates in multiple places
111
+ 6. **Tight Coupling**: Changes to model structure required updates in datasource configuration
112
+
113
+ ## File Structure
114
+
115
+ ```
116
+ src/
117
+ ├── models/
118
+ │ └── entities/
119
+ │ ├── user.model.ts # Table + Relations + Class
120
+ │ └── configuration.model.ts # Table + Relations + Class
121
+ ├── datasources/
122
+ │ └── postgres.datasource.ts # Manual schema assembly
123
+ └── repositories/
124
+ ├── user.repository.ts # Explicit constructor injection
125
+ └── configuration.repository.ts
126
+ ```
127
+
128
+ ## Dependencies
129
+
130
+ - `@venizia/ignis-helpers`: Core utilities and types
131
+ - `@venizia/ignis-inversion`: Dependency injection
132
+ - `drizzle-orm`: ORM layer
133
+ - `drizzle-zod`: Schema validation
134
+
135
+ ---
136
+
137
+ *This architecture was superseded by the Loopback 4-style refactor in v0.0.1-8*