@venizia/ignis-docs 0.0.2 → 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 +647 -182
- 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 +86 -0
- package/wiki/changelogs/2025-12-26-transaction-support.md +57 -0
- 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 +8 -1
- package/wiki/changelogs/planned-schema-migrator.md +2 -10
- 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/guides/core-concepts/components.md +122 -0
- 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 +532 -31
- package/wiki/references/base/controllers.md +136 -38
- package/wiki/references/base/datasources.md +108 -5
- 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 -549
- 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 +15 -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 +167 -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/changelogs/planned-transaction-support.md +0 -216
- 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 -88
- package/wiki/get-started/best-practices/security-guidelines.md +0 -99
- package/wiki/get-started/core-concepts/components.md +0 -98
- package/wiki/get-started/core-concepts/persistent.md +0 -543
- package/wiki/get-started/index.md +0 -65
- package/wiki/get-started/philosophy.md +0 -296
- package/wiki/get-started/prerequisites.md +0 -113
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# Data Modeling
|
|
2
|
-
|
|
3
|
-
Ignis streamlines data modeling with Drizzle ORM by providing powerful helpers and "enrichers" that reduce boilerplate code for common schema patterns.
|
|
4
|
-
|
|
5
|
-
## 1. Base Entity
|
|
6
|
-
|
|
7
|
-
All entity models should extend `BaseEntity`. This provides integration with the framework's repository layer and automatic schema generation support.
|
|
8
|
-
|
|
9
|
-
The recommended pattern is to define the schema and relations as **static properties** on the class. This keeps the definition self-contained and enables powerful type inference.
|
|
10
|
-
|
|
11
|
-
**Example (`src/models/entities/user.model.ts`):**
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import { BaseEntity, extraUserColumns, generateIdColumnDefs, model } from '@venizia/ignis';
|
|
15
|
-
import { pgTable } from 'drizzle-orm/pg-core';
|
|
16
|
-
|
|
17
|
-
@model({ type: 'entity' })
|
|
18
|
-
export class User extends BaseEntity<typeof User.schema> {
|
|
19
|
-
// 1. Define schema as a static property
|
|
20
|
-
static override schema = pgTable('User', {
|
|
21
|
-
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
22
|
-
...extraUserColumns({ idType: 'string' }),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// 2. Define relations as a static method (return empty array if none)
|
|
26
|
-
static override relations = () => [];
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## 2. Schema Enrichers
|
|
31
|
-
|
|
32
|
-
Instead of manually defining common columns like primary keys, timestamps, or audit fields in every table, use Ignis "enrichers".
|
|
33
|
-
|
|
34
|
-
**Available Enrichers:**
|
|
35
|
-
|
|
36
|
-
| Enricher | Description | Columns Added |
|
|
37
|
-
|----------|-------------|---------------|
|
|
38
|
-
| `generateIdColumnDefs` | Adds a Primary Key | `id` (string/UUID or number/Serial) |
|
|
39
|
-
| `generateTzColumnDefs` | Adds timestamps | `createdAt`, `modifiedAt` (auto-updating) |
|
|
40
|
-
| `generateUserAuditColumnDefs` | Adds audit fields | `createdBy`, `modifiedBy` |
|
|
41
|
-
| `generateDataTypeColumnDefs` | Adds generic value fields | `nValue` (number), `tValue` (text), `jValue` (json), etc. |
|
|
42
|
-
| `extraUserColumns` | Comprehensive user fields | Combines audit, timestamps, status, and type fields |
|
|
43
|
-
|
|
44
|
-
**Usage Example:**
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
import {
|
|
48
|
-
generateIdColumnDefs,
|
|
49
|
-
generateTzColumnDefs,
|
|
50
|
-
generateUserAuditColumnDefs,
|
|
51
|
-
} from '@venizia/ignis';
|
|
52
|
-
import { pgTable, text } from 'drizzle-orm/pg-core';
|
|
53
|
-
|
|
54
|
-
export const configurationTable = pgTable(
|
|
55
|
-
'Configuration',
|
|
56
|
-
{
|
|
57
|
-
// 1. Auto-generate UUID Primary Key
|
|
58
|
-
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
59
|
-
|
|
60
|
-
// 2. Auto-generate createdAt / modifiedAt
|
|
61
|
-
...generateTzColumnDefs(),
|
|
62
|
-
|
|
63
|
-
// 3. Auto-generate createdBy / modifiedBy
|
|
64
|
-
...generateUserAuditColumnDefs({
|
|
65
|
-
created: { dataType: 'string', columnName: 'created_by' },
|
|
66
|
-
modified: { dataType: 'string', columnName: 'modified_by' },
|
|
67
|
-
}),
|
|
68
|
-
|
|
69
|
-
// 4. Your custom columns
|
|
70
|
-
code: text('code').notNull(),
|
|
71
|
-
description: text('description'),
|
|
72
|
-
group: text('group').notNull(),
|
|
73
|
-
},
|
|
74
|
-
(table) => [
|
|
75
|
-
// Define indexes/constraints here
|
|
76
|
-
unique('UQ_code').on(table.code),
|
|
77
|
-
]
|
|
78
|
-
);
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## 3. Defining Relations
|
|
82
|
-
|
|
83
|
-
Relations are defined using the `TRelationConfig` structure within the static `relations` method of your model.
|
|
84
|
-
|
|
85
|
-
**Example (`src/models/entities/configuration.model.ts`):**
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import {
|
|
89
|
-
BaseEntity,
|
|
90
|
-
model,
|
|
91
|
-
RelationTypes,
|
|
92
|
-
TRelationConfig,
|
|
93
|
-
} from '@venizia/ignis';
|
|
94
|
-
import { User } from './user.model';
|
|
95
|
-
|
|
96
|
-
@model({ type: 'entity' })
|
|
97
|
-
export class Configuration extends BaseEntity<typeof Configuration.schema> {
|
|
98
|
-
// ... schema definition ...
|
|
99
|
-
|
|
100
|
-
// Define relations
|
|
101
|
-
static override relations = (): TRelationConfig[] => [
|
|
102
|
-
{
|
|
103
|
-
name: 'creator',
|
|
104
|
-
type: RelationTypes.ONE,
|
|
105
|
-
schema: User.schema,
|
|
106
|
-
metadata: {
|
|
107
|
-
fields: [Configuration.schema.createdBy],
|
|
108
|
-
references: [User.schema.id],
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## 4. Repositories and Auto-Discovery
|
|
116
|
-
|
|
117
|
-
Ignis simplifies the connection between models, repositories, and datasources.
|
|
118
|
-
|
|
119
|
-
### DataSource Auto-Discovery
|
|
120
|
-
|
|
121
|
-
DataSources automatically discover their schema from the repositories that bind to them. You **do not** need to manually register schemas in the DataSource constructor.
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
// src/datasources/postgres.datasource.ts
|
|
125
|
-
@datasource({ driver: 'node-postgres' })
|
|
126
|
-
export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
|
|
127
|
-
constructor() {
|
|
128
|
-
super({
|
|
129
|
-
name: PostgresDataSource.name,
|
|
130
|
-
config: { /* connection config */ },
|
|
131
|
-
// NO schema property needed - auto-discovered!
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
override configure(): ValueOrPromise<void> {
|
|
136
|
-
// This method automatically collects all schemas from bound repositories
|
|
137
|
-
const schema = this.getSchema();
|
|
138
|
-
this.connector = drizzle({ client: new Pool(this.settings), schema });
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Repository Binding
|
|
144
|
-
|
|
145
|
-
Repositories use the `@repository` decorator to bind a **Model** to a **DataSource**. This binding is what powers the auto-discovery mechanism.
|
|
146
|
-
|
|
147
|
-
**Pattern 1: Zero Boilerplate (Recommended)**
|
|
148
|
-
|
|
149
|
-
For most repositories, you don't need a constructor. The DataSource is automatically injected.
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
@repository({ model: Configuration, dataSource: PostgresDataSource })
|
|
153
|
-
export class ConfigurationRepository extends DefaultCRUDRepository<typeof Configuration.schema> {
|
|
154
|
-
// No constructor needed!
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**Pattern 2: Explicit Injection (Advanced)**
|
|
159
|
-
|
|
160
|
-
If you need to perform custom initialization or inject additional dependencies, you can define a constructor. **Important:** The first parameter must be the DataSource.
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
@repository({ model: User, dataSource: PostgresDataSource })
|
|
164
|
-
export class UserRepository extends ReadableRepository<typeof User.schema> {
|
|
165
|
-
constructor(
|
|
166
|
-
@inject({ key: 'datasources.PostgresDataSource' })
|
|
167
|
-
dataSource: PostgresDataSource,
|
|
168
|
-
) {
|
|
169
|
-
super(dataSource);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Custom methods
|
|
173
|
-
async findByRealm(realm: string) {
|
|
174
|
-
return this.findOne({ filter: { where: { realm } } });
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Deployment Strategies
|
|
2
|
-
|
|
3
|
-
Deploy your Ignis application reliably, securely, and efficiently.
|
|
4
|
-
|
|
5
|
-
## 1. Building for Production
|
|
6
|
-
|
|
7
|
-
Compile TypeScript to JavaScript before deploying:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
bun run build
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**What this does:**
|
|
14
|
-
1. `tsc -p tsconfig.json` - Compile TypeScript → JavaScript
|
|
15
|
-
2. `tsc-alias -p tsconfig.json` - Replace path aliases (`@/*`) with relative paths
|
|
16
|
-
|
|
17
|
-
**Output:** `dist/` folder with production-ready JavaScript.
|
|
18
|
-
|
|
19
|
-
## 2. Environment Configuration
|
|
20
|
-
|
|
21
|
-
Use environment variables for all configuration - never hard-code.
|
|
22
|
-
|
|
23
|
-
**Production Environment Variables:**
|
|
24
|
-
| Variable | Value | Purpose |
|
|
25
|
-
|----------|-------|---------|
|
|
26
|
-
| `NODE_ENV` | `production` | Enables performance optimizations |
|
|
27
|
-
| `APP_ENV_APPLICATION_SECRET` | Strong random string | Application secret |
|
|
28
|
-
| `APP_ENV_JWT_SECRET` | Strong random string | JWT signing key |
|
|
29
|
-
| `APP_ENV_POSTGRES_*` | Production DB credentials | Database connection |
|
|
30
|
-
| `APP_ENV_SERVER_HOST` | `0.0.0.0` | Accept connections from any IP |
|
|
31
|
-
| `APP_ENV_SERVER_PORT` | `3000` or cloud-assigned | Server port |
|
|
32
|
-
|
|
33
|
-
**Where to store:**
|
|
34
|
-
- **Docker:** Use environment variables in `docker-compose.yml` or secrets
|
|
35
|
-
- **Kubernetes:** ConfigMaps and Secrets
|
|
36
|
-
- **Cloud Platforms:** AWS Secrets Manager, Azure Key Vault, Google Secret Manager
|
|
37
|
-
|
|
38
|
-
## 3. Deployment Methods
|
|
39
|
-
|
|
40
|
-
### Docker Deployment (Recommended)
|
|
41
|
-
|
|
42
|
-
**Dockerfile:**
|
|
43
|
-
```dockerfile
|
|
44
|
-
FROM node:20-slim
|
|
45
|
-
|
|
46
|
-
WORKDIR /usr/src/app
|
|
47
|
-
|
|
48
|
-
# Copy dependency files
|
|
49
|
-
COPY package.json bun.lockb ./
|
|
50
|
-
|
|
51
|
-
# Install production dependencies
|
|
52
|
-
RUN bun install --production
|
|
53
|
-
|
|
54
|
-
# Copy source code
|
|
55
|
-
COPY . .
|
|
56
|
-
|
|
57
|
-
# Build TypeScript
|
|
58
|
-
RUN bun run build
|
|
59
|
-
|
|
60
|
-
# Expose port
|
|
61
|
-
EXPOSE 3000
|
|
62
|
-
|
|
63
|
-
# Start server
|
|
64
|
-
CMD [ "bun", "run", "server:prod" ]
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Build and deploy:**
|
|
68
|
-
```bash
|
|
69
|
-
# Build image
|
|
70
|
-
docker build -t my-ignis-app .
|
|
71
|
-
|
|
72
|
-
# Run container
|
|
73
|
-
docker run -p 3000:3000 \
|
|
74
|
-
-e NODE_ENV=production \
|
|
75
|
-
-e APP_ENV_APPLICATION_SECRET=xxx \
|
|
76
|
-
my-ignis-app
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Bun Single Executable (Alternative)
|
|
80
|
-
|
|
81
|
-
Compile your app into a single standalone binary:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
bun build --compile --minify --target=bun-linux-x64 \
|
|
85
|
-
./src/index.ts --outfile ./dist/my-app
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**Pros:** No dependencies needed on server, simple deployment
|
|
89
|
-
**Cons:** Platform-specific, newer technology (test thoroughly)
|
|
90
|
-
|
|
91
|
-
**Deploy:**
|
|
92
|
-
```bash
|
|
93
|
-
# Copy executable and .env to server
|
|
94
|
-
scp dist/my-app .env user@server:/app/
|
|
95
|
-
|
|
96
|
-
# Run
|
|
97
|
-
./my-app
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## 4. Production Best Practices
|
|
101
|
-
|
|
102
|
-
**Use a process manager:**
|
|
103
|
-
- **PM2** - For Node.js/Bun processes
|
|
104
|
-
- **systemd** - Linux service management
|
|
105
|
-
- **Docker/Kubernetes** - Built-in orchestration
|
|
106
|
-
|
|
107
|
-
**Example with PM2:**
|
|
108
|
-
```bash
|
|
109
|
-
pm2 start dist/index.js --name my-app -i max
|
|
110
|
-
pm2 save
|
|
111
|
-
pm2 startup
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Health checks:**
|
|
115
|
-
Add health check endpoint for load balancers:
|
|
116
|
-
```typescript
|
|
117
|
-
// In application.ts
|
|
118
|
-
this.component(HealthCheckComponent);
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Access at `/health-check` for liveness/readiness probes.
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Performance Optimization
|
|
2
|
-
|
|
3
|
-
Optimize your Ignis application for speed and scalability.
|
|
4
|
-
|
|
5
|
-
## 1. Measure Performance
|
|
6
|
-
|
|
7
|
-
Identify bottlenecks before optimizing:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { executeWithPerformanceMeasure } from '@venizia/ignis';
|
|
11
|
-
|
|
12
|
-
await executeWithPerformanceMeasure({
|
|
13
|
-
logger: this.logger,
|
|
14
|
-
scope: 'DataProcessing',
|
|
15
|
-
description: 'Process large dataset',
|
|
16
|
-
task: async () => {
|
|
17
|
-
await processLargeDataset();
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Logs execution time automatically.
|
|
23
|
-
|
|
24
|
-
> **Deep Dive:** See [Performance Utility](../../references/utilities/performance.md) for advanced profiling.
|
|
25
|
-
|
|
26
|
-
## 2. Offload CPU-Intensive Tasks
|
|
27
|
-
|
|
28
|
-
Prevent blocking the event loop with Worker Threads:
|
|
29
|
-
|
|
30
|
-
**Use Worker Threads for:**
|
|
31
|
-
- Complex calculations or crypto operations
|
|
32
|
-
- Large file/data processing
|
|
33
|
-
- Any synchronous task > 5ms
|
|
34
|
-
|
|
35
|
-
> **Deep Dive:** See [Worker Thread Helper](../../references/helpers/worker-thread.md) for implementation guide.
|
|
36
|
-
|
|
37
|
-
## 3. Optimize Database Queries
|
|
38
|
-
|
|
39
|
-
| Technique | Example | Impact |
|
|
40
|
-
|-----------|---------|--------|
|
|
41
|
-
| **Select specific fields** | `fields: { id: true, name: true }` | Reduce data transfer |
|
|
42
|
-
| **Use indexes** | Create indexes on WHERE/JOIN columns | 10-100x faster queries |
|
|
43
|
-
| **Paginate results** | `limit: 20, offset: 0` | Prevent memory overflow |
|
|
44
|
-
| **Eager load relations** | `include: [{ relation: 'creator' }]` | Solve N+1 problem |
|
|
45
|
-
|
|
46
|
-
**Example:**
|
|
47
|
-
```typescript
|
|
48
|
-
await userRepository.find({
|
|
49
|
-
filter: {
|
|
50
|
-
fields: { id: true, name: true, email: true }, // ✅ Specific fields
|
|
51
|
-
where: { status: 'ACTIVE' },
|
|
52
|
-
limit: 20, // ✅ Pagination
|
|
53
|
-
include: [{ relation: 'profile' }], // ✅ Eager load
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## 4. Implement Caching
|
|
59
|
-
|
|
60
|
-
Reduce database load with caching:
|
|
61
|
-
|
|
62
|
-
| Cache Type | Use Case | Implementation |
|
|
63
|
-
|-----------|----------|----------------|
|
|
64
|
-
| **Redis** | Distributed cache, session storage | [Redis Helper](../../references/helpers/redis.md) |
|
|
65
|
-
| **In-Memory** | Single-process cache | `MemoryStorageHelper` |
|
|
66
|
-
|
|
67
|
-
**Example:**
|
|
68
|
-
```typescript
|
|
69
|
-
// Cache expensive query results
|
|
70
|
-
const cached = await redis.get('users:active');
|
|
71
|
-
if (!cached) {
|
|
72
|
-
const users = await userRepository.find({ where: { active: true } });
|
|
73
|
-
await redis.set('users:active', users, 300); // 5 min TTL
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## 5. Production Settings
|
|
78
|
-
|
|
79
|
-
| Setting | Value | Why |
|
|
80
|
-
|---------|-------|-----|
|
|
81
|
-
| `NODE_ENV` | `production` | Enables library optimizations |
|
|
82
|
-
| Process Manager | PM2, systemd, Docker | Auto-restart, cluster mode |
|
|
83
|
-
| Cluster Mode | CPU cores | Utilize all CPUs |
|
|
84
|
-
|
|
85
|
-
**PM2 Cluster Mode:**
|
|
86
|
-
```bash
|
|
87
|
-
pm2 start dist/index.js -i max # Use all CPU cores
|
|
88
|
-
```
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# Security Guidelines
|
|
2
|
-
|
|
3
|
-
Critical security practices to protect your Ignis application.
|
|
4
|
-
|
|
5
|
-
## 1. Secret Management
|
|
6
|
-
|
|
7
|
-
**Never hard-code secrets.** Use environment variables for all sensitive data.
|
|
8
|
-
|
|
9
|
-
| Environment | Where to Store Secrets |
|
|
10
|
-
|-------------|----------------------|
|
|
11
|
-
| Development | `.env` file (add to `.gitignore`) |
|
|
12
|
-
| Production | Cloud provider's secret manager (AWS Secrets Manager, Azure Key Vault, etc.) |
|
|
13
|
-
|
|
14
|
-
**Example `.env`:**
|
|
15
|
-
```bash
|
|
16
|
-
APP_ENV_APPLICATION_SECRET=your_strong_random_secret_here
|
|
17
|
-
APP_ENV_JWT_SECRET=another_strong_random_secret_here
|
|
18
|
-
APP_ENV_POSTGRES_PASSWORD=database_password_here
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**Generate strong secrets:**
|
|
22
|
-
```bash
|
|
23
|
-
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## 2. Input Validation
|
|
27
|
-
|
|
28
|
-
**Always validate incoming data** with Zod schemas. Ignis automatically rejects invalid requests.
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { z } from '@hono/zod-openapi';
|
|
32
|
-
import { jsonContent, jsonResponse } from '@venizia/ignis';
|
|
33
|
-
|
|
34
|
-
const CreateUserRoute = {
|
|
35
|
-
method: 'post',
|
|
36
|
-
path: '/users',
|
|
37
|
-
request: {
|
|
38
|
-
body: jsonContent({
|
|
39
|
-
schema: z.object({
|
|
40
|
-
email: z.string().email(), // Valid email
|
|
41
|
-
age: z.number().int().min(18), // Adult only
|
|
42
|
-
role: z.enum(['user', 'admin']), // Whitelist
|
|
43
|
-
}),
|
|
44
|
-
}),
|
|
45
|
-
},
|
|
46
|
-
responses: jsonResponse({ /* ... */ }),
|
|
47
|
-
} as const;
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
**Validation happens automatically** - invalid requests never reach your handler.
|
|
51
|
-
|
|
52
|
-
## 3. Authentication & Authorization
|
|
53
|
-
|
|
54
|
-
Protect sensitive endpoints with `AuthenticateComponent`.
|
|
55
|
-
|
|
56
|
-
**Setup:**
|
|
57
|
-
```typescript
|
|
58
|
-
// application.ts
|
|
59
|
-
this.component(AuthenticateComponent);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Protect routes:**
|
|
63
|
-
```typescript
|
|
64
|
-
const SecureRoute = {
|
|
65
|
-
path: '/admin/users',
|
|
66
|
-
authStrategies: [Authentication.STRATEGY_JWT], // Requires JWT
|
|
67
|
-
// ...
|
|
68
|
-
};
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
> **Deep Dive:** See [Authentication Component](../../references/components/authentication.md) for full setup guide.
|
|
72
|
-
|
|
73
|
-
**Access user in protected routes:**
|
|
74
|
-
```typescript
|
|
75
|
-
import { Authentication, IJWTTokenPayload, ApplicationError, getError } from '@venizia/ignis';
|
|
76
|
-
|
|
77
|
-
const user = c.get(Authentication.CURRENT_USER) as IJWTTokenPayload;
|
|
78
|
-
if (!user.roles.includes('admin')) {
|
|
79
|
-
throw getError({ statusCode: 403, message: 'Forbidden' });
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## 4. Secure Dependencies
|
|
84
|
-
|
|
85
|
-
Regularly audit and update dependencies:
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
# Check for vulnerabilities
|
|
89
|
-
bun audit
|
|
90
|
-
|
|
91
|
-
# Update dependencies
|
|
92
|
-
bun update
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**Critical packages to keep updated:**
|
|
96
|
-
- `hono` - Web framework
|
|
97
|
-
- `jose` - JWT handling
|
|
98
|
-
- `drizzle-orm` - Database ORM
|
|
99
|
-
- `@venizia/ignis` - Framework core
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Components
|
|
2
|
-
|
|
3
|
-
Components are reusable, pluggable modules that encapsulate a group of related features. A component acts as a powerful container for various resources—including providers, services, controllers, repositories, and even entire mini-applications—making it easy to share and integrate complex functionality across projects.
|
|
4
|
-
|
|
5
|
-
> **Deep Dive:** See [Components Reference](../../references/base/components.md) for technical details.
|
|
6
|
-
|
|
7
|
-
## What is a Component?
|
|
8
|
-
|
|
9
|
-
A component is a class that extends `BaseComponent` and is responsible for:
|
|
10
|
-
|
|
11
|
-
- **Binding Dependencies**: Registering services, controllers, repositories, providers, or other resources with the application's dependency injection container.
|
|
12
|
-
- **Configuring Features**: Setting up middlewares, initializing services, or performing any other setup required for the feature to work.
|
|
13
|
-
|
|
14
|
-
A single component can bundle everything needed for a specific domain—for example, an "AuthComponent" might include multiple services for token management, repositories for user data, and controllers for login/signup endpoints, essentially functioning as a plug-and-play mini-application.
|
|
15
|
-
|
|
16
|
-
`Ignis` comes with several built-in components, which you can explore in the [**Components Reference**](../../references/components/) section:
|
|
17
|
-
|
|
18
|
-
- **`AuthenticateComponent`**: Sets up JWT-based authentication.
|
|
19
|
-
- **`SwaggerComponent`**: Generates interactive OpenAPI documentation.
|
|
20
|
-
- **`HealthCheckComponent`**: Adds a health check endpoint.
|
|
21
|
-
- **`RequestTrackerComponent`**: Adds request logging and tracing.
|
|
22
|
-
- **`SocketIOComponent`**: Integrates Socket.IO for real-time communication.
|
|
23
|
-
|
|
24
|
-
## Creating a Component
|
|
25
|
-
|
|
26
|
-
To create a new component, extend the `BaseComponent` class. The constructor is the ideal place to define any **default bindings** that the component provides.
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { BaseApplication, BaseComponent, inject, CoreBindings, ValueOrPromise, Binding, BindingScopes } from '@venizia/ignis';
|
|
30
|
-
|
|
31
|
-
// An example service that the component will provide
|
|
32
|
-
class MyFeatureService {
|
|
33
|
-
// ... business logic
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// A controller that depends on the service
|
|
37
|
-
@controller({ path: '/my-feature' })
|
|
38
|
-
class MyFeatureController {
|
|
39
|
-
constructor(
|
|
40
|
-
@inject({ key: 'services.MyFeatureService' })
|
|
41
|
-
private myFeatureService: MyFeatureService
|
|
42
|
-
) { /* ... */ }
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class MyFeatureComponent extends BaseComponent {
|
|
46
|
-
constructor(
|
|
47
|
-
@inject({ key: CoreBindings.APPLICATION_INSTANCE })
|
|
48
|
-
private application: BaseApplication,
|
|
49
|
-
) {
|
|
50
|
-
super({
|
|
51
|
-
scope: MyFeatureComponent.name,
|
|
52
|
-
// Enable default bindings for this component
|
|
53
|
-
initDefault: { enable: true, container: application },
|
|
54
|
-
// Define the default bindings this component provides
|
|
55
|
-
bindings: {
|
|
56
|
-
'services.MyFeatureService': Binding.bind({ key: 'services.MyFeatureService' })
|
|
57
|
-
.toClass(MyFeatureService)
|
|
58
|
-
.setScope(BindingScopes.SINGLETON), // Make it a singleton
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
override binding(): ValueOrPromise<void> {
|
|
64
|
-
// This is where you configure logic that USES the bindings.
|
|
65
|
-
// Here, we register a controller that depends on the service
|
|
66
|
-
// we just bound in the constructor.
|
|
67
|
-
this.application.controller(MyFeatureController);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Component Lifecycle
|
|
73
|
-
|
|
74
|
-
Components have a simple, two-stage lifecycle managed by the application.
|
|
75
|
-
|
|
76
|
-
| Stage | Method | Description |
|
|
77
|
-
| :--- | :--- | :--- |
|
|
78
|
-
| **1. Instantiation** | `constructor()` | The component is created by the DI container. This is where you call `super()` and define the component's `bindings`. If `initDefault` is enabled, these bindings are registered with the application container immediately. |
|
|
79
|
-
| **2. Configuration**| `binding()` | Called by the application during the `registerComponents` startup phase. This is where you should set up resources (like controllers) that *depend* on the bindings you defined in the constructor. |
|
|
80
|
-
|
|
81
|
-
## Registering a Component
|
|
82
|
-
|
|
83
|
-
To activate a component, you must register it with the application instance, usually in the `preConfigure` method of your `Application` class.
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// in src/application.ts
|
|
87
|
-
import { MyFeatureComponent } from './components/my-feature.component';
|
|
88
|
-
|
|
89
|
-
// ... inside your Application class
|
|
90
|
-
|
|
91
|
-
preConfigure(): ValueOrPromise<void> {
|
|
92
|
-
// ...
|
|
93
|
-
this.component(MyFeatureComponent);
|
|
94
|
-
// ...
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
When the application starts, it will find the `MyFeatureComponent` binding, instantiate it, and then call its `binding()` method at the appropriate time. This modular approach keeps your main application class clean and makes it easy to toggle features on and off.
|