@mbc-cqrs-serverless/tenant 1.0.16 → 1.0.18
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 +199 -125
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# @mbc-cqrs-serverless/tenant
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@mbc-cqrs-serverless/tenant)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Multi-tenancy support for the MBC CQRS Serverless framework. Manage tenants, tenant groups, and role-based setting group assignments for enterprise SaaS applications.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
8
11
|
|
|
9
12
|
- **Tenant Management**: Create, update, and manage tenant entities
|
|
10
|
-
- **Tenant Groups**: Organize
|
|
13
|
+
- **Tenant Groups**: Organize related entities within tenants
|
|
14
|
+
- **Role-Based Settings**: Assign setting groups to user roles within tenants
|
|
15
|
+
- **Common Tenant**: Shared configuration across all tenants
|
|
11
16
|
- **Tenant Isolation**: Automatic data isolation between tenants
|
|
12
|
-
- **Tenant Settings**: Tenant-specific configuration management
|
|
13
17
|
|
|
14
18
|
## Installation
|
|
15
19
|
|
|
@@ -17,201 +21,271 @@ The Tenant package provides multi-tenancy support for CQRS applications. It mana
|
|
|
17
21
|
npm install @mbc-cqrs-serverless/tenant
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
### Basic Setup
|
|
24
|
+
## Quick Start
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
### 1. Register the Module
|
|
25
27
|
|
|
26
28
|
```typescript
|
|
27
|
-
import { TenantModule } from '@mbc-cqrs-serverless/tenant';
|
|
28
29
|
import { Module } from '@nestjs/common';
|
|
30
|
+
import { TenantModule } from '@mbc-cqrs-serverless/tenant';
|
|
31
|
+
import { TenantDataSyncHandler } from './handlers/tenant-data-sync.handler';
|
|
29
32
|
|
|
30
33
|
@Module({
|
|
31
34
|
imports: [
|
|
32
35
|
TenantModule.register({
|
|
33
|
-
|
|
36
|
+
enableController: true, // Optional: enable REST endpoints
|
|
37
|
+
dataSyncHandlers: [TenantDataSyncHandler], // Optional: custom sync handlers
|
|
34
38
|
}),
|
|
35
39
|
],
|
|
36
40
|
})
|
|
37
41
|
export class AppModule {}
|
|
38
42
|
```
|
|
39
43
|
|
|
40
|
-
### Tenant
|
|
41
|
-
|
|
42
|
-
#### Create Tenant
|
|
44
|
+
### 2. Use the Tenant Service
|
|
43
45
|
|
|
44
46
|
```typescript
|
|
47
|
+
import { Injectable } from '@nestjs/common';
|
|
45
48
|
import { TenantService } from '@mbc-cqrs-serverless/tenant';
|
|
49
|
+
import { IInvoke } from '@mbc-cqrs-serverless/core';
|
|
46
50
|
|
|
47
51
|
@Injectable()
|
|
48
|
-
export class
|
|
52
|
+
export class MyService {
|
|
49
53
|
constructor(private readonly tenantService: TenantService) {}
|
|
50
54
|
|
|
51
|
-
async createTenant(data:
|
|
52
|
-
return this.tenantService.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
plan: 'enterprise',
|
|
58
|
-
maxUsers: 100,
|
|
55
|
+
async createTenant(data: any, opts: { invokeContext: IInvoke }) {
|
|
56
|
+
return this.tenantService.createTenant(
|
|
57
|
+
{
|
|
58
|
+
code: 'ACME',
|
|
59
|
+
name: 'Acme Corporation',
|
|
60
|
+
attributes: { plan: 'enterprise', maxUsers: 100 },
|
|
59
61
|
},
|
|
60
|
-
|
|
62
|
+
opts,
|
|
63
|
+
);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
```
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
## API Reference
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
async getTenant(tenantCode: string) {
|
|
69
|
-
return this.tenantService.findByCode(tenantCode);
|
|
70
|
-
}
|
|
70
|
+
### TenantService
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
| Method | Description |
|
|
73
|
+
|--------|-------------|
|
|
74
|
+
| `createTenant(dto, context)` | Create a new tenant |
|
|
75
|
+
| `createCommonTenant(dto, context)` | Create the shared common tenant |
|
|
76
|
+
| `updateTenant(key, dto, context)` | Update tenant properties |
|
|
77
|
+
| `deleteTenant(key, context)` | Soft delete a tenant |
|
|
78
|
+
| `getTenant(key)` | Get tenant by pk/sk |
|
|
79
|
+
| `createTenantGroup(tenantGroupCode, dto, context)` | Create a tenant within a tenant group |
|
|
80
|
+
| `addTenantGroup(dto, context)` | Add a group to tenant role settings |
|
|
81
|
+
| `customizeSettingGroups(dto, context)` | Customize setting group order for a role |
|
|
76
82
|
|
|
77
|
-
|
|
83
|
+
### TenantCreateDto
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
| Property | Type | Required | Description |
|
|
86
|
+
|----------|------|----------|-------------|
|
|
87
|
+
| `code` | string | Yes | Unique tenant identifier |
|
|
88
|
+
| `name` | string | Yes | Display name |
|
|
89
|
+
| `attributes` | object | No | Custom tenant properties |
|
|
90
|
+
|
|
91
|
+
### TenantGroupAddDto
|
|
92
|
+
|
|
93
|
+
| Property | Type | Required | Description |
|
|
94
|
+
|----------|------|----------|-------------|
|
|
95
|
+
| `tenantCode` | string | Yes | Target tenant |
|
|
96
|
+
| `role` | string | Yes | User role to configure |
|
|
97
|
+
| `groupId` | string | Yes | Group to add to role settings |
|
|
87
98
|
|
|
88
|
-
|
|
99
|
+
## Usage Examples
|
|
100
|
+
|
|
101
|
+
### Create Common Tenant
|
|
102
|
+
|
|
103
|
+
Create a shared tenant for common settings:
|
|
89
104
|
|
|
90
105
|
```typescript
|
|
91
|
-
async
|
|
92
|
-
return this.tenantService.
|
|
106
|
+
async createCommonTenant(opts: { invokeContext: IInvoke }) {
|
|
107
|
+
return this.tenantService.createCommonTenant(
|
|
108
|
+
{
|
|
109
|
+
name: 'Common Settings',
|
|
110
|
+
attributes: { description: 'Shared across all tenants' },
|
|
111
|
+
},
|
|
112
|
+
opts,
|
|
113
|
+
);
|
|
93
114
|
}
|
|
94
115
|
```
|
|
95
116
|
|
|
96
|
-
### Tenant
|
|
97
|
-
|
|
98
|
-
Organize tenants into groups for easier management:
|
|
99
|
-
|
|
100
|
-
#### Create Tenant Group
|
|
117
|
+
### Create Tenant
|
|
101
118
|
|
|
102
119
|
```typescript
|
|
103
|
-
async
|
|
104
|
-
return this.tenantService.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
120
|
+
async createTenant(dto: CreateTenantDto, opts: { invokeContext: IInvoke }) {
|
|
121
|
+
return this.tenantService.createTenant(
|
|
122
|
+
{
|
|
123
|
+
code: dto.code,
|
|
124
|
+
name: dto.name,
|
|
125
|
+
attributes: {
|
|
126
|
+
plan: dto.plan,
|
|
127
|
+
maxUsers: dto.maxUsers,
|
|
128
|
+
features: dto.features,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
opts,
|
|
132
|
+
);
|
|
109
133
|
}
|
|
110
134
|
```
|
|
111
135
|
|
|
112
|
-
|
|
136
|
+
### Update Tenant
|
|
113
137
|
|
|
114
138
|
```typescript
|
|
115
|
-
async
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
139
|
+
async updateTenant(
|
|
140
|
+
tenantCode: string,
|
|
141
|
+
dto: UpdateTenantDto,
|
|
142
|
+
opts: { invokeContext: IInvoke },
|
|
143
|
+
) {
|
|
144
|
+
const pk = `TENANT#${tenantCode}`;
|
|
145
|
+
const sk = 'TENANT';
|
|
146
|
+
|
|
147
|
+
return this.tenantService.updateTenant(
|
|
148
|
+
{ pk, sk },
|
|
149
|
+
{ name: dto.name, attributes: dto.attributes },
|
|
150
|
+
opts,
|
|
151
|
+
);
|
|
120
152
|
}
|
|
121
153
|
```
|
|
122
154
|
|
|
123
|
-
|
|
155
|
+
### Delete Tenant (Soft Delete)
|
|
124
156
|
|
|
125
157
|
```typescript
|
|
126
|
-
async
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
158
|
+
async deleteTenant(tenantCode: string, opts: { invokeContext: IInvoke }) {
|
|
159
|
+
const pk = `TENANT#${tenantCode}`;
|
|
160
|
+
const sk = 'TENANT';
|
|
161
|
+
|
|
162
|
+
return this.tenantService.deleteTenant({ pk, sk }, opts);
|
|
131
163
|
}
|
|
132
164
|
```
|
|
133
165
|
|
|
134
|
-
###
|
|
166
|
+
### Role-Based Setting Groups
|
|
135
167
|
|
|
136
|
-
|
|
168
|
+
Configure which setting groups apply to different user roles:
|
|
137
169
|
|
|
138
170
|
```typescript
|
|
139
|
-
|
|
171
|
+
// Add a group to admin role settings
|
|
172
|
+
async addGroupToAdminRole(tenantCode: string, groupId: string, opts: { invokeContext: IInvoke }) {
|
|
173
|
+
return this.tenantService.addTenantGroup(
|
|
174
|
+
{
|
|
175
|
+
tenantCode,
|
|
176
|
+
role: 'admin',
|
|
177
|
+
groupId,
|
|
178
|
+
},
|
|
179
|
+
opts,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
140
182
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return this.orderRepository.create({
|
|
183
|
+
// Customize the order of setting groups for a role
|
|
184
|
+
async customizeRoleSettings(
|
|
185
|
+
tenantCode: string,
|
|
186
|
+
role: string,
|
|
187
|
+
settingGroups: string[],
|
|
188
|
+
opts: { invokeContext: IInvoke },
|
|
189
|
+
) {
|
|
190
|
+
return this.tenantService.customizeSettingGroups(
|
|
191
|
+
{
|
|
151
192
|
tenantCode,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
193
|
+
role,
|
|
194
|
+
settingGroups, // Ordered list of group IDs
|
|
195
|
+
},
|
|
196
|
+
opts,
|
|
197
|
+
);
|
|
155
198
|
}
|
|
156
199
|
```
|
|
157
200
|
|
|
158
|
-
###
|
|
201
|
+
### Create Tenant Group
|
|
159
202
|
|
|
160
|
-
Create a
|
|
203
|
+
Create a tenant entity within a specific tenant group:
|
|
161
204
|
|
|
162
205
|
```typescript
|
|
163
|
-
async
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
206
|
+
async createDepartment(
|
|
207
|
+
tenantGroupCode: string,
|
|
208
|
+
dto: CreateDepartmentDto,
|
|
209
|
+
opts: { invokeContext: IInvoke },
|
|
210
|
+
) {
|
|
211
|
+
return this.tenantService.createTenantGroup(
|
|
212
|
+
tenantGroupCode,
|
|
213
|
+
{
|
|
214
|
+
code: dto.code,
|
|
215
|
+
name: dto.name,
|
|
216
|
+
attributes: dto.attributes,
|
|
217
|
+
},
|
|
218
|
+
opts,
|
|
219
|
+
);
|
|
168
220
|
}
|
|
169
221
|
```
|
|
170
222
|
|
|
171
|
-
##
|
|
223
|
+
## Data Model
|
|
172
224
|
|
|
173
|
-
###
|
|
225
|
+
### Tenant Key Pattern
|
|
174
226
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
| `update(code, dto)` | Update tenant |
|
|
179
|
-
| `delete(code)` | Delete tenant |
|
|
180
|
-
| `findByCode(code)` | Find tenant by code |
|
|
181
|
-
| `findAll()` | Get all tenants |
|
|
182
|
-
| `createGroup(dto)` | Create tenant group |
|
|
183
|
-
| `updateGroup(code, dto)` | Update tenant group |
|
|
184
|
-
| `addToGroup(dto)` | Add tenant to group |
|
|
185
|
-
| `removeFromGroup(dto)` | Remove tenant from group |
|
|
186
|
-
|
|
187
|
-
### TenantContext
|
|
227
|
+
```
|
|
228
|
+
pk: TENANT#[tenantCode]
|
|
229
|
+
sk: TENANT
|
|
188
230
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
| `isCommonTenant()` | Check if common tenant |
|
|
231
|
+
Example:
|
|
232
|
+
pk: TENANT#ACME
|
|
233
|
+
sk: TENANT
|
|
234
|
+
```
|
|
194
235
|
|
|
195
|
-
|
|
236
|
+
### Tenant Group Key Pattern
|
|
196
237
|
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
238
|
+
```
|
|
239
|
+
pk: TENANT#[tenantCode]
|
|
240
|
+
sk: [groupCode]
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
pk: TENANT#ACME
|
|
244
|
+
sk: SALES_DEPT
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Setting Groups Structure
|
|
248
|
+
|
|
249
|
+
Role-based setting groups are stored in tenant attributes:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"pk": "TENANT#ACME",
|
|
254
|
+
"sk": "TENANT",
|
|
255
|
+
"attributes": {
|
|
256
|
+
"setting": [
|
|
257
|
+
{
|
|
258
|
+
"tenantRole": "admin",
|
|
259
|
+
"groups": ["GROUP#ADMIN", "GROUP#POWER_USER"],
|
|
260
|
+
"setting_groups": ["GROUP#ADMIN", "GROUP#POWER_USER"],
|
|
261
|
+
"setting_groups_mode": "auto"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"tenantRole": "user",
|
|
265
|
+
"groups": ["GROUP#USER"],
|
|
266
|
+
"setting_groups": ["GROUP#USER"],
|
|
267
|
+
"setting_groups_mode": "customized"
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|
|
207
271
|
}
|
|
208
272
|
```
|
|
209
273
|
|
|
274
|
+
## Related Packages
|
|
275
|
+
|
|
276
|
+
| Package | Description |
|
|
277
|
+
|---------|-------------|
|
|
278
|
+
| [@mbc-cqrs-serverless/core](https://www.npmjs.com/package/@mbc-cqrs-serverless/core) | Core CQRS framework |
|
|
279
|
+
| [@mbc-cqrs-serverless/master](https://www.npmjs.com/package/@mbc-cqrs-serverless/master) | Hierarchical settings with tenant support |
|
|
280
|
+
|
|
210
281
|
## Documentation
|
|
211
282
|
|
|
212
|
-
|
|
283
|
+
Full documentation available at [https://mbc-cqrs-serverless.mbc-net.com/](https://mbc-cqrs-serverless.mbc-net.com/)
|
|
284
|
+
|
|
285
|
+
- [Tenant Service Guide](https://mbc-cqrs-serverless.mbc-net.com/docs/tenant-service)
|
|
213
286
|
|
|
214
287
|
## License
|
|
215
288
|
|
|
216
|
-
Copyright
|
|
217
|
-
|
|
289
|
+
Copyright © 2024-2025, Murakami Business Consulting, Inc. [https://www.mbc-net.com/](https://www.mbc-net.com/)
|
|
290
|
+
|
|
291
|
+
This project is under the [MIT License](../../LICENSE.txt).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbc-cqrs-serverless/tenant",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "Multiple tenant management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mbc",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@mbc-cqrs-serverless/core": "^0.1.48-beta.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "f94a747c55ac4b09a643a5201dc89e4edda19c76"
|
|
48
48
|
}
|