@mbc-cqrs-serverless/sequence 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +200 -122
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,16 +1,19 @@
1
1
  ![MBC CQRS serverless framework](https://mbc-cqrs-serverless.mbc-net.com/img/mbc-cqrs-serverless.png)
2
2
 
3
- # MBC CQRS serverless framework Sequence package
3
+ # @mbc-cqrs-serverless/sequence
4
4
 
5
- ## Description
5
+ [![npm version](https://badge.fury.io/js/@mbc-cqrs-serverless%2Fsequence.svg)](https://www.npmjs.com/package/@mbc-cqrs-serverless/sequence)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
- The Sequence package provides robust sequence number generation functionality for the MBC CQRS Serverless framework. It supports:
8
+ Robust sequence number generation for the MBC CQRS Serverless framework. Generate unique, formatted sequence numbers with automatic rotation support for invoices, orders, tickets, and more.
8
9
 
9
- - Flexible sequence number generation
10
- - Rotation by fiscal year, year, month, or day
11
- - Customizable number formats
12
- - Multi-tenant sequence management
13
- - Atomic operations for concurrent access
10
+ ## Features
11
+
12
+ - **Atomic Counter**: DynamoDB-based atomic operations ensure no duplicates
13
+ - **Flexible Rotation**: Reset sequences by fiscal year, year, month, or day
14
+ - **Custom Formatting**: Configure prefixes, padding, and format patterns
15
+ - **Multi-tenant**: Isolated sequences per tenant
16
+ - **Hierarchical Codes**: Support up to 5 levels of code hierarchy
14
17
 
15
18
  ## Installation
16
19
 
@@ -18,173 +21,248 @@ The Sequence package provides robust sequence number generation functionality fo
18
21
  npm install @mbc-cqrs-serverless/sequence
19
22
  ```
20
23
 
21
- ## Usage
24
+ ## Quick Start
22
25
 
23
- ### Basic Setup
26
+ ### 1. Register the Module
24
27
 
25
- 1. Import and configure the sequence module:
26
28
  ```typescript
27
- import { SequenceModule } from '@mbc-cqrs-serverless/sequence';
28
29
  import { Module } from '@nestjs/common';
30
+ import { SequencesModule } from '@mbc-cqrs-serverless/sequence';
29
31
 
30
32
  @Module({
31
33
  imports: [
32
- SequenceModule.forRoot({
33
- tableName: 'sequences',
34
- region: 'ap-northeast-1',
34
+ SequencesModule.register({
35
+ enableController: true, // Optional: enable REST endpoints
35
36
  }),
36
37
  ],
37
38
  })
38
39
  export class AppModule {}
39
40
  ```
40
41
 
41
- ### Creating Sequences
42
-
43
- 1. Define a sequence configuration:
44
- ```typescript
45
- import {
46
- SequenceConfig,
47
- RotateByEnum
48
- } from '@mbc-cqrs-serverless/sequence';
49
-
50
- const invoiceSequence: SequenceConfig = {
51
- name: 'INVOICE',
52
- prefix: 'INV',
53
- padding: 6,
54
- rotateBy: RotateByEnum.FISCAL_YEAR,
55
- startNumber: 1,
56
- };
57
- ```
42
+ ### 2. Generate Sequence Numbers
58
43
 
59
- 2. Use the sequence service:
60
44
  ```typescript
61
- import { SequencesService } from '@mbc-cqrs-serverless/sequence';
45
+ import { Injectable } from '@nestjs/common';
46
+ import { SequencesService, RotateByEnum } from '@mbc-cqrs-serverless/sequence';
47
+ import { getUserContext, IInvoke } from '@mbc-cqrs-serverless/core';
62
48
 
63
49
  @Injectable()
64
50
  export class InvoiceService {
65
- constructor(
66
- private readonly sequencesService: SequencesService
67
- ) {}
51
+ constructor(private readonly sequencesService: SequencesService) {}
52
+
53
+ async createInvoice(opts: { invokeContext: IInvoke }) {
54
+ const { tenantCode } = getUserContext(opts.invokeContext);
55
+
56
+ const seq = await this.sequencesService.generateSequenceItem(
57
+ {
58
+ tenantCode,
59
+ typeCode: 'INVOICE',
60
+ rotateBy: RotateByEnum.FISCAL_YEARLY,
61
+ },
62
+ opts,
63
+ );
64
+
65
+ console.log(seq.no); // 1
66
+ console.log(seq.formattedNo); // "INV-0001" (based on master data format)
67
+ console.log(seq.issuedAt); // Date object
68
68
 
69
- async generateInvoiceNumber(): Promise<string> {
70
- const sequence = await this.sequencesService.next('INVOICE');
71
- return sequence.formattedNo; // Returns: "INV000001"
69
+ return seq;
72
70
  }
73
71
  }
74
72
  ```
75
73
 
76
- ### Rotation Strategies
74
+ ## API Reference
75
+
76
+ ### SequencesService
77
+
78
+ | Method | Description |
79
+ |--------|-------------|
80
+ | `generateSequenceItem(dto, options)` | Generate sequence using master data configuration |
81
+ | `generateSequenceItemWithProvideSetting(dto, options)` | Generate sequence with inline settings |
82
+
83
+ ### GenerateFormattedSequenceDto
84
+
85
+ | Property | Type | Required | Description |
86
+ |----------|------|----------|-------------|
87
+ | `tenantCode` | string | Yes | Tenant identifier |
88
+ | `typeCode` | string | Yes | Sequence type (e.g., 'INVOICE', 'ORDER') |
89
+ | `rotateBy` | RotateByEnum | No | Rotation strategy |
90
+ | `date` | Date | No | Date for sequence (default: now) |
91
+ | `prefix` | string | No | Prefix to add before formatted number |
92
+ | `postfix` | string | No | Postfix to add after formatted number |
93
+ | `params` | object | No | Additional parameters (code1-code5) |
94
+
95
+ ### RotateByEnum
96
+
97
+ | Value | Description | Example Reset |
98
+ |-------|-------------|---------------|
99
+ | `FISCAL_YEARLY` | Reset on fiscal year start (April 1st in Japan) | Apr 1, 2024 |
100
+ | `YEARLY` | Reset on calendar year | Jan 1, 2024 |
101
+ | `MONTHLY` | Reset each month | First of each month |
102
+ | `DAILY` | Reset each day | Every day |
103
+ | `NONE` | Never reset, continuous increment | Never |
104
+
105
+ ### SequenceEntity (Return Type)
77
106
 
78
- 1. Yearly rotation:
79
107
  ```typescript
80
- const yearlySequence: SequenceConfig = {
81
- name: 'YEARLY_DOC',
82
- prefix: 'DOC',
83
- rotateBy: RotateByEnum.YEAR,
84
- format: '{{prefix}}-{{year}}-{{no}}', // DOC-2024-0001
85
- };
108
+ {
109
+ id: string; // Unique identifier
110
+ no: number; // Raw sequence number
111
+ formattedNo: string; // Formatted sequence string
112
+ issuedAt: Date; // Timestamp of generation
113
+ }
86
114
  ```
87
115
 
88
- 2. Monthly rotation:
116
+ ## Usage Examples
117
+
118
+ ### Fiscal Year Rotation (Japan)
119
+
120
+ Sequences reset on April 1st:
121
+
89
122
  ```typescript
90
- const monthlySequence: SequenceConfig = {
91
- name: 'MONTHLY_ORDER',
92
- prefix: 'ORD',
93
- rotateBy: RotateByEnum.MONTH,
94
- format: '{{prefix}}{{year}}{{month}}{{no}}', // ORD202401001
95
- };
123
+ const seq = await this.sequencesService.generateSequenceItem(
124
+ {
125
+ tenantCode: 'MBC',
126
+ typeCode: 'INVOICE',
127
+ rotateBy: RotateByEnum.FISCAL_YEARLY,
128
+ },
129
+ opts,
130
+ );
131
+ // FY2024: INV-0001, INV-0002, ...
132
+ // FY2025 (after Apr 1): INV-0001, INV-0002, ...
96
133
  ```
97
134
 
98
- 3. Daily rotation:
135
+ ### Monthly Rotation
136
+
137
+ Sequences reset on the first of each month:
138
+
99
139
  ```typescript
100
- const dailySequence: SequenceConfig = {
101
- name: 'DAILY_TICKET',
102
- prefix: 'TKT',
103
- rotateBy: RotateByEnum.DAY,
104
- format: '{{prefix}}-{{date}}-{{no}}', // TKT-20240101-001
105
- };
140
+ const seq = await this.sequencesService.generateSequenceItem(
141
+ {
142
+ tenantCode: 'MBC',
143
+ typeCode: 'ORDER',
144
+ rotateBy: RotateByEnum.MONTHLY,
145
+ },
146
+ opts,
147
+ );
148
+ // January: ORD-202401-0001, ORD-202401-0002
149
+ // February: ORD-202402-0001, ORD-202402-0002
106
150
  ```
107
151
 
108
- ### Custom Formatting
152
+ ### Daily Rotation
153
+
154
+ Sequences reset every day:
109
155
 
110
- 1. Define custom format patterns:
111
156
  ```typescript
112
- const customSequence: SequenceConfig = {
113
- name: 'CUSTOM_DOC',
114
- prefix: 'DOC',
115
- format: '{{prefix}}/{{year}}/{{tenantCode}}/{{no}}',
116
- padding: 4,
117
- };
157
+ const seq = await this.sequencesService.generateSequenceItem(
158
+ {
159
+ tenantCode: 'MBC',
160
+ typeCode: 'TICKET',
161
+ rotateBy: RotateByEnum.DAILY,
162
+ },
163
+ opts,
164
+ );
165
+ // Day 1: TKT-20240115-001, TKT-20240115-002
166
+ // Day 2: TKT-20240116-001, TKT-20240116-002
118
167
  ```
119
168
 
120
- 2. Use with tenant context:
169
+ ### Hierarchical Sequences
170
+
171
+ Use code1-code5 for hierarchical sequence numbers:
172
+
121
173
  ```typescript
122
- @Injectable()
123
- export class DocumentService {
124
- constructor(
125
- private readonly sequencesService: SequencesService
126
- ) {}
127
-
128
- @UseTenant()
129
- async generateDocumentNumber(
130
- @TenantContext() tenantCode: string
131
- ): Promise<string> {
132
- const sequence = await this.sequencesService.next('CUSTOM_DOC', {
133
- tenantCode,
134
- });
135
- return sequence.formattedNo; // Returns: "DOC/2024/TENANT1/0001"
136
- }
137
- }
174
+ const seq = await this.sequencesService.generateSequenceItem(
175
+ {
176
+ tenantCode: 'MBC',
177
+ typeCode: 'PRODUCT',
178
+ params: {
179
+ code1: 'ELECTRONICS',
180
+ code2: 'PHONES',
181
+ },
182
+ rotateBy: RotateByEnum.YEARLY,
183
+ },
184
+ opts,
185
+ );
186
+ // Each category has its own sequence: ELECTRONICS-PHONES-0001
138
187
  ```
139
188
 
140
- ### Concurrent Access
189
+ ### Custom Settings (No Master Data)
141
190
 
142
- The package handles concurrent access automatically:
191
+ Provide format settings directly without master data lookup:
143
192
 
144
193
  ```typescript
145
- @Injectable()
146
- export class BulkProcessor {
147
- constructor(
148
- private readonly sequencesService: SequencesService
149
- ) {}
150
-
151
- async processBatch(): Promise<string[]> {
152
- // Safe for concurrent access
153
- const numbers = await Promise.all(
154
- Array(10).fill(null).map(() =>
155
- this.sequencesService.next('BATCH_SEQ')
156
- )
157
- );
158
- return numbers.map(seq => seq.formattedNo);
159
- }
160
- }
194
+ const seq = await this.sequencesService.generateSequenceItemWithProvideSetting(
195
+ {
196
+ tenantCode: 'MBC',
197
+ typeCode: 'CUSTOM',
198
+ format: '%%year%%-%%month#:0>2%%-%%no#:0>4%%',
199
+ rotateBy: RotateByEnum.MONTHLY,
200
+ prefix: 'DOC-',
201
+ },
202
+ opts,
203
+ );
204
+ // Result: DOC-2024-01-0001
161
205
  ```
162
206
 
163
- ### Error Handling
207
+ ### Format Patterns
164
208
 
165
- ```typescript
166
- import { SequenceError } from '@mbc-cqrs-serverless/sequence';
209
+ Format strings use `%%key%%` syntax with optional padding:
167
210
 
168
- try {
169
- await sequencesService.next('INVALID_SEQ');
170
- } catch (error) {
171
- if (error instanceof SequenceError) {
172
- console.error('Sequence error:', error.message);
173
- }
211
+ | Pattern | Output | Description |
212
+ |---------|--------|-------------|
213
+ | `%%no%%` | `1` | Raw number |
214
+ | `%%no#:0>4%%` | `0001` | Zero-padded to 4 digits |
215
+ | `%%year%%` | `2024` | Current year |
216
+ | `%%month%%` | `1` | Current month (1-12) |
217
+ | `%%month#:0>2%%` | `01` | Zero-padded month |
218
+ | `%%day%%` | `15` | Current day |
219
+ | `%%fiscal_year%%` | `71` | Fiscal year number |
220
+ | `%%code1%%` | `DEPT` | Hierarchical code 1 |
221
+
222
+ ## Master Data Configuration
223
+
224
+ The `generateSequenceItem` method reads format configuration from master data:
225
+
226
+ ```json
227
+ {
228
+ "pk": "MASTER#MBC",
229
+ "sk": "MASTER_DATA#INVOICE",
230
+ "format": "%%year%%-%%no#:0>4%%",
231
+ "startMonth": 4,
232
+ "registerDate": "2024-04-01"
174
233
  }
175
234
  ```
176
235
 
236
+ ## Concurrent Access Safety
237
+
238
+ All sequence operations use DynamoDB atomic counters, ensuring thread-safe generation:
239
+
240
+ ```typescript
241
+ // Safe for concurrent requests
242
+ const results = await Promise.all([
243
+ sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
244
+ sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
245
+ sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
246
+ ]);
247
+ // Results: [{ no: 1 }, { no: 2 }, { no: 3 }] - guaranteed unique
248
+ ```
249
+
250
+ ## Related Packages
251
+
252
+ | Package | Description |
253
+ |---------|-------------|
254
+ | [@mbc-cqrs-serverless/core](https://www.npmjs.com/package/@mbc-cqrs-serverless/core) | Core CQRS framework |
255
+ | [@mbc-cqrs-serverless/master](https://www.npmjs.com/package/@mbc-cqrs-serverless/master) | Master data for sequence formats |
256
+
177
257
  ## Documentation
178
258
 
259
+ Full documentation available at [https://mbc-cqrs-serverless.mbc-net.com/](https://mbc-cqrs-serverless.mbc-net.com/)
179
260
 
180
- Visit https://mbc-cqrs-serverless.mbc-net.com/ to view the full documentation, including:
181
- - Sequence configuration options
182
- - Rotation strategies
183
- - Format customization
184
- - Usage examples
185
- - API reference
261
+ - [Sequence Service Guide](https://mbc-cqrs-serverless.mbc-net.com/docs/sequence-service)
262
+ - [Build a Todo App Tutorial](https://mbc-cqrs-serverless.mbc-net.com/docs/build-todo-app)
186
263
 
187
264
  ## License
188
265
 
189
- Copyright &copy; 2024, Murakami Business Consulting, Inc. https://www.mbc-net.com/
190
- This project and sub projects are under the MIT License.
266
+ Copyright © 2024-2025, Murakami Business Consulting, Inc. [https://www.mbc-net.com/](https://www.mbc-net.com/)
267
+
268
+ 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/sequence",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Generate increment sequence with time-rotation",
5
5
  "keywords": [
6
6
  "mbc",
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
- "@mbc-cqrs-serverless/core": "1.0.16"
44
+ "@mbc-cqrs-serverless/core": "1.0.17"
45
45
  },
46
- "gitHead": "4ab967474160873735b8cb816272a7012b8940d5"
46
+ "gitHead": "1870821803cfb045c9c4d6bc18d513fa2558de1c"
47
47
  }