@venizia/ignis-docs 0.0.3 → 0.0.4-1

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 (131) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -2
  3. package/wiki/best-practices/api-usage-examples.md +591 -0
  4. package/wiki/best-practices/architectural-patterns.md +415 -0
  5. package/wiki/best-practices/architecture-decisions.md +488 -0
  6. package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
  7. package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
  8. package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
  9. package/wiki/best-practices/data-modeling.md +376 -0
  10. package/wiki/best-practices/deployment-strategies.md +698 -0
  11. package/wiki/best-practices/index.md +27 -0
  12. package/wiki/best-practices/performance-optimization.md +196 -0
  13. package/wiki/best-practices/security-guidelines.md +218 -0
  14. package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
  15. package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
  16. package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
  17. package/wiki/changelogs/2025-12-17-refactor.md +1 -1
  18. package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
  19. package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
  20. package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
  21. package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
  22. package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
  23. package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
  24. package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
  25. package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
  26. package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
  27. package/wiki/changelogs/index.md +6 -0
  28. package/wiki/changelogs/planned-schema-migrator.md +0 -8
  29. package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
  30. package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
  31. package/wiki/guides/core-concepts/components-guide.md +509 -0
  32. package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
  33. package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
  34. package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
  35. package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
  36. package/wiki/guides/core-concepts/persistent/index.md +119 -0
  37. package/wiki/guides/core-concepts/persistent/models.md +241 -0
  38. package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
  39. package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
  40. package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
  41. package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
  42. package/wiki/guides/get-started/philosophy.md +682 -0
  43. package/wiki/guides/get-started/setup.md +157 -0
  44. package/wiki/guides/index.md +89 -0
  45. package/wiki/guides/reference/glossary.md +243 -0
  46. package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
  47. package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
  48. package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
  49. package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
  50. package/wiki/guides/tutorials/realtime-chat.md +1261 -0
  51. package/wiki/guides/tutorials/testing.md +723 -0
  52. package/wiki/index.md +176 -37
  53. package/wiki/references/base/application.md +27 -0
  54. package/wiki/references/base/bootstrapping.md +31 -26
  55. package/wiki/references/base/components.md +24 -7
  56. package/wiki/references/base/controllers.md +50 -20
  57. package/wiki/references/base/datasources.md +30 -0
  58. package/wiki/references/base/dependency-injection.md +39 -3
  59. package/wiki/references/base/filter-system/application-usage.md +224 -0
  60. package/wiki/references/base/filter-system/array-operators.md +132 -0
  61. package/wiki/references/base/filter-system/comparison-operators.md +109 -0
  62. package/wiki/references/base/filter-system/default-filter.md +428 -0
  63. package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
  64. package/wiki/references/base/filter-system/index.md +127 -0
  65. package/wiki/references/base/filter-system/json-filtering.md +197 -0
  66. package/wiki/references/base/filter-system/list-operators.md +71 -0
  67. package/wiki/references/base/filter-system/logical-operators.md +156 -0
  68. package/wiki/references/base/filter-system/null-operators.md +58 -0
  69. package/wiki/references/base/filter-system/pattern-matching.md +108 -0
  70. package/wiki/references/base/filter-system/quick-reference.md +431 -0
  71. package/wiki/references/base/filter-system/range-operators.md +63 -0
  72. package/wiki/references/base/filter-system/tips.md +190 -0
  73. package/wiki/references/base/filter-system/use-cases.md +452 -0
  74. package/wiki/references/base/index.md +90 -0
  75. package/wiki/references/base/middlewares.md +604 -0
  76. package/wiki/references/base/models.md +215 -23
  77. package/wiki/references/base/providers.md +731 -0
  78. package/wiki/references/base/repositories/advanced.md +555 -0
  79. package/wiki/references/base/repositories/index.md +228 -0
  80. package/wiki/references/base/repositories/mixins.md +331 -0
  81. package/wiki/references/base/repositories/relations.md +486 -0
  82. package/wiki/references/base/repositories.md +40 -635
  83. package/wiki/references/base/services.md +28 -4
  84. package/wiki/references/components/authentication.md +22 -2
  85. package/wiki/references/components/health-check.md +12 -0
  86. package/wiki/references/components/index.md +23 -0
  87. package/wiki/references/components/mail.md +687 -0
  88. package/wiki/references/components/request-tracker.md +16 -0
  89. package/wiki/references/components/socket-io.md +18 -0
  90. package/wiki/references/components/static-asset.md +14 -26
  91. package/wiki/references/components/swagger.md +17 -0
  92. package/wiki/references/configuration/environment-variables.md +427 -0
  93. package/wiki/references/configuration/index.md +73 -0
  94. package/wiki/references/helpers/cron.md +14 -0
  95. package/wiki/references/helpers/crypto.md +15 -0
  96. package/wiki/references/helpers/env.md +16 -0
  97. package/wiki/references/helpers/error.md +17 -0
  98. package/wiki/references/helpers/index.md +14 -0
  99. package/wiki/references/helpers/inversion.md +24 -4
  100. package/wiki/references/helpers/logger.md +19 -0
  101. package/wiki/references/helpers/network.md +11 -0
  102. package/wiki/references/helpers/queue.md +19 -0
  103. package/wiki/references/helpers/redis.md +21 -0
  104. package/wiki/references/helpers/socket-io.md +24 -5
  105. package/wiki/references/helpers/storage.md +18 -10
  106. package/wiki/references/helpers/testing.md +18 -0
  107. package/wiki/references/helpers/types.md +16 -0
  108. package/wiki/references/helpers/uid.md +167 -0
  109. package/wiki/references/helpers/worker-thread.md +16 -0
  110. package/wiki/references/index.md +177 -0
  111. package/wiki/references/quick-reference.md +634 -0
  112. package/wiki/references/src-details/boot.md +3 -3
  113. package/wiki/references/src-details/dev-configs.md +0 -4
  114. package/wiki/references/src-details/docs.md +2 -2
  115. package/wiki/references/src-details/index.md +86 -0
  116. package/wiki/references/src-details/inversion.md +1 -6
  117. package/wiki/references/src-details/mcp-server.md +3 -15
  118. package/wiki/references/utilities/index.md +86 -10
  119. package/wiki/references/utilities/jsx.md +577 -0
  120. package/wiki/references/utilities/request.md +0 -2
  121. package/wiki/references/utilities/statuses.md +740 -0
  122. package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
  123. package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
  124. package/wiki/get-started/best-practices/data-modeling.md +0 -177
  125. package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
  126. package/wiki/get-started/best-practices/performance-optimization.md +0 -97
  127. package/wiki/get-started/best-practices/security-guidelines.md +0 -99
  128. package/wiki/get-started/core-concepts/persistent.md +0 -539
  129. package/wiki/get-started/index.md +0 -65
  130. package/wiki/get-started/philosophy.md +0 -296
  131. package/wiki/get-started/prerequisites.md +0 -113
@@ -1,3 +1,9 @@
1
+ ---
2
+ title: Models & Enrichers Reference
3
+ description: Technical reference for model architecture and schema enrichers
4
+ difficulty: intermediate
5
+ ---
6
+
1
7
  # Deep Dive: Models and Enrichers
2
8
 
3
9
  Technical reference for model architecture and schema enrichers in Ignis.
@@ -29,6 +35,145 @@ Fundamental building block wrapping a Drizzle ORM schema.
29
35
  | **Static Properties** | Supports static `schema`, `relations`, and `TABLE_NAME` for cleaner syntax |
30
36
  | **Convenience** | Includes `toObject()` and `toJSON()` methods |
31
37
 
38
+ ### The `@model` Decorator
39
+
40
+ The `@model` decorator marks a class as a database entity and configures its behavior.
41
+
42
+ #### Decorator Options
43
+
44
+ ```typescript
45
+ @model({
46
+ type: 'entity' | 'view',
47
+ tableName?: string,
48
+ skipMigrate?: boolean,
49
+ settings?: {
50
+ hiddenProperties?: string[], // Properties to exclude from query results
51
+ defaultFilter?: TFilter, // Filter applied to all repository queries
52
+ }
53
+ })
54
+ ```
55
+
56
+ | Option | Type | Description |
57
+ |--------|------|-------------|
58
+ | `type` | `'entity' \| 'view'` | Entity type - `'entity'` for tables, `'view'` for database views |
59
+ | `tableName` | `string` | Optional custom table name (defaults to class name) |
60
+ | `skipMigrate` | `boolean` | Skip this model during schema migrations |
61
+ | `settings.hiddenProperties` | `string[]` | Array of property names to exclude from all repository query results |
62
+ | `settings.defaultFilter` | `TFilter` | Filter automatically applied to all repository queries (see [Default Filter](/references/base/filter-system/default-filter)) |
63
+
64
+ ### Hidden Properties
65
+
66
+ Hidden properties are **excluded at the SQL level** - they are never fetched from the database when querying through repositories. This provides:
67
+
68
+ - **Security**: Sensitive data like passwords are never accidentally exposed
69
+ - **Performance**: Less data transferred from database
70
+ - **Consistency**: Hidden properties are excluded from ALL repository operations
71
+
72
+ ```typescript
73
+ import { pgTable, text } from 'drizzle-orm/pg-core';
74
+ import { BaseEntity, model, generateIdColumnDefs } from '@venizia/ignis';
75
+
76
+ @model({
77
+ type: 'entity',
78
+ settings: {
79
+ hiddenProperties: ['password', 'secret'], // Never returned via repository
80
+ },
81
+ })
82
+ export class User extends BaseEntity<typeof User.schema> {
83
+ static override schema = pgTable('User', {
84
+ ...generateIdColumnDefs({ id: { dataType: 'string' } }),
85
+ email: text('email').notNull(),
86
+ password: text('password'), // Hidden - never in query results
87
+ secret: text('secret'), // Hidden - never in query results
88
+ });
89
+ }
90
+ ```
91
+
92
+ #### Behavior
93
+
94
+ | Operation | Hidden Properties |
95
+ |-----------|-------------------|
96
+ | `find()`, `findOne()`, `findById()` | Excluded from SELECT |
97
+ | `create()`, `createAll()` | Excluded from RETURNING |
98
+ | `updateById()`, `updateAll()` | Excluded from RETURNING |
99
+ | `deleteById()`, `deleteAll()` | Excluded from RETURNING |
100
+ | `count()`, `existsWith()` | Can filter by hidden fields |
101
+ | Direct connector query | **Included** (bypasses repository) |
102
+
103
+ #### Important Notes
104
+
105
+ - Hidden properties can still be used in `where` clauses for filtering
106
+ - Data is still **stored** in the database - only excluded from query results
107
+ - Use direct connector queries when you need to access hidden data:
108
+
109
+ ```typescript
110
+ // Repository query - password/secret NOT included
111
+ const user = await userRepo.findById({ id: '123' });
112
+ // user = { id: '123', email: 'john@example.com' }
113
+
114
+ // Direct connector query - ALL fields included
115
+ const connector = userRepo.getConnector();
116
+ const [fullUser] = await connector
117
+ .select()
118
+ .from(User.schema)
119
+ .where(eq(User.schema.id, '123'));
120
+ // fullUser = { id: '123', email: 'john@example.com', password: 'hashed...', secret: '...' }
121
+ ```
122
+
123
+ ### Default Filter
124
+
125
+ Default filters are **automatically applied** to all repository queries for a model. This is useful for:
126
+
127
+ - **Soft Delete**: Automatically exclude deleted records
128
+ - **Multi-Tenancy**: Isolate data by tenant
129
+ - **Active Records**: Filter to active/non-expired records
130
+ - **Query Limits**: Prevent unbounded queries
131
+
132
+ ```typescript
133
+ @model({
134
+ type: 'entity',
135
+ settings: {
136
+ defaultFilter: {
137
+ where: { isDeleted: false }, // Applied to all queries
138
+ limit: 100, // Prevents unbounded queries
139
+ },
140
+ },
141
+ })
142
+ export class Post extends BaseEntity<typeof Post.schema> {
143
+ static override schema = postTable;
144
+ }
145
+ ```
146
+
147
+ #### Behavior
148
+
149
+ | Operation | Default Filter |
150
+ |-----------|----------------|
151
+ | `find()`, `findOne()`, `findById()` | Applied to WHERE clause |
152
+ | `count()`, `existsWith()` | Applied to WHERE clause |
153
+ | `updateById()`, `updateAll()` | Applied to WHERE clause |
154
+ | `deleteById()`, `deleteAll()` | Applied to WHERE clause |
155
+ | `create()`, `createAll()` | **Not applied** |
156
+
157
+ #### Bypassing
158
+
159
+ Use `shouldSkipDefaultFilter: true` to bypass:
160
+
161
+ ```typescript
162
+ // Normal query - includes default filter
163
+ await postRepo.find({ filter: {} });
164
+ // WHERE isDeleted = false LIMIT 100
165
+
166
+ // Admin query - bypass default filter
167
+ await postRepo.find({
168
+ filter: {},
169
+ options: { shouldSkipDefaultFilter: true }
170
+ });
171
+ // No WHERE clause (includes deleted)
172
+ ```
173
+
174
+ > [!TIP]
175
+ > See [Default Filter](/references/base/filter-system/default-filter) for full documentation including merge strategies and common patterns.
176
+
32
177
  ### Definition Patterns
33
178
 
34
179
  `BaseEntity` supports two patterns for defining models:
@@ -185,7 +330,7 @@ Enrichers are helper functions located in `packages/core/src/base/models/enriche
185
330
  | **`generateUserAuditColumnDefs`** | Adds `createdBy` and `modifiedBy` columns to track user audit information. |
186
331
  | **`generateDataTypeColumnDefs`** | Adds generic data type columns (`dataType`, `nValue`, `tValue`, `bValue`, `jValue`, `boValue`) for flexible data storage. |
187
332
  | **`generatePrincipalColumnDefs`** | Adds polymorphic fields for associating with different principal types. |
188
- | **`extraUserColumns`** (from `components/auth/models/entities/user.model.ts`) | Adds common fields for a user model, such as `realm`, `status`, `type`, `activatedAt`, `lastLoginAt`, and `parentId`. |
333
+ | **`extraUserColumns`** | Adds common fields for a user model, such as `realm`, `status`, `type`, `activatedAt`, `lastLoginAt`, and `parentId`. Import from `@venizia/ignis`. |
189
334
 
190
335
  ### Example Usage
191
336
 
@@ -205,7 +350,6 @@ export const myTable = pgTable('MyTable', {
205
350
  });
206
351
  ```
207
352
 
208
- ---
209
353
 
210
354
  ## Detailed Enricher Reference
211
355
 
@@ -228,7 +372,7 @@ generateIdColumnDefs<Opts extends TIdEnricherOptions | undefined>(
228
372
  ```typescript
229
373
  type TIdEnricherOptions = {
230
374
  id?: { columnName?: string } & (
231
- | { dataType: 'string' }
375
+ | { dataType: 'string'; generator?: () => string } // Optional custom ID generator
232
376
  | {
233
377
  dataType: 'number';
234
378
  sequenceOptions?: PgSequenceOptions;
@@ -250,7 +394,7 @@ type TIdEnricherOptions = {
250
394
 
251
395
  | Data Type | Column Type | Constraints | Description |
252
396
  |-----------|------------|-------------|-------------|
253
- | `'string'` | `uuid` | Primary Key, Default: `gen_random_uuid()` | Native PostgreSQL UUID (no extension required) |
397
+ | `'string'` | `text` | Primary Key, Default: `crypto.randomUUID()` | Text column with customizable ID generator (default: UUID) |
254
398
  | `'number'` | `integer` | Primary Key, `GENERATED ALWAYS AS IDENTITY` | Auto-incrementing integer |
255
399
  | `'big-number'` | `bigint` | Primary Key, `GENERATED ALWAYS AS IDENTITY` | Auto-incrementing big integer (mode: 'number' or 'bigint') |
256
400
 
@@ -259,18 +403,27 @@ type TIdEnricherOptions = {
259
403
  The function provides **full TypeScript type inference** based on the configuration options:
260
404
 
261
405
  ```typescript
262
- type TIdColumnDef<Opts extends TIdEnricherOptions | undefined> =
263
- Opts extends { id: infer IdOpts }
264
- ? IdOpts extends { dataType: 'string' }
265
- ? { id: IsPrimaryKey<NotNull<HasDefault<PgUUIDBuilderInitial<'id'>>>> }
266
- : IdOpts extends { dataType: 'number' }
267
- ? { id: IsIdentity<IsPrimaryKey<NotNull<PgIntegerBuilderInitial<'id'>>>, 'always'> }
268
- : IdOpts extends { dataType: 'big-number' }
269
- ? IdOpts extends { numberMode: 'number' }
270
- ? { id: IsIdentity<IsPrimaryKey<NotNull<PgBigInt53BuilderInitial<'id'>>>, 'always'> }
271
- : { id: IsIdentity<IsPrimaryKey<NotNull<PgBigInt64BuilderInitial<'id'>>>, 'always'> }
272
- : { id: IsIdentity<IsPrimaryKey<NotNull<PgIntegerBuilderInitial<'id'>>>, 'always'> }
273
- : { id: IsIdentity<IsPrimaryKey<NotNull<PgIntegerBuilderInitial<'id'>>>, 'always'> };
406
+ // Type aliases for readability
407
+ type TStringIdCol = HasRuntimeDefault<
408
+ HasDefault<IsPrimaryKey<NotNull<PgTextBuilderInitial<'id', [string, ...string[]]>>>>
409
+ >;
410
+ type TNumberIdCol = IsIdentity<IsPrimaryKey<NotNull<PgIntegerBuilderInitial<'id'>>>, 'always'>;
411
+ type TBigInt53IdCol = IsIdentity<IsPrimaryKey<NotNull<PgBigInt53BuilderInitial<'id'>>>, 'always'>;
412
+ type TBigInt64IdCol = IsIdentity<IsPrimaryKey<NotNull<PgBigInt64BuilderInitial<'id'>>>, 'always'>;
413
+
414
+ type TIdColumnDef<Opts extends TIdEnricherOptions | undefined> = Opts extends {
415
+ id: infer IdOpts;
416
+ }
417
+ ? IdOpts extends { dataType: 'string' }
418
+ ? { id: TStringIdCol }
419
+ : IdOpts extends { dataType: 'number' }
420
+ ? { id: TNumberIdCol }
421
+ : IdOpts extends { dataType: 'big-number' }
422
+ ? IdOpts extends { numberMode: 'number' }
423
+ ? { id: TBigInt53IdCol }
424
+ : { id: TBigInt64IdCol }
425
+ : { id: TNumberIdCol }
426
+ : { id: TNumberIdCol };
274
427
  ```
275
428
 
276
429
  This ensures that TypeScript correctly infers the exact column type based on your configuration.
@@ -291,7 +444,7 @@ export const myTable = pgTable('MyTable', {
291
444
  // Generates: id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY
292
445
  ```
293
446
 
294
- **UUID-based string ID:**
447
+ **Text-based string ID (UUID by default):**
295
448
 
296
449
  ```typescript
297
450
  export const myTable = pgTable('MyTable', {
@@ -299,8 +452,26 @@ export const myTable = pgTable('MyTable', {
299
452
  name: text('name').notNull(),
300
453
  });
301
454
 
302
- // Generates: id uuid PRIMARY KEY DEFAULT gen_random_uuid()
303
- // No extension required - built into PostgreSQL 13+
455
+ // Generates: id text PRIMARY KEY with $defaultFn(() => crypto.randomUUID())
456
+ // Uses text column for maximum database compatibility
457
+ ```
458
+
459
+ **Custom ID generator (e.g., nanoid, cuid):**
460
+
461
+ ```typescript
462
+ import { nanoid } from 'nanoid';
463
+
464
+ export const myTable = pgTable('MyTable', {
465
+ ...generateIdColumnDefs({
466
+ id: {
467
+ dataType: 'string',
468
+ generator: () => nanoid(), // Custom generator function
469
+ },
470
+ }),
471
+ name: text('name').notNull(),
472
+ });
473
+
474
+ // Generates: id text PRIMARY KEY with $defaultFn(() => nanoid())
304
475
  ```
305
476
 
306
477
  **Auto-incrementing integer with sequence options:**
@@ -357,12 +528,12 @@ export const myTable = pgTable('MyTable', {
357
528
 
358
529
  #### Important Notes
359
530
 
360
- - **UUID Type:** When using `dataType: 'string'`, the native PostgreSQL `uuid` type is used with `gen_random_uuid()` - no extension required (built into PostgreSQL 13+). This is more efficient than `text` type (16 bytes vs 36 bytes) and provides better indexing performance.
531
+ - **Text Column:** When using `dataType: 'string'`, a `text` column is used for maximum database compatibility. This allows you to use any ID format (UUID, nanoid, cuid, etc.) without database-specific constraints.
532
+ - **Custom Generator:** You can provide a custom `generator` function to generate IDs. Default is `crypto.randomUUID()`.
361
533
  - **Type Safety:** The return type is fully inferred based on your options, providing better autocomplete and type checking
362
534
  - **Big Number Mode:** For `dataType: 'big-number'`, the `numberMode` field is required to specify whether to use JavaScript `number` (up to 2^53-1) or `bigint` (for larger values)
363
535
  - **Sequence Options:** Available for `number` and `big-number` types to customize identity generation behavior
364
536
 
365
- ---
366
537
 
367
538
  ### `generateTzColumnDefs`
368
539
 
@@ -516,7 +687,6 @@ type TTzEnricherResult<ColumnDefinitions extends TColumnDefinitions = TColumnDef
516
687
  };
517
688
  ```
518
689
 
519
- ---
520
690
 
521
691
  ### `generateUserAuditColumnDefs`
522
692
 
@@ -625,7 +795,6 @@ export const myTable = pgTable('MyTable', {
625
795
  // modifiedBy: integer('editor_id')
626
796
  ```
627
797
 
628
- ---
629
798
 
630
799
  ## Schema Utilities
631
800
 
@@ -790,3 +959,26 @@ try {
790
959
  - Recursively handles nested objects
791
960
  - Preserves array structures
792
961
  - Works seamlessly with Zod's other features (refinements, transforms, etc.)
962
+
963
+ ## See Also
964
+
965
+ - **Related Concepts:**
966
+ - [Models Guide](/guides/core-concepts/persistent/models) - Creating models tutorial
967
+ - [Repositories](/guides/core-concepts/persistent/repositories) - Using models in repositories
968
+ - [DataSources](/guides/core-concepts/persistent/datasources) - Database connections
969
+
970
+ - **References:**
971
+ - [Repositories API](/references/base/repositories/) - Data access layer
972
+ - [Relations](/references/base/repositories/relations) - Model relationships
973
+ - [Filter System](/references/base/filter-system/) - Querying models
974
+
975
+ - **External Resources:**
976
+ - [Drizzle ORM Documentation](https://orm.drizzle.team/) - Schema definition guide
977
+ - [PostgreSQL Data Types](https://www.postgresql.org/docs/current/datatype.html) - Column types
978
+
979
+ - **Best Practices:**
980
+ - [Data Modeling](/best-practices/data-modeling) - Schema design patterns
981
+
982
+ - **Tutorials:**
983
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - Model examples
984
+ - [E-commerce API](/guides/tutorials/ecommerce-api) - Models with relations