@venizia/ignis-docs 0.0.1-9 → 0.0.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.
- package/LICENSE.md +1 -0
- package/package.json +2 -2
- package/wiki/changelogs/{v0.0.1-7-initial-architecture.md → 2025-12-16-initial-architecture.md} +20 -12
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +300 -0
- package/wiki/changelogs/2025-12-17-refactor.md +80 -12
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +28 -90
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +101 -297
- package/wiki/changelogs/index.md +20 -8
- package/wiki/changelogs/planned-schema-migrator.md +561 -0
- package/wiki/changelogs/planned-transaction-support.md +216 -0
- package/wiki/changelogs/template.md +123 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -2
- package/wiki/get-started/best-practices/architectural-patterns.md +2 -2
- package/wiki/get-started/best-practices/code-style-standards.md +575 -10
- package/wiki/get-started/best-practices/common-pitfalls.md +5 -3
- package/wiki/get-started/best-practices/contribution-workflow.md +2 -0
- package/wiki/get-started/best-practices/data-modeling.md +91 -34
- package/wiki/get-started/best-practices/security-guidelines.md +3 -1
- package/wiki/get-started/building-a-crud-api.md +3 -3
- package/wiki/get-started/core-concepts/application.md +72 -3
- package/wiki/get-started/core-concepts/bootstrapping.md +566 -0
- package/wiki/get-started/core-concepts/components.md +4 -2
- package/wiki/get-started/core-concepts/persistent.md +350 -378
- package/wiki/get-started/core-concepts/services.md +21 -27
- package/wiki/references/base/bootstrapping.md +789 -0
- package/wiki/references/base/components.md +1 -1
- package/wiki/references/base/dependency-injection.md +95 -2
- package/wiki/references/base/services.md +2 -2
- package/wiki/references/components/authentication.md +4 -3
- package/wiki/references/components/index.md +1 -1
- package/wiki/references/helpers/error.md +2 -2
- package/wiki/references/src-details/boot.md +379 -0
- package/wiki/references/src-details/core.md +2 -2
- package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +0 -278
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Planned - Transaction Support
|
|
3
|
+
description: Implementation plan for Loopback 4-style explicit transaction objects
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Planned: Transaction Support
|
|
7
|
+
|
|
8
|
+
**Status:** Planned (Not Yet Implemented)
|
|
9
|
+
**Priority:** Future Enhancement
|
|
10
|
+
|
|
11
|
+
## Goal
|
|
12
|
+
|
|
13
|
+
Implement Loopback 4-style explicit transaction objects, allowing transactions to be passed through multiple services/repositories instead of using Drizzle's callback-based approach.
|
|
14
|
+
|
|
15
|
+
## Target API
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Default isolation level (READ COMMITTED)
|
|
19
|
+
const tx = await userRepo.beginTransaction();
|
|
20
|
+
|
|
21
|
+
// Or with specific isolation level
|
|
22
|
+
const tx = await userRepo.beginTransaction({
|
|
23
|
+
isolationLevel: 'SERIALIZABLE'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
await userRepo.create({ data, options: { transaction: tx } });
|
|
28
|
+
await profileRepo.create({ data, options: { transaction: tx } });
|
|
29
|
+
await tx.commit();
|
|
30
|
+
} catch (err) {
|
|
31
|
+
await tx.rollback();
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Isolation Levels
|
|
37
|
+
|
|
38
|
+
| Level | Description | Use Case |
|
|
39
|
+
|-------|-------------|----------|
|
|
40
|
+
| `READ COMMITTED` | Default. Sees only committed data at query start | General use, most common |
|
|
41
|
+
| `REPEATABLE READ` | Sees snapshot from transaction start | Reports, consistent reads |
|
|
42
|
+
| `SERIALIZABLE` | Strictest. Full isolation, may throw serialization errors | Financial transactions, critical data |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Implementation Steps
|
|
47
|
+
|
|
48
|
+
### Step 1: Define Transaction Types
|
|
49
|
+
|
|
50
|
+
**File:** `packages/core/src/base/datasources/types.ts`
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
/** PostgreSQL transaction isolation levels */
|
|
54
|
+
export type TIsolationLevel = 'READ COMMITTED' | 'REPEATABLE READ' | 'SERIALIZABLE';
|
|
55
|
+
|
|
56
|
+
/** Options for starting a transaction */
|
|
57
|
+
export interface ITransactionOptions {
|
|
58
|
+
isolationLevel?: TIsolationLevel;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Transaction object returned by beginTransaction() */
|
|
62
|
+
export interface ITransaction<Connector = TNodePostgresConnector> {
|
|
63
|
+
/** Isolated Drizzle instance bound to this transaction */
|
|
64
|
+
connector: Connector;
|
|
65
|
+
|
|
66
|
+
/** Commit the transaction */
|
|
67
|
+
commit(): Promise<void>;
|
|
68
|
+
|
|
69
|
+
/** Rollback the transaction */
|
|
70
|
+
rollback(): Promise<void>;
|
|
71
|
+
|
|
72
|
+
/** Check if transaction is still active */
|
|
73
|
+
isActive: boolean;
|
|
74
|
+
|
|
75
|
+
/** The isolation level used for this transaction */
|
|
76
|
+
isolationLevel: TIsolationLevel;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 2: Add `beginTransaction()` to DataSource
|
|
81
|
+
|
|
82
|
+
**File:** `packages/core/src/base/datasources/base.ts`
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
async beginTransaction(
|
|
86
|
+
opts?: ITransactionOptions
|
|
87
|
+
): Promise<ITransaction<Connector>> {
|
|
88
|
+
// 1. Get raw client from pool
|
|
89
|
+
const pool = this.connector.client as Pool;
|
|
90
|
+
const client = await pool.connect();
|
|
91
|
+
|
|
92
|
+
// 2. Determine isolation level (default: READ COMMITTED)
|
|
93
|
+
const isolationLevel: TIsolationLevel = opts?.isolationLevel ?? 'READ COMMITTED';
|
|
94
|
+
|
|
95
|
+
// 3. Execute BEGIN with isolation level
|
|
96
|
+
await client.query(`BEGIN TRANSACTION ISOLATION LEVEL ${isolationLevel}`);
|
|
97
|
+
|
|
98
|
+
// 4. Create isolated Drizzle instance with this client
|
|
99
|
+
const txConnector = drizzle({ client, schema: this.schema });
|
|
100
|
+
|
|
101
|
+
// 5. Return transaction object
|
|
102
|
+
let isActive = true;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
connector: txConnector as Connector,
|
|
106
|
+
isActive,
|
|
107
|
+
isolationLevel,
|
|
108
|
+
|
|
109
|
+
async commit() {
|
|
110
|
+
if (!isActive) throw new Error('Transaction already ended');
|
|
111
|
+
try {
|
|
112
|
+
await client.query('COMMIT');
|
|
113
|
+
} finally {
|
|
114
|
+
isActive = false;
|
|
115
|
+
client.release();
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
async rollback() {
|
|
120
|
+
if (!isActive) throw new Error('Transaction already ended');
|
|
121
|
+
try {
|
|
122
|
+
await client.query('ROLLBACK');
|
|
123
|
+
} finally {
|
|
124
|
+
isActive = false;
|
|
125
|
+
client.release();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Step 3: Update Repository Base
|
|
133
|
+
|
|
134
|
+
**File:** `packages/core/src/base/repositories/core/base.ts`
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// Add method to start transaction (delegates to DataSource)
|
|
138
|
+
async beginTransaction(opts?: ITransactionOptions): Promise<ITransaction> {
|
|
139
|
+
return this.dataSource.beginTransaction(opts);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Replace this.connector with getConnector(opts)
|
|
143
|
+
protected getConnector(opts?: { transaction?: ITransaction }) {
|
|
144
|
+
if (opts?.transaction) {
|
|
145
|
+
if (!opts.transaction.isActive) {
|
|
146
|
+
throw getError({ message: 'Transaction is no longer active' });
|
|
147
|
+
}
|
|
148
|
+
return opts.transaction.connector;
|
|
149
|
+
}
|
|
150
|
+
return this.dataSource.connector;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Step 4: Update CRUD Options Types
|
|
155
|
+
|
|
156
|
+
**File:** `packages/core/src/base/repositories/common/types.ts`
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
export type TTransactionOption = {
|
|
160
|
+
transaction?: ITransaction;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Add to existing option types
|
|
164
|
+
export type TCreateOptions = TTransactionOption & {
|
|
165
|
+
shouldReturn?: boolean;
|
|
166
|
+
log?: TRepositoryLogOptions;
|
|
167
|
+
};
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 5: Update CRUD Methods
|
|
171
|
+
|
|
172
|
+
**Files:** `readable.ts`, `persistable.ts`
|
|
173
|
+
|
|
174
|
+
Change all methods from:
|
|
175
|
+
```typescript
|
|
176
|
+
this.connector.insert(...)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
To:
|
|
180
|
+
```typescript
|
|
181
|
+
this.getConnector(opts.options).insert(...)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Files to Modify
|
|
187
|
+
|
|
188
|
+
| File | Changes |
|
|
189
|
+
|------|---------|
|
|
190
|
+
| `packages/core/src/base/datasources/types.ts` | Add `TIsolationLevel`, `ITransactionOptions`, `ITransaction` |
|
|
191
|
+
| `packages/core/src/base/datasources/base.ts` | Add `beginTransaction(opts?)` method |
|
|
192
|
+
| `packages/core/src/base/repositories/common/types.ts` | Add `TTransactionOption` |
|
|
193
|
+
| `packages/core/src/base/repositories/core/base.ts` | Add `beginTransaction(opts?)`, `getConnector(opts)` |
|
|
194
|
+
| `packages/core/src/base/repositories/core/readable.ts` | Use `getConnector(opts)` in all methods |
|
|
195
|
+
| `packages/core/src/base/repositories/core/persistable.ts` | Use `getConnector(opts)` in all methods |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Breaking Changes
|
|
200
|
+
|
|
201
|
+
1. **`this.connector`** → `this.getConnector(opts)`
|
|
202
|
+
- Backward compatible when called without args
|
|
203
|
+
|
|
204
|
+
2. **Options parameter** - Now includes optional `transaction` field
|
|
205
|
+
- Non-breaking: transaction is optional
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Benefits
|
|
210
|
+
|
|
211
|
+
| Aspect | Current (Drizzle Callback) | After (Pass-through) |
|
|
212
|
+
|--------|---------------------------|----------------------|
|
|
213
|
+
| Service composition | Hard - all in one callback | Easy - pass tx anywhere |
|
|
214
|
+
| Separation of concerns | Services must know each other | Services stay independent |
|
|
215
|
+
| Testing | Complex mocking | Easy to mock tx object |
|
|
216
|
+
| Code organization | Nested callbacks | Flat, sequential flow |
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: [Short Title]
|
|
3
|
+
description: [Brief description of the changes]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - YYYY-MM-DD
|
|
7
|
+
|
|
8
|
+
## [Main Title/Focus Area]
|
|
9
|
+
|
|
10
|
+
[A brief, high-level summary of the changes in this release. What is the main focus?]
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **[Change 1]**: Brief description
|
|
15
|
+
- **[Change 2]**: Brief description
|
|
16
|
+
- **[Change 3]**: Brief description
|
|
17
|
+
|
|
18
|
+
## Breaking Changes
|
|
19
|
+
|
|
20
|
+
> [!WARNING]
|
|
21
|
+
> This section contains changes that require migration or manual updates to existing code.
|
|
22
|
+
|
|
23
|
+
### 1. [Breaking Change Title]
|
|
24
|
+
|
|
25
|
+
**Before:**
|
|
26
|
+
```typescript
|
|
27
|
+
// Code that no longer works or is deprecated
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**After:**
|
|
31
|
+
```typescript
|
|
32
|
+
// New pattern
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## New Features
|
|
36
|
+
|
|
37
|
+
### [Feature Name]
|
|
38
|
+
|
|
39
|
+
**File:** `packages/core/src/path/to/file.ts`
|
|
40
|
+
|
|
41
|
+
**Problem:** [What problem does this solve?]
|
|
42
|
+
|
|
43
|
+
**Solution:** [How does it solve it?]
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Example usage
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Benefits:**
|
|
50
|
+
- Benefit 1
|
|
51
|
+
- Benefit 2
|
|
52
|
+
|
|
53
|
+
## Security Fixes
|
|
54
|
+
|
|
55
|
+
### [Security Issue Title]
|
|
56
|
+
|
|
57
|
+
**Vulnerability:** [Describe the vulnerability]
|
|
58
|
+
|
|
59
|
+
**Fix:** [Describe the fix]
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Before: vulnerable code behavior
|
|
63
|
+
// After: secure code behavior
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Performance Improvements
|
|
67
|
+
|
|
68
|
+
### [Performance Improvement Title]
|
|
69
|
+
|
|
70
|
+
**File:** `packages/core/src/path/to/file.ts`
|
|
71
|
+
|
|
72
|
+
**Problem:** [What was slow/inefficient?]
|
|
73
|
+
|
|
74
|
+
**Solution:** [How was it optimized?]
|
|
75
|
+
|
|
76
|
+
| Scenario | Improvement |
|
|
77
|
+
|----------|-------------|
|
|
78
|
+
| [Use case 1] | [Improvement metric] |
|
|
79
|
+
| [Use case 2] | [Improvement metric] |
|
|
80
|
+
|
|
81
|
+
## Files Changed
|
|
82
|
+
|
|
83
|
+
### Core Package (`packages/core`)
|
|
84
|
+
|
|
85
|
+
| File | Changes |
|
|
86
|
+
|------|---------|
|
|
87
|
+
| `src/base/models/base.ts` | [Description of changes] |
|
|
88
|
+
| `src/base/repositories/core/readable.ts` | [Description of changes] |
|
|
89
|
+
|
|
90
|
+
### Helpers Package (`packages/helpers`)
|
|
91
|
+
|
|
92
|
+
| File | Changes |
|
|
93
|
+
|------|---------|
|
|
94
|
+
| `src/utils/index.ts` | [Description of changes] |
|
|
95
|
+
|
|
96
|
+
### Examples (`examples/vert`)
|
|
97
|
+
|
|
98
|
+
| File | Changes |
|
|
99
|
+
|------|---------|
|
|
100
|
+
| `src/models/entities/user.model.ts` | [Description of changes] |
|
|
101
|
+
|
|
102
|
+
## Migration Guide
|
|
103
|
+
|
|
104
|
+
> [!NOTE]
|
|
105
|
+
> Follow these steps if you're upgrading from a previous version.
|
|
106
|
+
|
|
107
|
+
### Step 1: [Action Name]
|
|
108
|
+
|
|
109
|
+
[Instructions]
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Example of the change to apply
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Step 2: [Action Name]
|
|
116
|
+
|
|
117
|
+
[Instructions]
|
|
118
|
+
|
|
119
|
+
## No Breaking Changes
|
|
120
|
+
|
|
121
|
+
[Use this section instead of "Breaking Changes" and "Migration Guide" if there are no breaking changes]
|
|
122
|
+
|
|
123
|
+
All changes are internal optimizations. No API changes or migration required.
|
|
@@ -90,7 +90,7 @@ export class ConfigurationController extends _Controller {
|
|
|
90
90
|
// an instance of ConfigurationRepository here.
|
|
91
91
|
@inject({
|
|
92
92
|
key: BindingKeys.build({
|
|
93
|
-
namespace:
|
|
93
|
+
namespace: BindingNamespaces.REPOSITORY,
|
|
94
94
|
key: ConfigurationRepository.name,
|
|
95
95
|
}),
|
|
96
96
|
})
|
|
@@ -103,7 +103,7 @@ export class ConfigurationController extends _Controller {
|
|
|
103
103
|
|
|
104
104
|
## 3. Component-Based Modularity
|
|
105
105
|
|
|
106
|
-
Components bundle related features into self-contained,
|
|
106
|
+
Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories, essentially functioning as a mini-application that can be easily "plugged in" to any Ignis project.
|
|
107
107
|
|
|
108
108
|
**Built-in Components:**
|
|
109
109
|
- `AuthenticateComponent` - JWT authentication
|