@venizia/ignis-docs 0.0.3 → 0.0.4-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.
- package/README.md +1 -1
- package/package.json +4 -2
- package/wiki/best-practices/api-usage-examples.md +591 -0
- package/wiki/best-practices/architectural-patterns.md +415 -0
- package/wiki/best-practices/architecture-decisions.md +488 -0
- package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
- package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
- package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
- package/wiki/best-practices/data-modeling.md +376 -0
- package/wiki/best-practices/deployment-strategies.md +698 -0
- package/wiki/best-practices/index.md +27 -0
- package/wiki/best-practices/performance-optimization.md +196 -0
- package/wiki/best-practices/security-guidelines.md +218 -0
- package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
- package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
- package/wiki/changelogs/2025-12-17-refactor.md +1 -1
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
- package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
- package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
- package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
- package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
- package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
- package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
- package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
- package/wiki/changelogs/index.md +6 -0
- package/wiki/changelogs/planned-schema-migrator.md +0 -8
- package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
- package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
- package/wiki/guides/core-concepts/components-guide.md +509 -0
- package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
- package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
- package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
- package/wiki/guides/core-concepts/persistent/index.md +119 -0
- package/wiki/guides/core-concepts/persistent/models.md +241 -0
- package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
- package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
- package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
- package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
- package/wiki/guides/get-started/philosophy.md +682 -0
- package/wiki/guides/get-started/setup.md +157 -0
- package/wiki/guides/index.md +89 -0
- package/wiki/guides/reference/glossary.md +243 -0
- package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
- package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
- package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
- package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
- package/wiki/guides/tutorials/realtime-chat.md +1261 -0
- package/wiki/guides/tutorials/testing.md +723 -0
- package/wiki/index.md +176 -37
- package/wiki/references/base/application.md +27 -0
- package/wiki/references/base/bootstrapping.md +30 -26
- package/wiki/references/base/components.md +24 -7
- package/wiki/references/base/controllers.md +51 -20
- package/wiki/references/base/datasources.md +30 -0
- package/wiki/references/base/dependency-injection.md +39 -3
- package/wiki/references/base/filter-system/application-usage.md +224 -0
- package/wiki/references/base/filter-system/array-operators.md +132 -0
- package/wiki/references/base/filter-system/comparison-operators.md +109 -0
- package/wiki/references/base/filter-system/default-filter.md +428 -0
- package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
- package/wiki/references/base/filter-system/index.md +127 -0
- package/wiki/references/base/filter-system/json-filtering.md +197 -0
- package/wiki/references/base/filter-system/list-operators.md +71 -0
- package/wiki/references/base/filter-system/logical-operators.md +156 -0
- package/wiki/references/base/filter-system/null-operators.md +58 -0
- package/wiki/references/base/filter-system/pattern-matching.md +108 -0
- package/wiki/references/base/filter-system/quick-reference.md +431 -0
- package/wiki/references/base/filter-system/range-operators.md +63 -0
- package/wiki/references/base/filter-system/tips.md +190 -0
- package/wiki/references/base/filter-system/use-cases.md +452 -0
- package/wiki/references/base/index.md +90 -0
- package/wiki/references/base/middlewares.md +602 -0
- package/wiki/references/base/models.md +215 -23
- package/wiki/references/base/providers.md +732 -0
- package/wiki/references/base/repositories/advanced.md +555 -0
- package/wiki/references/base/repositories/index.md +228 -0
- package/wiki/references/base/repositories/mixins.md +331 -0
- package/wiki/references/base/repositories/relations.md +486 -0
- package/wiki/references/base/repositories.md +40 -635
- package/wiki/references/base/services.md +28 -4
- package/wiki/references/components/authentication.md +22 -2
- package/wiki/references/components/health-check.md +12 -0
- package/wiki/references/components/index.md +23 -0
- package/wiki/references/components/mail.md +687 -0
- package/wiki/references/components/request-tracker.md +16 -0
- package/wiki/references/components/socket-io.md +18 -0
- package/wiki/references/components/static-asset.md +14 -26
- package/wiki/references/components/swagger.md +17 -0
- package/wiki/references/configuration/environment-variables.md +427 -0
- package/wiki/references/configuration/index.md +73 -0
- package/wiki/references/helpers/cron.md +14 -0
- package/wiki/references/helpers/crypto.md +15 -0
- package/wiki/references/helpers/env.md +16 -0
- package/wiki/references/helpers/error.md +17 -0
- package/wiki/references/helpers/index.md +14 -0
- package/wiki/references/helpers/inversion.md +24 -4
- package/wiki/references/helpers/logger.md +19 -0
- package/wiki/references/helpers/network.md +11 -0
- package/wiki/references/helpers/queue.md +19 -0
- package/wiki/references/helpers/redis.md +21 -0
- package/wiki/references/helpers/socket-io.md +24 -5
- package/wiki/references/helpers/storage.md +18 -10
- package/wiki/references/helpers/testing.md +18 -0
- package/wiki/references/helpers/types.md +16 -0
- package/wiki/references/helpers/uid.md +167 -0
- package/wiki/references/helpers/worker-thread.md +16 -0
- package/wiki/references/index.md +177 -0
- package/wiki/references/quick-reference.md +634 -0
- package/wiki/references/src-details/boot.md +3 -3
- package/wiki/references/src-details/dev-configs.md +0 -4
- package/wiki/references/src-details/docs.md +2 -2
- package/wiki/references/src-details/index.md +86 -0
- package/wiki/references/src-details/inversion.md +1 -6
- package/wiki/references/src-details/mcp-server.md +3 -15
- package/wiki/references/utilities/index.md +86 -10
- package/wiki/references/utilities/jsx.md +577 -0
- package/wiki/references/utilities/request.md +0 -2
- package/wiki/references/utilities/statuses.md +740 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
- package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
- package/wiki/get-started/best-practices/data-modeling.md +0 -177
- package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
- package/wiki/get-started/best-practices/performance-optimization.md +0 -97
- package/wiki/get-started/best-practices/security-guidelines.md +0 -99
- package/wiki/get-started/core-concepts/persistent.md +0 -539
- package/wiki/get-started/index.md +0 -65
- package/wiki/get-started/philosophy.md +0 -296
- package/wiki/get-started/prerequisites.md +0 -113
|
@@ -0,0 +1,740 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Status Codes & Constants Reference
|
|
3
|
+
description: Technical reference for IGNIS status codes, bindings, and constants
|
|
4
|
+
difficulty: beginner
|
|
5
|
+
lastUpdated: 2026-01-03
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Status Codes & Constants Reference
|
|
9
|
+
|
|
10
|
+
IGNIS provides a comprehensive system of standardized status codes and constants to maintain consistency across your application. This reference covers the `Statuses` class and related utilities for managing entity states.
|
|
11
|
+
|
|
12
|
+
**Files:**
|
|
13
|
+
- `packages/core/src/common/statuses.ts`
|
|
14
|
+
- `packages/core/src/common/bindings.ts`
|
|
15
|
+
|
|
16
|
+
## Quick Reference
|
|
17
|
+
|
|
18
|
+
| Class | Purpose | Use Case |
|
|
19
|
+
|-------|---------|----------|
|
|
20
|
+
| `Statuses` | Universal status codes (0xx-5xx scheme) | General entity lifecycle states |
|
|
21
|
+
| `MigrationStatuses` | Database migration status tracking | Migration success/failure tracking |
|
|
22
|
+
| `CommonStatuses` | Common entity statuses | Users, roles, and general entities |
|
|
23
|
+
| `UserStatuses` | User-specific statuses | User account states |
|
|
24
|
+
| `RoleStatuses` | Role-specific statuses | Role lifecycle states |
|
|
25
|
+
| `UserTypes` | User type classification | System vs linked users |
|
|
26
|
+
|
|
27
|
+
## Table of Contents
|
|
28
|
+
|
|
29
|
+
- [Statuses Class](#statuses-class)
|
|
30
|
+
- [Status Code Scheme](#status-code-scheme)
|
|
31
|
+
- [Status Groups](#status-groups)
|
|
32
|
+
- [Validation Methods](#validation-methods)
|
|
33
|
+
- [Specialized Status Classes](#specialized-status-classes)
|
|
34
|
+
- [Usage Examples](#usage-examples)
|
|
35
|
+
- [Binding Namespaces](#binding-namespaces)
|
|
36
|
+
- [Best Practices](#best-practices)
|
|
37
|
+
- [See Also](#see-also)
|
|
38
|
+
|
|
39
|
+
## Statuses Class
|
|
40
|
+
|
|
41
|
+
The `Statuses` class provides a comprehensive, HTTP-inspired status code system for tracking entity lifecycle states.
|
|
42
|
+
|
|
43
|
+
### Status Code Scheme
|
|
44
|
+
|
|
45
|
+
Status codes follow a numerical prefix pattern inspired by HTTP status codes:
|
|
46
|
+
|
|
47
|
+
| Prefix | Category | Meaning | Reversibility |
|
|
48
|
+
|--------|----------|---------|---------------|
|
|
49
|
+
| **0xx** | Initial | Entity creation/draft state | N/A |
|
|
50
|
+
| **1xx** | Pending | Awaiting action or decision | Reversible |
|
|
51
|
+
| **2xx** | Active | In progress or running | Reversible |
|
|
52
|
+
| **3xx** | Completed | Positive terminal state | Terminal |
|
|
53
|
+
| **4xx** | Inactive | Negative but reversible | Reversible |
|
|
54
|
+
| **5xx** | Failed | Negative terminal state | Terminal |
|
|
55
|
+
|
|
56
|
+
### 0xx - Initial States
|
|
57
|
+
|
|
58
|
+
Initial states for entities being created or in draft mode.
|
|
59
|
+
|
|
60
|
+
| Constant | Value | Description |
|
|
61
|
+
|----------|-------|-------------|
|
|
62
|
+
| `UNKNOWN` | `'000_UNKNOWN'` | Unknown or uninitialized state |
|
|
63
|
+
| `DRAFT` | `'001_DRAFT'` | Draft state, not yet finalized |
|
|
64
|
+
|
|
65
|
+
**Example Usage:**
|
|
66
|
+
```typescript
|
|
67
|
+
import { Statuses } from '@venizia/ignis';
|
|
68
|
+
|
|
69
|
+
const article = await articleRepository.create({
|
|
70
|
+
title: 'My Article',
|
|
71
|
+
status: Statuses.DRAFT, // Still being written
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 1xx - Pending/Waiting States
|
|
76
|
+
|
|
77
|
+
States indicating the entity is awaiting action, approval, or processing.
|
|
78
|
+
|
|
79
|
+
| Constant | Value | Description |
|
|
80
|
+
|----------|-------|-------------|
|
|
81
|
+
| `NEW` | `'100_NEW'` | Newly created, not yet processed |
|
|
82
|
+
| `QUEUED` | `'101_QUEUED'` | Queued for processing |
|
|
83
|
+
| `SCHEDULED` | `'102_SCHEDULED'` | Scheduled for future execution |
|
|
84
|
+
| `PENDING` | `'103_PENDING'` | Awaiting action or decision |
|
|
85
|
+
| `IN_REVIEW` | `'104_IN_REVIEW'` | Under review or approval process |
|
|
86
|
+
|
|
87
|
+
**Example Usage:**
|
|
88
|
+
```typescript
|
|
89
|
+
// Job queue
|
|
90
|
+
const job = await jobRepository.create({
|
|
91
|
+
name: 'send-email',
|
|
92
|
+
status: Statuses.QUEUED,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Approval workflow
|
|
96
|
+
const post = await postRepository.update(postId, {
|
|
97
|
+
status: Statuses.IN_REVIEW, // Submitted for moderation
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2xx - Active/Running States
|
|
102
|
+
|
|
103
|
+
States indicating the entity is actively being processed or is currently operational.
|
|
104
|
+
|
|
105
|
+
| Constant | Value | Description |
|
|
106
|
+
|----------|-------|-------------|
|
|
107
|
+
| `ENABLED` | `'200_ENABLED'` | Feature or entity is enabled |
|
|
108
|
+
| `ACTIVATED` | `'201_ACTIVATED'` | Account or service is active |
|
|
109
|
+
| `RUNNING` | `'202_RUNNING'` | Process is currently running |
|
|
110
|
+
| `PROCESSING` | `'203_PROCESSING'` | Being actively processed |
|
|
111
|
+
| `SENT` | `'204_SENT'` | Message/item has been sent |
|
|
112
|
+
| `RECEIVED` | `'205_RECEIVED'` | Message/item has been received |
|
|
113
|
+
|
|
114
|
+
**Example Usage:**
|
|
115
|
+
```typescript
|
|
116
|
+
// User account activation
|
|
117
|
+
await userRepository.update(userId, {
|
|
118
|
+
status: Statuses.ACTIVATED,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Background job
|
|
122
|
+
await jobRepository.update(jobId, {
|
|
123
|
+
status: Statuses.RUNNING,
|
|
124
|
+
startedAt: new Date(),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Email tracking
|
|
128
|
+
await emailRepository.create({
|
|
129
|
+
to: 'user@example.com',
|
|
130
|
+
subject: 'Welcome',
|
|
131
|
+
status: Statuses.SENT,
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 3xx - Completed States
|
|
136
|
+
|
|
137
|
+
Positive terminal states indicating successful completion.
|
|
138
|
+
|
|
139
|
+
| Constant | Value | Description |
|
|
140
|
+
|----------|-------|-------------|
|
|
141
|
+
| `PARTIAL` | `'300_PARTIAL'` | Partially completed |
|
|
142
|
+
| `APPROVED` | `'301_APPROVED'` | Approved by reviewer |
|
|
143
|
+
| `SUCCESS` | `'302_SUCCESS'` | Successfully completed |
|
|
144
|
+
| `COMPLETED` | `'303_COMPLETED'` | Fully completed |
|
|
145
|
+
| `SETTLED` | `'304_SETTLED'` | Finalized or settled |
|
|
146
|
+
|
|
147
|
+
**Example Usage:**
|
|
148
|
+
```typescript
|
|
149
|
+
// Job completion
|
|
150
|
+
await jobRepository.update(jobId, {
|
|
151
|
+
status: Statuses.SUCCESS,
|
|
152
|
+
completedAt: new Date(),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Approval workflow
|
|
156
|
+
await documentRepository.update(docId, {
|
|
157
|
+
status: Statuses.APPROVED,
|
|
158
|
+
approvedBy: userId,
|
|
159
|
+
approvedAt: new Date(),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Batch processing
|
|
163
|
+
await batchRepository.update(batchId, {
|
|
164
|
+
status: Statuses.PARTIAL, // Some items succeeded
|
|
165
|
+
processedCount: 75,
|
|
166
|
+
totalCount: 100,
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 4xx - Inactive States
|
|
171
|
+
|
|
172
|
+
Negative but reversible states - the entity can be reactivated.
|
|
173
|
+
|
|
174
|
+
| Constant | Value | Description |
|
|
175
|
+
|----------|-------|-------------|
|
|
176
|
+
| `DISABLED` | `'400_DISABLED'` | Feature or entity is disabled |
|
|
177
|
+
| `DEACTIVATED` | `'401_DEACTIVATED'` | Account or service is deactivated |
|
|
178
|
+
| `SUSPENDED` | `'402_SUSPENDED'` | Temporarily suspended |
|
|
179
|
+
| `BLOCKED` | `'403_BLOCKED'` | Access blocked (e.g., banned user) |
|
|
180
|
+
| `CLOSED` | `'404_CLOSED'` | Closed but can be reopened |
|
|
181
|
+
| `ARCHIVED` | `'405_ARCHIVED'` | Archived for record keeping |
|
|
182
|
+
| `PAUSED` | `'406_PAUSED'` | Paused, can be resumed |
|
|
183
|
+
| `REVOKED` | `'407_REVOKED'` | Permission or access revoked |
|
|
184
|
+
|
|
185
|
+
**Example Usage:**
|
|
186
|
+
```typescript
|
|
187
|
+
// User account management
|
|
188
|
+
await userRepository.update(userId, {
|
|
189
|
+
status: Statuses.SUSPENDED, // Temporarily suspended
|
|
190
|
+
suspendedUntil: addDays(new Date(), 7),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Feature flags
|
|
194
|
+
await featureRepository.update(featureId, {
|
|
195
|
+
status: Statuses.DISABLED, // Feature turned off
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Ticket system
|
|
199
|
+
await ticketRepository.update(ticketId, {
|
|
200
|
+
status: Statuses.CLOSED, // Can be reopened if needed
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 5xx - Failed/Error States
|
|
205
|
+
|
|
206
|
+
Negative terminal states indicating permanent failure or cancellation.
|
|
207
|
+
|
|
208
|
+
| Constant | Value | Description |
|
|
209
|
+
|----------|-------|-------------|
|
|
210
|
+
| `FAIL` | `'500_FAIL'` | General failure |
|
|
211
|
+
| `EXPIRED` | `'501_EXPIRED'` | Expired and no longer valid |
|
|
212
|
+
| `TIMEOUT` | `'502_TIMEOUT'` | Operation timed out |
|
|
213
|
+
| `SKIPPED` | `'503_SKIPPED'` | Intentionally skipped |
|
|
214
|
+
| `ABORTED` | `'504_ABORTED'` | Aborted by system |
|
|
215
|
+
| `CANCELLED` | `'505_CANCELLED'` | Cancelled by user/admin |
|
|
216
|
+
| `DELETED` | `'506_DELETED'` | Soft deleted |
|
|
217
|
+
| `REJECTED` | `'507_REJECTED'` | Rejected by reviewer |
|
|
218
|
+
|
|
219
|
+
**Example Usage:**
|
|
220
|
+
```typescript
|
|
221
|
+
// Job failure
|
|
222
|
+
await jobRepository.update(jobId, {
|
|
223
|
+
status: Statuses.FAIL,
|
|
224
|
+
error: 'Connection timeout',
|
|
225
|
+
failedAt: new Date(),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Token expiration
|
|
229
|
+
await tokenRepository.update(tokenId, {
|
|
230
|
+
status: Statuses.EXPIRED,
|
|
231
|
+
expiredAt: new Date(),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Soft delete
|
|
235
|
+
await productRepository.update(productId, {
|
|
236
|
+
status: Statuses.DELETED,
|
|
237
|
+
deletedAt: new Date(),
|
|
238
|
+
deletedBy: userId,
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Status Groups
|
|
245
|
+
|
|
246
|
+
The `Statuses` class provides static sets for grouping related statuses.
|
|
247
|
+
|
|
248
|
+
### Available Groups
|
|
249
|
+
|
|
250
|
+
| Group | Set Name | Included Statuses |
|
|
251
|
+
|-------|----------|-------------------|
|
|
252
|
+
| Initial | `INITIAL_SCHEME_SET` | `UNKNOWN`, `DRAFT` |
|
|
253
|
+
| Pending | `PENDING_SCHEME_SET` | `NEW`, `QUEUED`, `SCHEDULED`, `PENDING`, `IN_REVIEW` |
|
|
254
|
+
| Active | `ACTIVE_SCHEME_SET` | `ENABLED`, `ACTIVATED`, `RUNNING`, `PROCESSING`, `SENT`, `RECEIVED` |
|
|
255
|
+
| Completed | `COMPLETED_SCHEME_SET` | `PARTIAL`, `APPROVED`, `SUCCESS`, `COMPLETED`, `SETTLED` |
|
|
256
|
+
| Inactive | `INACTIVE_SCHEME_SET` | `DISABLED`, `DEACTIVATED`, `SUSPENDED`, `BLOCKED`, `CLOSED`, `ARCHIVED`, `PAUSED`, `REVOKED` |
|
|
257
|
+
| Failed | `FAILED_SCHEME_SET` | `FAIL`, `EXPIRED`, `TIMEOUT`, `SKIPPED`, `ABORTED`, `CANCELLED`, `DELETED`, `REJECTED` |
|
|
258
|
+
| All | `SCHEME_SET` | All statuses combined |
|
|
259
|
+
|
|
260
|
+
### Usage
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { Statuses } from '@venizia/ignis';
|
|
264
|
+
|
|
265
|
+
// Check if status is in a group
|
|
266
|
+
if (Statuses.ACTIVE_SCHEME_SET.has(order.status)) {
|
|
267
|
+
console.log('Order is being processed');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Filter active jobs
|
|
271
|
+
const activeJobs = jobs.filter(job =>
|
|
272
|
+
Statuses.ACTIVE_SCHEME_SET.has(job.status)
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
// Check if operation can proceed
|
|
276
|
+
const canRetry = !Statuses.FAILED_SCHEME_SET.has(task.status);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Validation Methods
|
|
282
|
+
|
|
283
|
+
The `Statuses` class provides helper methods for checking status categories.
|
|
284
|
+
|
|
285
|
+
### Available Methods
|
|
286
|
+
|
|
287
|
+
| Method | Parameters | Returns | Description |
|
|
288
|
+
|--------|------------|---------|-------------|
|
|
289
|
+
| `isInitial(status)` | `status: string` | `boolean` | Check if status is in initial group |
|
|
290
|
+
| `isPending(status)` | `status: string` | `boolean` | Check if status is in pending group |
|
|
291
|
+
| `isActive(status)` | `status: string` | `boolean` | Check if status is in active group |
|
|
292
|
+
| `isCompleted(status)` | `status: string` | `boolean` | Check if status is in completed group |
|
|
293
|
+
| `isInactive(status)` | `status: string` | `boolean` | Check if status is in inactive group |
|
|
294
|
+
| `isFailed(status)` | `status: string` | `boolean` | Check if status is in failed group |
|
|
295
|
+
| `isValid(status)` | `status: string` | `boolean` | Check if status is a valid status code |
|
|
296
|
+
|
|
297
|
+
### Examples
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { Statuses } from '@venizia/ignis';
|
|
301
|
+
|
|
302
|
+
// Conditional logic based on status
|
|
303
|
+
if (Statuses.isActive(user.status)) {
|
|
304
|
+
// User can log in
|
|
305
|
+
await processLogin(user);
|
|
306
|
+
} else if (Statuses.isInactive(user.status)) {
|
|
307
|
+
throw new Error('Account is inactive. Please contact support.');
|
|
308
|
+
} else if (Statuses.isFailed(user.status)) {
|
|
309
|
+
throw new Error('Account has been permanently closed.');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Validation
|
|
313
|
+
function validateStatusTransition(from: string, to: string) {
|
|
314
|
+
if (!Statuses.isValid(to)) {
|
|
315
|
+
throw new Error(`Invalid status: ${to}`);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Don't allow transitions from terminal states
|
|
319
|
+
if (Statuses.isCompleted(from) || Statuses.isFailed(from)) {
|
|
320
|
+
throw new Error('Cannot transition from terminal state');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Filter entities
|
|
327
|
+
const activeUsers = users.filter(user => Statuses.isActive(user.status));
|
|
328
|
+
const pendingOrders = orders.filter(order => Statuses.isPending(order.status));
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Specialized Status Classes
|
|
334
|
+
|
|
335
|
+
### MigrationStatuses
|
|
336
|
+
|
|
337
|
+
Simplified statuses for database migration tracking.
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { MigrationStatuses } from '@venizia/ignis';
|
|
341
|
+
|
|
342
|
+
class MigrationStatuses {
|
|
343
|
+
static readonly UNKNOWN = '000_UNKNOWN';
|
|
344
|
+
static readonly SUCCESS = '302_SUCCESS';
|
|
345
|
+
static readonly FAIL = '500_FAIL';
|
|
346
|
+
|
|
347
|
+
static readonly SCHEME_SET = new Set([
|
|
348
|
+
this.UNKNOWN,
|
|
349
|
+
this.SUCCESS,
|
|
350
|
+
this.FAIL,
|
|
351
|
+
]);
|
|
352
|
+
|
|
353
|
+
static isValid(scheme: string): boolean;
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Usage:**
|
|
358
|
+
```typescript
|
|
359
|
+
await migrationRepository.create({
|
|
360
|
+
version: '20240103_001',
|
|
361
|
+
name: 'add_users_table',
|
|
362
|
+
status: MigrationStatuses.SUCCESS,
|
|
363
|
+
appliedAt: new Date(),
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### CommonStatuses
|
|
368
|
+
|
|
369
|
+
Common statuses used across multiple entity types.
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { CommonStatuses } from '@venizia/ignis';
|
|
373
|
+
|
|
374
|
+
class CommonStatuses {
|
|
375
|
+
static readonly UNKNOWN = '000_UNKNOWN';
|
|
376
|
+
static readonly ACTIVATED = '201_ACTIVATED';
|
|
377
|
+
static readonly DEACTIVATED = '401_DEACTIVATED';
|
|
378
|
+
static readonly BLOCKED = '403_BLOCKED';
|
|
379
|
+
static readonly ARCHIVED = '405_ARCHIVED';
|
|
380
|
+
|
|
381
|
+
static readonly SCHEME_SET = new Set([...]);
|
|
382
|
+
static isValid(scheme: string): boolean;
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Usage:**
|
|
387
|
+
```typescript
|
|
388
|
+
// User management
|
|
389
|
+
await userRepository.update(userId, {
|
|
390
|
+
status: CommonStatuses.ACTIVATED,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Role management
|
|
394
|
+
await roleRepository.update(roleId, {
|
|
395
|
+
status: CommonStatuses.ARCHIVED,
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### UserStatuses & RoleStatuses
|
|
400
|
+
|
|
401
|
+
Aliases for `CommonStatuses` with semantic naming.
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
import { UserStatuses, RoleStatuses } from '@venizia/ignis';
|
|
405
|
+
|
|
406
|
+
// UserStatuses extends CommonStatuses
|
|
407
|
+
const user = await userRepository.create({
|
|
408
|
+
email: 'user@example.com',
|
|
409
|
+
status: UserStatuses.ACTIVATED,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// RoleStatuses extends CommonStatuses
|
|
413
|
+
const role = await roleRepository.create({
|
|
414
|
+
name: 'admin',
|
|
415
|
+
status: RoleStatuses.ACTIVATED,
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### UserTypes
|
|
420
|
+
|
|
421
|
+
Classification of user types in the system.
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import { UserTypes } from '@venizia/ignis';
|
|
425
|
+
|
|
426
|
+
class UserTypes {
|
|
427
|
+
static readonly SYSTEM = 'SYSTEM'; // System-generated users
|
|
428
|
+
static readonly LINKED = 'LINKED'; // External auth (OAuth, SAML)
|
|
429
|
+
|
|
430
|
+
static readonly SCHEME_SET = new Set([this.SYSTEM, this.LINKED]);
|
|
431
|
+
static isValid(orgType: string): boolean;
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Usage:**
|
|
436
|
+
```typescript
|
|
437
|
+
// Create system user
|
|
438
|
+
const systemUser = await userRepository.create({
|
|
439
|
+
email: 'system@app.com',
|
|
440
|
+
type: UserTypes.SYSTEM,
|
|
441
|
+
status: UserStatuses.ACTIVATED,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// OAuth linked user
|
|
445
|
+
const oauthUser = await userRepository.create({
|
|
446
|
+
email: 'user@example.com',
|
|
447
|
+
type: UserTypes.LINKED,
|
|
448
|
+
linkedProvider: 'google',
|
|
449
|
+
status: UserStatuses.ACTIVATED,
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Usage Examples
|
|
456
|
+
|
|
457
|
+
### Entity Lifecycle Management
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
import { Statuses } from '@venizia/ignis';
|
|
461
|
+
|
|
462
|
+
class OrderService extends BaseService {
|
|
463
|
+
async createOrder(data: CreateOrderDto) {
|
|
464
|
+
// Start as NEW
|
|
465
|
+
const order = await this.orderRepository.create({
|
|
466
|
+
...data,
|
|
467
|
+
status: Statuses.NEW,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Queue for processing
|
|
471
|
+
await this.orderRepository.update(order.id, {
|
|
472
|
+
status: Statuses.QUEUED,
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
return order;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async processOrder(orderId: string) {
|
|
479
|
+
// Mark as processing
|
|
480
|
+
await this.orderRepository.update(orderId, {
|
|
481
|
+
status: Statuses.PROCESSING,
|
|
482
|
+
startedAt: new Date(),
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
// Process order logic...
|
|
487
|
+
await this.paymentService.charge(order);
|
|
488
|
+
await this.inventoryService.reserve(order.items);
|
|
489
|
+
|
|
490
|
+
// Mark as completed
|
|
491
|
+
await this.orderRepository.update(orderId, {
|
|
492
|
+
status: Statuses.COMPLETED,
|
|
493
|
+
completedAt: new Date(),
|
|
494
|
+
});
|
|
495
|
+
} catch (error) {
|
|
496
|
+
// Mark as failed
|
|
497
|
+
await this.orderRepository.update(orderId, {
|
|
498
|
+
status: Statuses.FAIL,
|
|
499
|
+
error: error.message,
|
|
500
|
+
failedAt: new Date(),
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
async cancelOrder(orderId: string) {
|
|
508
|
+
const order = await this.orderRepository.findById(orderId);
|
|
509
|
+
|
|
510
|
+
// Can only cancel pending or active orders
|
|
511
|
+
if (Statuses.isCompleted(order.status) || Statuses.isFailed(order.status)) {
|
|
512
|
+
throw new Error('Cannot cancel completed or failed order');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
await this.orderRepository.update(orderId, {
|
|
516
|
+
status: Statuses.CANCELLED,
|
|
517
|
+
cancelledAt: new Date(),
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Status-Based Queries
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
import { Statuses } from '@venizia/ignis';
|
|
527
|
+
|
|
528
|
+
class JobService extends BaseService {
|
|
529
|
+
// Get all jobs that can be retried
|
|
530
|
+
async getRetryableJobs() {
|
|
531
|
+
return this.jobRepository.find({
|
|
532
|
+
where: {
|
|
533
|
+
status: { in: [...Statuses.FAILED_SCHEME_SET] },
|
|
534
|
+
retryCount: { lt: 3 },
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Get active jobs count
|
|
540
|
+
async getActiveJobsCount() {
|
|
541
|
+
return this.jobRepository.count({
|
|
542
|
+
where: {
|
|
543
|
+
status: { in: [...Statuses.ACTIVE_SCHEME_SET] },
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Archive old completed jobs
|
|
549
|
+
async archiveCompletedJobs(daysOld: number) {
|
|
550
|
+
const cutoffDate = new Date();
|
|
551
|
+
cutoffDate.setDate(cutoffDate.getDate() - daysOld);
|
|
552
|
+
|
|
553
|
+
return this.jobRepository.updateMany({
|
|
554
|
+
where: {
|
|
555
|
+
status: { in: [...Statuses.COMPLETED_SCHEME_SET] },
|
|
556
|
+
completedAt: { lt: cutoffDate },
|
|
557
|
+
},
|
|
558
|
+
data: {
|
|
559
|
+
status: Statuses.ARCHIVED,
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Validation & State Transitions
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
import { Statuses } from '@venizia/ignis';
|
|
570
|
+
|
|
571
|
+
class TaskService extends BaseService {
|
|
572
|
+
async updateTaskStatus(taskId: string, newStatus: string) {
|
|
573
|
+
// Validate status
|
|
574
|
+
if (!Statuses.isValid(newStatus)) {
|
|
575
|
+
throw new Error(`Invalid status: ${newStatus}`);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const task = await this.taskRepository.findById(taskId);
|
|
579
|
+
|
|
580
|
+
// Validate transition
|
|
581
|
+
this.validateStatusTransition(task.status, newStatus);
|
|
582
|
+
|
|
583
|
+
await this.taskRepository.update(taskId, {
|
|
584
|
+
status: newStatus,
|
|
585
|
+
statusChangedAt: new Date(),
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
private validateStatusTransition(from: string, to: string) {
|
|
590
|
+
// Cannot transition from terminal states
|
|
591
|
+
if (Statuses.isCompleted(from) || Statuses.isFailed(from)) {
|
|
592
|
+
throw new Error('Cannot change status from terminal state');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Can only move to COMPLETED from ACTIVE or PENDING
|
|
596
|
+
if (to === Statuses.COMPLETED) {
|
|
597
|
+
if (!Statuses.isActive(from) && !Statuses.isPending(from)) {
|
|
598
|
+
throw new Error('Can only complete active or pending tasks');
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Additional transition rules...
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Binding Namespaces
|
|
610
|
+
|
|
611
|
+
The `BindingNamespaces` class organizes dependency injection bindings by type.
|
|
612
|
+
|
|
613
|
+
**File:** `packages/core/src/common/bindings.ts`
|
|
614
|
+
|
|
615
|
+
### Available Namespaces
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import { BindingNamespaces } from '@venizia/ignis';
|
|
619
|
+
|
|
620
|
+
class BindingNamespaces {
|
|
621
|
+
static readonly COMPONENT = 'components';
|
|
622
|
+
static readonly DATASOURCE = 'datasources';
|
|
623
|
+
static readonly REPOSITORY = 'repositories';
|
|
624
|
+
static readonly MODEL = 'models';
|
|
625
|
+
static readonly SERVICE = 'services';
|
|
626
|
+
static readonly MIDDLEWARE = 'middlewares';
|
|
627
|
+
static readonly PROVIDER = 'providers';
|
|
628
|
+
static readonly CONTROLLER = 'controllers';
|
|
629
|
+
static readonly BOOTERS = 'booters';
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### CoreBindings
|
|
634
|
+
|
|
635
|
+
Application-level binding keys:
|
|
636
|
+
|
|
637
|
+
```typescript
|
|
638
|
+
import { CoreBindings } from '@venizia/ignis';
|
|
639
|
+
|
|
640
|
+
class CoreBindings {
|
|
641
|
+
static readonly APPLICATION_INSTANCE = '@app/instance';
|
|
642
|
+
static readonly APPLICATION_SERVER = '@app/server';
|
|
643
|
+
static readonly APPLICATION_CONFIG = '@app/config';
|
|
644
|
+
static readonly APPLICATION_PROJECT_ROOT = '@app/project_root';
|
|
645
|
+
static readonly APPLICATION_ROOT_ROUTER = '@app/router/root';
|
|
646
|
+
static readonly APPLICATION_ENVIRONMENTS = '@app/environments';
|
|
647
|
+
static readonly APPLICATION_MIDDLEWARE_OPTIONS = '@app/middleware_options';
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**Usage:**
|
|
652
|
+
```typescript
|
|
653
|
+
// Access application instance
|
|
654
|
+
const app = container.get(CoreBindings.APPLICATION_INSTANCE);
|
|
655
|
+
|
|
656
|
+
// Access configuration
|
|
657
|
+
const config = container.get(CoreBindings.APPLICATION_CONFIG);
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## Best Practices
|
|
663
|
+
|
|
664
|
+
### 1. Use Status Constants
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
// ✅ Good: Use constants
|
|
668
|
+
order.status = Statuses.COMPLETED;
|
|
669
|
+
|
|
670
|
+
// ❌ Bad: Magic strings
|
|
671
|
+
order.status = '303_COMPLETED'; // Prone to typos
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### 2. Validate Before Updating
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
// ✅ Good: Validate transitions
|
|
678
|
+
if (Statuses.isCompleted(order.status)) {
|
|
679
|
+
throw new Error('Cannot modify completed order');
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// ❌ Bad: No validation
|
|
683
|
+
order.status = newStatus; // Could break business rules
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### 3. Use Helper Methods
|
|
687
|
+
|
|
688
|
+
```typescript
|
|
689
|
+
// ✅ Good: Use helper methods
|
|
690
|
+
if (Statuses.isActive(job.status)) {
|
|
691
|
+
// ...
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// ❌ Bad: Manual set checking
|
|
695
|
+
if (Statuses.ACTIVE_SCHEME_SET.has(job.status)) {
|
|
696
|
+
// Less readable
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### 4. Document State Machines
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
/**
|
|
704
|
+
* Order Status Flow:
|
|
705
|
+
* NEW → QUEUED → PROCESSING → COMPLETED
|
|
706
|
+
* ↓ ↓ ↓
|
|
707
|
+
* CANCELLED ← ← ← ← ← ←
|
|
708
|
+
*/
|
|
709
|
+
class OrderService {
|
|
710
|
+
// Implementation...
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### 5. Terminal State Checks
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
// ✅ Good: Check for terminal states
|
|
718
|
+
const isTerminal = Statuses.isCompleted(status) || Statuses.isFailed(status);
|
|
719
|
+
|
|
720
|
+
if (isTerminal) {
|
|
721
|
+
throw new Error('Cannot modify entity in terminal state');
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## See Also
|
|
728
|
+
|
|
729
|
+
- **Related References:**
|
|
730
|
+
- [Models](../base/models.md) - Entity definitions using statuses
|
|
731
|
+
- [Repositories](../base/repositories/) - Querying by status
|
|
732
|
+
- [Services](../base/services.md) - Business logic with status transitions
|
|
733
|
+
|
|
734
|
+
- **Guides:**
|
|
735
|
+
- [Data Modeling](/guides/core-concepts/models.md)
|
|
736
|
+
- [Working with Repositories](/guides/core-concepts/repositories.md)
|
|
737
|
+
|
|
738
|
+
- **Best Practices:**
|
|
739
|
+
- [State Machine Patterns](/best-practices/architecture/state-machines.md)
|
|
740
|
+
- [Entity Lifecycle Management](/best-practices/architecture/entity-lifecycle.md)
|