@venizia/ignis-docs 0.0.4-0 → 0.0.4-2

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 (44) hide show
  1. package/package.json +1 -1
  2. package/wiki/best-practices/api-usage-examples.md +1 -0
  3. package/wiki/best-practices/code-style-standards/advanced-patterns.md +259 -0
  4. package/wiki/best-practices/code-style-standards/constants-configuration.md +225 -0
  5. package/wiki/best-practices/code-style-standards/control-flow.md +245 -0
  6. package/wiki/best-practices/code-style-standards/documentation.md +221 -0
  7. package/wiki/best-practices/code-style-standards/function-patterns.md +142 -0
  8. package/wiki/best-practices/code-style-standards/index.md +110 -0
  9. package/wiki/best-practices/code-style-standards/naming-conventions.md +174 -0
  10. package/wiki/best-practices/code-style-standards/route-definitions.md +150 -0
  11. package/wiki/best-practices/code-style-standards/tooling.md +155 -0
  12. package/wiki/best-practices/code-style-standards/type-safety.md +165 -0
  13. package/wiki/best-practices/common-pitfalls.md +164 -3
  14. package/wiki/best-practices/contribution-workflow.md +1 -1
  15. package/wiki/best-practices/data-modeling.md +102 -2
  16. package/wiki/best-practices/error-handling.md +468 -0
  17. package/wiki/best-practices/index.md +204 -21
  18. package/wiki/best-practices/performance-optimization.md +180 -0
  19. package/wiki/best-practices/security-guidelines.md +249 -0
  20. package/wiki/best-practices/testing-strategies.md +620 -0
  21. package/wiki/changelogs/2026-01-05-range-queries-content-range.md +184 -0
  22. package/wiki/changelogs/2026-01-06-basic-authentication.md +103 -0
  23. package/wiki/changelogs/2026-01-07-controller-route-customization.md +209 -0
  24. package/wiki/changelogs/index.md +3 -0
  25. package/wiki/guides/core-concepts/components-guide.md +1 -1
  26. package/wiki/guides/core-concepts/persistent/models.md +10 -0
  27. package/wiki/guides/tutorials/complete-installation.md +1 -1
  28. package/wiki/guides/tutorials/testing.md +1 -1
  29. package/wiki/references/base/bootstrapping.md +4 -3
  30. package/wiki/references/base/components.md +47 -29
  31. package/wiki/references/base/controllers.md +220 -24
  32. package/wiki/references/base/filter-system/fields-order-pagination.md +84 -0
  33. package/wiki/references/base/middlewares.md +37 -3
  34. package/wiki/references/base/models.md +40 -2
  35. package/wiki/references/base/providers.md +1 -2
  36. package/wiki/references/base/repositories/index.md +3 -1
  37. package/wiki/references/base/services.md +2 -2
  38. package/wiki/references/components/authentication.md +261 -247
  39. package/wiki/references/helpers/index.md +1 -1
  40. package/wiki/references/helpers/socket-io.md +1 -1
  41. package/wiki/references/quick-reference.md +2 -2
  42. package/wiki/references/src-details/core.md +1 -1
  43. package/wiki/references/utilities/statuses.md +4 -4
  44. package/wiki/best-practices/code-style-standards.md +0 -1193
@@ -54,8 +54,8 @@ export class Application extends BaseApplication {
54
54
  }),
55
55
  })
56
56
 
57
- // ❌ BAD - typo in string
58
- @inject({ key: 'repositories.ConfigurationRepositry' })
57
+ // ❌ BAD - typo in string (note: "Repository" is misspelled)
58
+ @inject({ key: 'repositories.ConfigurationRepository' })
59
59
  ```
60
60
 
61
61
  ## 3. Business Logic in Controllers
@@ -240,4 +240,165 @@ try {
240
240
  });
241
241
  }
242
242
  }
243
- ```
243
+ ```
244
+
245
+ ## 9. Circular Dependency Issues
246
+
247
+ **Problem:** Application fails to start with `Cannot access 'X' before initialization` or similar errors.
248
+
249
+ **Cause:** Two or more modules import each other directly, creating a circular reference that JavaScript cannot resolve.
250
+
251
+ **Solution:** Use lazy imports or restructure your modules:
252
+
253
+ ```typescript
254
+ // ❌ BAD - Direct import causes circular dependency
255
+ import { UserService } from './user.service';
256
+
257
+ @model({ type: 'entity' })
258
+ export class Order extends BaseEntity<typeof Order.schema> {
259
+ static override relations = (): TRelationConfig[] => [
260
+ { schema: User.schema, ... }, // User imports Order, Order imports User
261
+ ];
262
+ }
263
+
264
+ // ✅ GOOD - Lazy import breaks the cycle
265
+ @model({ type: 'entity' })
266
+ export class Order extends BaseEntity<typeof Order.schema> {
267
+ static override relations = (): TRelationConfig[] => {
268
+ const { User } = require('./user.model'); // Lazy require
269
+ return [{ schema: User.schema, ... }];
270
+ };
271
+ }
272
+ ```
273
+
274
+ **Alternative:** Restructure to have a shared module that both import from.
275
+
276
+ ## 10. Transaction Not Rolling Back
277
+
278
+ **Problem:** Errors occur but database changes are still persisted.
279
+
280
+ **Cause:** Transaction not properly wrapped in try-catch, or rollback not called on error.
281
+
282
+ **Solution:** Always wrap transactions in try-catch with explicit rollback:
283
+
284
+ ```typescript
285
+ // ❌ BAD - No error handling
286
+ const tx = await repo.beginTransaction();
287
+ await repo.create({ data, options: { transaction: tx } });
288
+ await tx.commit(); // If create fails, commit is never called but neither is rollback
289
+
290
+ // ✅ GOOD - Proper transaction handling
291
+ const tx = await repo.beginTransaction();
292
+ try {
293
+ await repo.create({ data, options: { transaction: tx } });
294
+ await otherRepo.update({ data: other, options: { transaction: tx } });
295
+ await tx.commit();
296
+ } catch (error) {
297
+ await tx.rollback();
298
+ throw error; // Re-throw to let caller handle
299
+ }
300
+ ```
301
+
302
+ ## 11. Fire-and-Forget Promises Losing Context
303
+
304
+ **Problem:** `getCurrentUserId()` or other context-dependent functions return `null` in background tasks.
305
+
306
+ **Cause:** When you fire-and-forget a promise, it runs outside the original async context where the user was authenticated.
307
+
308
+ **Solution:** Pass required context data explicitly to background tasks:
309
+
310
+ ```typescript
311
+ // ❌ BAD - Context lost in fire-and-forget
312
+ @post({ configs: RouteConfigs.CREATE_ORDER })
313
+ async createOrder(c: Context) {
314
+ const data = c.req.valid('json');
315
+ const order = await this.orderService.create(data);
316
+
317
+ // Fire-and-forget: sendNotification runs outside request context
318
+ this.notificationService.sendOrderConfirmation(order.id);
319
+ // Inside sendOrderConfirmation, getCurrentUserId() returns null!
320
+
321
+ return c.json(order);
322
+ }
323
+
324
+ // ✅ GOOD - Pass user ID explicitly
325
+ @post({ configs: RouteConfigs.CREATE_ORDER })
326
+ async createOrder(c: Context) {
327
+ const data = c.req.valid('json');
328
+ const userId = c.get(Authentication.AUDIT_USER_ID);
329
+ const order = await this.orderService.create(data);
330
+
331
+ // Pass userId explicitly to background task
332
+ this.notificationService.sendOrderConfirmation(order.id, userId);
333
+
334
+ return c.json(order);
335
+ }
336
+ ```
337
+
338
+ > [!WARNING]
339
+ > This is especially important when using `allowAnonymous: false` in user audit columns. The enricher will throw an error if it cannot find the user context.
340
+
341
+ ## 12. Incorrect Relation Configuration
342
+
343
+ **Problem:** Relations return empty arrays or `null` unexpectedly.
344
+
345
+ **Cause:** Mismatch between `fields` and `references` in relation metadata.
346
+
347
+ **Solution:** Double-check that foreign keys point to the correct columns:
348
+
349
+ ```typescript
350
+ // ❌ BAD - fields and references swapped
351
+ static override relations = (): TRelationConfig[] => [
352
+ {
353
+ name: 'posts',
354
+ type: RelationTypes.MANY,
355
+ schema: Post.schema,
356
+ 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
359
+ },
360
+ },
361
+ ];
362
+
363
+ // ✅ GOOD - Correct configuration
364
+ // "User has many Posts where User.id = Post.authorId"
365
+ static override relations = (): TRelationConfig[] => [
366
+ {
367
+ name: 'posts',
368
+ type: RelationTypes.MANY,
369
+ schema: Post.schema,
370
+ metadata: {
371
+ fields: [User.schema.id], // Parent's key
372
+ references: [Post.schema.authorId], // Child's foreign key
373
+ },
374
+ },
375
+ ];
376
+ ```
377
+
378
+ **Rule of thumb:** `fields` is the key on the current entity, `references` is the key on the related entity.
379
+
380
+ ## 13. Overwriting Data with Partial Updates
381
+
382
+ **Problem:** PATCH endpoint replaces entire record instead of merging fields.
383
+
384
+ **Cause:** Using `create()` or full `update()` instead of partial update methods.
385
+
386
+ **Solution:** Use `updateById()` which only updates provided fields:
387
+
388
+ ```typescript
389
+ // ❌ BAD - Overwrites all fields (if using raw insert/update)
390
+ await db.update(users).set(data).where(eq(users.id, id));
391
+ // If data = { name: 'New' }, email and other fields might be set to undefined
392
+
393
+ // ✅ GOOD - Repository updateById only updates provided fields
394
+ await userRepository.updateById({
395
+ id: userId,
396
+ data: { name: 'New Name' }, // Only updates 'name', leaves other fields intact
397
+ });
398
+ ```
399
+
400
+ ## See Also
401
+
402
+ - [Troubleshooting Tips](./troubleshooting-tips) - Debug common issues
403
+ - [Error Handling](./error-handling) - Proper error handling patterns
404
+ - [Architecture Decisions](./architecture-decisions) - Avoid design mistakes
@@ -125,7 +125,7 @@ git checkout -b feature/your-feature-name
125
125
  ### Step 2: Make Changes
126
126
 
127
127
  **Checklist:**
128
- - ✅ Follow [Code Style Standards](./code-style-standards.md)
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
131
  - ✅ Update docs in `packages/docs/wiki` if needed
@@ -38,7 +38,7 @@ Instead of manually defining common columns like primary keys, timestamps, or au
38
38
  | `generateIdColumnDefs` | Adds a Primary Key | `id` (text, number, or big-number) |
39
39
  | `generatePrincipalColumnDefs` | Adds polymorphic relation fields | `{discriminator}Id`, `{discriminator}Type` |
40
40
  | `generateTzColumnDefs` | Adds timestamps | `createdAt`, `modifiedAt` (auto-updating) |
41
- | `generateUserAuditColumnDefs` | Adds audit fields | `createdBy`, `modifiedBy` |
41
+ | `generateUserAuditColumnDefs` | Adds audit fields | `createdBy`, `modifiedBy` (supports `allowAnonymous` option) |
42
42
  | `generateDataTypeColumnDefs` | Adds generic value fields | `nValue` (number), `tValue` (text), `jValue` (json), etc. |
43
43
  | `extraUserColumns` | Comprehensive user fields | Combines audit, timestamps, status, and type fields |
44
44
 
@@ -373,4 +373,104 @@ export class User extends BaseEntity<typeof User.schema> {
373
373
  - Hidden properties are **recursively excluded** from included relations
374
374
  - Use the connector directly when you need to access hidden data (e.g., password verification)
375
375
 
376
- > **Reference:** See [Hidden Properties](../references/base/models.md#hidden-properties) for complete documentation.
376
+ > **Reference:** See [Hidden Properties](../references/base/models.md#hidden-properties) for complete documentation.
377
+
378
+ ## 6. Database Migrations
379
+
380
+ Drizzle Kit handles schema migrations. Follow these best practices for safe migrations.
381
+
382
+ ### Generate Migrations
383
+
384
+ ```bash
385
+ # Generate migration from schema changes
386
+ bun run db:generate
387
+
388
+ # Apply migrations to database
389
+ bun run db:migrate
390
+
391
+ # Push schema directly (development only)
392
+ bun run db:push
393
+ ```
394
+
395
+ ### Migration Best Practices
396
+
397
+ | Practice | Description |
398
+ |----------|-------------|
399
+ | **One change per migration** | Keep migrations focused and reversible |
400
+ | **Never edit applied migrations** | Create new migration instead |
401
+ | **Test on staging first** | Always test migrations before production |
402
+ | **Backup before migrate** | `pg_dump` before running in production |
403
+ | **Use transactions** | Drizzle wraps migrations in transactions by default |
404
+
405
+ ### Safe Schema Changes
406
+
407
+ **Adding columns (safe):**
408
+ ```typescript
409
+ // Add with default value to avoid nulls in existing rows
410
+ newField: text('new_field').default(''),
411
+
412
+ // Or allow null initially, then backfill and set notNull
413
+ newField: text('new_field'), // Initially nullable
414
+ ```
415
+
416
+ **Renaming columns (requires care):**
417
+ ```sql
418
+ -- In custom migration SQL
419
+ ALTER TABLE "User" RENAME COLUMN "old_name" TO "new_name";
420
+ ```
421
+
422
+ **Dropping columns (dangerous):**
423
+ ```typescript
424
+ // 1. First, remove all code references
425
+ // 2. Deploy code changes
426
+ // 3. Then drop in separate migration
427
+ ```
428
+
429
+ ### Custom Migration SQL
430
+
431
+ For complex migrations, use custom SQL:
432
+
433
+ ```typescript
434
+ // drizzle/migrations/0005_custom_migration.ts
435
+ import { sql } from 'drizzle-orm';
436
+
437
+ export async function up(db: DrizzleDB) {
438
+ // Add index for performance
439
+ await db.execute(sql`
440
+ CREATE INDEX CONCURRENTLY idx_user_email
441
+ ON "User" (email)
442
+ WHERE status = 'ACTIVE'
443
+ `);
444
+
445
+ // Backfill data
446
+ await db.execute(sql`
447
+ UPDATE "User"
448
+ SET normalized_email = LOWER(email)
449
+ WHERE normalized_email IS NULL
450
+ `);
451
+ }
452
+
453
+ export async function down(db: DrizzleDB) {
454
+ await db.execute(sql`DROP INDEX IF EXISTS idx_user_email`);
455
+ }
456
+ ```
457
+
458
+ ### Migration Checklist
459
+
460
+ | Step | Action |
461
+ |------|--------|
462
+ | 1 | Review generated SQL before applying |
463
+ | 2 | Test migration on staging database |
464
+ | 3 | Backup production database |
465
+ | 4 | Run during low-traffic period |
466
+ | 5 | Monitor for errors after migration |
467
+ | 6 | Have rollback plan ready |
468
+
469
+ > [!WARNING]
470
+ > Never run migrations directly on production without testing. Use staging environments that mirror production data structure.
471
+
472
+ ## See Also
473
+
474
+ - [API Usage Examples](./api-usage-examples) - Query patterns
475
+ - [Performance Optimization](./performance-optimization) - Index design
476
+ - [Common Pitfalls](./common-pitfalls) - Migration mistakes to avoid