@webex/contact-center 3.12.0-next.9 → 3.12.0-task-refactor.1
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/AGENTS.md +438 -0
- package/ai-docs/README.md +131 -0
- package/ai-docs/RULES.md +455 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +65 -123
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +13 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +26 -13
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +7 -6
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +0 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +2 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +16 -14
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +0 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +79 -55
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +17 -92
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +5 -25
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -2
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +644 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +556 -532
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +132 -28
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +7 -6
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +0 -51
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +366 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +139 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +256 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +369 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +157 -18
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1031 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +4 -33
- package/dist/types/constants.d.ts +13 -2
- package/dist/types/index.d.ts +11 -5
- package/dist/types/metrics/constants.d.ts +5 -3
- package/dist/types/services/ApiAiAssistant.d.ts +1 -1
- package/dist/types/services/config/types.d.ts +97 -25
- package/dist/types/services/core/Err.d.ts +0 -2
- package/dist/types/services/core/Utils.d.ts +25 -23
- package/dist/types/services/core/aqm-reqs.d.ts +0 -49
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
- package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +146 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskUtils.d.ts +39 -8
- package/dist/types/services/task/constants.d.ts +5 -4
- package/dist/types/services/task/dialer.d.ts +0 -15
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
- package/dist/types/services/task/state-machine/actions.d.ts +8 -0
- package/dist/types/services/task/state-machine/constants.d.ts +91 -0
- package/dist/types/services/task/state-machine/guards.d.ts +78 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +256 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +539 -88
- package/dist/types/services/task/voice/Voice.d.ts +183 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +68 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +70 -0
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +14 -11
- package/src/cc.ts +91 -177
- package/src/constants.ts +13 -2
- package/src/index.ts +14 -5
- package/src/metrics/ai-docs/AGENTS.md +348 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
- package/src/metrics/behavioral-events.ts +28 -14
- package/src/metrics/constants.ts +7 -8
- package/src/services/ApiAiAssistant.ts +2 -4
- package/src/services/agent/ai-docs/AGENTS.md +238 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
- package/src/services/ai-docs/AGENTS.md +384 -0
- package/src/services/config/Util.ts +2 -3
- package/src/services/config/ai-docs/AGENTS.md +253 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
- package/src/services/config/types.ts +108 -20
- package/src/services/constants.ts +0 -1
- package/src/services/core/Err.ts +0 -1
- package/src/services/core/Utils.ts +90 -67
- package/src/services/core/ai-docs/AGENTS.md +379 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
- package/src/services/core/aqm-reqs.ts +22 -100
- package/src/services/core/websocket/WebSocketManager.ts +4 -23
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -2
- package/src/services/task/Task.ts +785 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +567 -633
- package/src/services/task/TaskUtils.ts +175 -31
- package/src/services/task/ai-docs/AGENTS.md +448 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
- package/src/services/task/constants.ts +5 -4
- package/src/services/task/dialer.ts +1 -56
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
- package/src/services/task/state-machine/actions.ts +409 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
- package/src/services/task/state-machine/constants.ts +150 -0
- package/src/services/task/state-machine/guards.ts +295 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +228 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +529 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +641 -95
- package/src/services/task/voice/Voice.ts +1255 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +88 -5
- package/src/utils/AGENTS.md +276 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +59 -142
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
- package/test/unit/spec/services/config/index.ts +26 -55
- package/test/unit/spec/services/core/Utils.ts +103 -52
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
- package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +416 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +781 -1735
- package/test/unit/spec/services/task/TaskUtils.ts +125 -0
- package/test/unit/spec/services/task/dialer.ts +112 -198
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +587 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# New Method - Tests
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Create unit tests for the new method.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Test Location
|
|
8
|
+
|
|
9
|
+
Add tests to the existing test file that corresponds to the source file:
|
|
10
|
+
- For `cc.ts` methods: `test/unit/spec/cc.ts`
|
|
11
|
+
- For service methods: `test/unit/spec/services/[service]/index.ts`
|
|
12
|
+
- For non-service files: `test/unit/spec/[filename].ts`
|
|
13
|
+
|
|
14
|
+
> **Convention**: The test file path mirrors the source file path under `test/unit/spec/`. For example:
|
|
15
|
+
> - `src/cc.ts` → `test/unit/spec/cc.ts`
|
|
16
|
+
> - `src/logger-proxy.ts` → `test/unit/spec/logger-proxy.ts`
|
|
17
|
+
> - `src/metrics/MetricsManager.ts` → `test/unit/spec/metrics/MetricsManager.ts`
|
|
18
|
+
> - `src/services/agent/index.ts` → `test/unit/spec/services/agent/index.ts`
|
|
19
|
+
> - `src/services/task/Task.ts` → `test/unit/spec/services/task/Task.ts`
|
|
20
|
+
> - `src/services/WebCallingService.ts` → `test/unit/spec/services/WebCallingService.ts`
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Test Template
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
describe('cc.methodName', () => {
|
|
28
|
+
// Mock data
|
|
29
|
+
const mockParams = {
|
|
30
|
+
requiredField: 'test-value',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const mockSuccessResponse = {
|
|
34
|
+
data: {
|
|
35
|
+
field: 'value',
|
|
36
|
+
},
|
|
37
|
+
trackingId: 'track-123',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const mockError = new Error('Operation failed');
|
|
41
|
+
mockError.details = {
|
|
42
|
+
type: 'OperationFailed',
|
|
43
|
+
data: { reason: 'INVALID_INPUT' },
|
|
44
|
+
trackingId: 'track-456',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
// Reset mocks
|
|
49
|
+
jest.clearAllMocks();
|
|
50
|
+
|
|
51
|
+
// Setup default mock behavior
|
|
52
|
+
mockServicesInstance.someService.method.mockResolvedValue(mockSuccessResponse);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('success scenarios', () => {
|
|
56
|
+
it('should complete operation successfully', async () => {
|
|
57
|
+
// Act
|
|
58
|
+
const result = await webex.cc.methodName(mockParams);
|
|
59
|
+
|
|
60
|
+
// Assert
|
|
61
|
+
expect(result).toEqual(mockSuccessResponse);
|
|
62
|
+
expect(mockServicesInstance.someService.method).toHaveBeenCalledWith({
|
|
63
|
+
data: {
|
|
64
|
+
requiredField: 'test-value',
|
|
65
|
+
agentId: 'mock-agent-id',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should track success metrics', async () => {
|
|
71
|
+
// Act
|
|
72
|
+
await webex.cc.methodName(mockParams);
|
|
73
|
+
|
|
74
|
+
// Assert
|
|
75
|
+
expect(mockMetricsManager.timeEvent).toHaveBeenCalledWith([
|
|
76
|
+
METRIC_EVENT_NAMES.OPERATION_SUCCESS,
|
|
77
|
+
METRIC_EVENT_NAMES.OPERATION_FAILED,
|
|
78
|
+
]);
|
|
79
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
80
|
+
METRIC_EVENT_NAMES.OPERATION_SUCCESS,
|
|
81
|
+
{
|
|
82
|
+
...mockCommonTrackingFields,
|
|
83
|
+
customField: 'test-value',
|
|
84
|
+
},
|
|
85
|
+
['behavioral', 'operational']
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should log operation start and completion', async () => {
|
|
90
|
+
// Act
|
|
91
|
+
await webex.cc.methodName(mockParams);
|
|
92
|
+
|
|
93
|
+
// Assert
|
|
94
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(
|
|
95
|
+
'Starting operation',
|
|
96
|
+
{
|
|
97
|
+
module: CC_FILE,
|
|
98
|
+
method: METHODS.METHOD_NAME,
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
102
|
+
'Operation completed successfully',
|
|
103
|
+
{
|
|
104
|
+
module: CC_FILE,
|
|
105
|
+
method: METHODS.METHOD_NAME,
|
|
106
|
+
trackingId: 'track-123',
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('error scenarios', () => {
|
|
113
|
+
it('should throw error on service failure', async () => {
|
|
114
|
+
// Arrange
|
|
115
|
+
mockServicesInstance.someService.method.mockRejectedValue(mockError);
|
|
116
|
+
|
|
117
|
+
// Act & Assert
|
|
118
|
+
await expect(webex.cc.methodName(mockParams)).rejects.toThrow();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should track failure metrics on error', async () => {
|
|
122
|
+
// Arrange
|
|
123
|
+
mockServicesInstance.someService.method.mockRejectedValue(mockError);
|
|
124
|
+
|
|
125
|
+
// Act
|
|
126
|
+
await expect(webex.cc.methodName(mockParams)).rejects.toThrow();
|
|
127
|
+
|
|
128
|
+
// Assert
|
|
129
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
130
|
+
METRIC_EVENT_NAMES.OPERATION_FAILED,
|
|
131
|
+
{
|
|
132
|
+
...mockCommonFailedTrackingFields,
|
|
133
|
+
customField: 'test-value',
|
|
134
|
+
},
|
|
135
|
+
['behavioral', 'operational']
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should call getErrorDetails on failure', async () => {
|
|
140
|
+
// Arrange
|
|
141
|
+
mockServicesInstance.someService.method.mockRejectedValue(mockError);
|
|
142
|
+
|
|
143
|
+
// Act
|
|
144
|
+
await expect(webex.cc.methodName(mockParams)).rejects.toThrow();
|
|
145
|
+
|
|
146
|
+
// Assert
|
|
147
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(
|
|
148
|
+
mockError,
|
|
149
|
+
METHODS.METHOD_NAME,
|
|
150
|
+
CC_FILE
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('input validation', () => {
|
|
156
|
+
it('should handle optional parameters', async () => {
|
|
157
|
+
// Arrange
|
|
158
|
+
const paramsWithOptional = {
|
|
159
|
+
...mockParams,
|
|
160
|
+
optionalField: 42,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Act
|
|
164
|
+
await webex.cc.methodName(paramsWithOptional);
|
|
165
|
+
|
|
166
|
+
// Assert
|
|
167
|
+
expect(mockServicesInstance.someService.method).toHaveBeenCalledWith({
|
|
168
|
+
data: {
|
|
169
|
+
requiredField: 'test-value',
|
|
170
|
+
optionalField: 42,
|
|
171
|
+
agentId: 'mock-agent-id',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Test Assertion Guidelines
|
|
182
|
+
|
|
183
|
+
> **Team standard: Use exact matches, not partial matchers.** Always use `expect(result).toEqual(expectedValue)` with the full expected object. Avoid `expect.objectContaining()` or `expect.arrayContaining()` unless there is a specific reason (e.g., dynamic fields like timestamps). Exact assertions catch unintended payload changes early.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Running Tests
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Run specific test file
|
|
191
|
+
yarn workspace @webex/contact-center test:unit -- <path_to_specific_file>
|
|
192
|
+
|
|
193
|
+
# Run with coverage
|
|
194
|
+
yarn workspace @webex/contact-center test:unit --coverage
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Next Step
|
|
200
|
+
|
|
201
|
+
Proceed to: [`04-validation.md`](04-validation.md)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# New Method - Validation Checklist
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Final quality check before completing method addition.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code Quality Checklist
|
|
8
|
+
|
|
9
|
+
### Method Implementation
|
|
10
|
+
- [ ] Method added with correct signature
|
|
11
|
+
- [ ] JSDoc with `@param`, `@returns`, `@throws`, `@example`
|
|
12
|
+
- [ ] `@public` tag for public API methods
|
|
13
|
+
- [ ] LoggerProxy.info at method start
|
|
14
|
+
- [ ] LoggerProxy.log on success
|
|
15
|
+
- [ ] LoggerProxy.error on failure (via getErrorDetails)
|
|
16
|
+
- [ ] MetricsManager.timeEvent at start
|
|
17
|
+
- [ ] MetricsManager.trackEvent on success
|
|
18
|
+
- [ ] MetricsManager.trackEvent on failure
|
|
19
|
+
- [ ] Error handling uses `getErrorDetails` pattern
|
|
20
|
+
- [ ] Failure cast: `const failure = error.details as Failure`
|
|
21
|
+
|
|
22
|
+
### Constants
|
|
23
|
+
- [ ] Method name added to `METHODS` constant
|
|
24
|
+
- [ ] Metric events added to `METRIC_EVENT_NAMES`
|
|
25
|
+
|
|
26
|
+
### Types
|
|
27
|
+
- [ ] Parameter type defined with JSDoc
|
|
28
|
+
- [ ] Return type defined with JSDoc
|
|
29
|
+
- [ ] Types exported from `src/types.ts`
|
|
30
|
+
|
|
31
|
+
### Tests
|
|
32
|
+
- [ ] Success case tested
|
|
33
|
+
- [ ] Error case tested
|
|
34
|
+
- [ ] Metrics tracking verified
|
|
35
|
+
- [ ] Logging verified
|
|
36
|
+
- [ ] Optional parameters tested
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Pattern Verification
|
|
41
|
+
|
|
42
|
+
### Correct Logging Pattern
|
|
43
|
+
```typescript
|
|
44
|
+
// ✅ At start
|
|
45
|
+
LoggerProxy.info('Starting operation', {
|
|
46
|
+
module: CC_FILE,
|
|
47
|
+
method: METHODS.METHOD_NAME,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ✅ On success
|
|
51
|
+
LoggerProxy.log('Operation completed successfully', {
|
|
52
|
+
module: CC_FILE,
|
|
53
|
+
method: METHODS.METHOD_NAME,
|
|
54
|
+
trackingId: result.trackingId,
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Error Logging — `error` vs `warn`
|
|
59
|
+
|
|
60
|
+
| Level | When to Use | Stack Trace Included? |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `LoggerProxy.error()` | Operation failures, API errors, exceptions in catch blocks | **Yes** — full stack trace is appended automatically |
|
|
63
|
+
| `LoggerProxy.warn()` | Non-critical issues that don't break flow (e.g., deprecation notices, fallback behavior) | **No** — only the message is logged |
|
|
64
|
+
|
|
65
|
+
> **Current codebase convention**: `LoggerProxy.error()` is used extensively across the SDK. `LoggerProxy.warn()` is not currently used in any source file. Default to `error` for catch blocks and failure paths.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// ✅ Error — in catch blocks and failure paths (includes stack trace)
|
|
69
|
+
LoggerProxy.error(`${methodName} failed with reason: ${reason}`, {
|
|
70
|
+
module: moduleName,
|
|
71
|
+
method: methodName,
|
|
72
|
+
trackingId: failure?.trackingId,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ✅ Error — via getErrorDetails (logs error + uploads logs automatically)
|
|
76
|
+
// Most methods use this pattern instead of calling LoggerProxy.error() directly
|
|
77
|
+
const {error: detailedError} = getErrorDetails(error, METHODS.METHOD_NAME, CC_FILE);
|
|
78
|
+
|
|
79
|
+
// ⚠️ Warn — for non-critical issues only (no stack trace)
|
|
80
|
+
LoggerProxy.warn('Falling back to default configuration', {
|
|
81
|
+
module: CC_FILE,
|
|
82
|
+
method: METHODS.METHOD_NAME,
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Note**: `getErrorDetails()` (in `src/services/core/Utils.ts`) already calls `LoggerProxy.error()` internally and uploads logs via `WebexRequest.uploadLogs()`. Do not double-log errors when using `getErrorDetails`.
|
|
87
|
+
|
|
88
|
+
### Correct Metrics Pattern
|
|
89
|
+
```typescript
|
|
90
|
+
// ✅ Start timing
|
|
91
|
+
this.metricsManager.timeEvent([
|
|
92
|
+
METRIC_EVENT_NAMES.SUCCESS,
|
|
93
|
+
METRIC_EVENT_NAMES.FAILED,
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
// ✅ Track success
|
|
97
|
+
this.metricsManager.trackEvent(
|
|
98
|
+
METRIC_EVENT_NAMES.SUCCESS,
|
|
99
|
+
{...MetricsManager.getCommonTrackingFieldForAQMResponse(result)},
|
|
100
|
+
['behavioral', 'operational']
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// ✅ Track failure
|
|
104
|
+
this.metricsManager.trackEvent(
|
|
105
|
+
METRIC_EVENT_NAMES.FAILED,
|
|
106
|
+
{...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure)},
|
|
107
|
+
['behavioral', 'operational']
|
|
108
|
+
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Correct Error Pattern
|
|
112
|
+
```typescript
|
|
113
|
+
// ✅
|
|
114
|
+
const failure = error.details as Failure;
|
|
115
|
+
this.metricsManager.trackEvent(FAILED_EVENT, {...}, [...]);
|
|
116
|
+
const {error: detailedError} = getErrorDetails(error, METHOD, MODULE);
|
|
117
|
+
throw detailedError;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Build & Test Verification
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Lint
|
|
126
|
+
yarn workspace @webex/contact-center test:styles
|
|
127
|
+
|
|
128
|
+
# Test unit tests
|
|
129
|
+
yarn workspace @webex/contact-center test:unit
|
|
130
|
+
|
|
131
|
+
# Build
|
|
132
|
+
yarn workspace @webex/contact-center build:src
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
All should pass without errors.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Complete!
|
|
140
|
+
|
|
141
|
+
Method addition is complete when all checkboxes are checked.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# New Service Creation - Master Template
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Orchestrator for creating new services or modules within the Contact Center SDK — whether top-level (e.g., AddressBook, EntryPoint, Queue), a sub-module under an existing service (e.g., a new module under `task/`), or an internal-only utility service.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Entry Paths
|
|
8
|
+
|
|
9
|
+
You can land on this template from:
|
|
10
|
+
- direct "create new service" requests
|
|
11
|
+
- "add feature" requests after feature triage determines the feature should be a standalone service/module
|
|
12
|
+
|
|
13
|
+
If coming from feature triage, include:
|
|
14
|
+
- feature placement rationale
|
|
15
|
+
- desired service/module name
|
|
16
|
+
- expected public API surface
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
Before starting, ensure you have:
|
|
23
|
+
- Clear understanding of what the service will do
|
|
24
|
+
- Complete API signature details (payload, response, HTTP method, endpoint)
|
|
25
|
+
- Event contract details when feature uses events (listener object, payload shape, emission source)
|
|
26
|
+
- Understanding of data structures involved
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Workflow Overview
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Step 1: Requirements → Step 2: Code Generation → Step 3: Integration → Step 4: Tests → Step 5: Validation
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Step-by-Step Process
|
|
39
|
+
|
|
40
|
+
### Step 1: Gather Requirements
|
|
41
|
+
**Template**: [`01-pre-questions.md`](01-pre-questions.md)
|
|
42
|
+
|
|
43
|
+
Answer these questions:
|
|
44
|
+
- What is the service name?
|
|
45
|
+
- What API endpoints will it call?
|
|
46
|
+
- What data will it manage?
|
|
47
|
+
- Will it be exposed on `cc.serviceName`?
|
|
48
|
+
|
|
49
|
+
### Step 2: Generate Code
|
|
50
|
+
**Template**: [`02-code-generation.md`](02-code-generation.md)
|
|
51
|
+
|
|
52
|
+
Create:
|
|
53
|
+
- Service class file (placement determined by pre-questions — see Step 1)
|
|
54
|
+
- Type definitions (location depends on placement — service folder's `types.ts` or root `src/types.ts`)
|
|
55
|
+
- Constants if needed (service folder's `constants.ts` or shared `src/services/constants.ts`)
|
|
56
|
+
|
|
57
|
+
### Step 3: Integration
|
|
58
|
+
**Template**: [`03-integration.md`](03-integration.md)
|
|
59
|
+
|
|
60
|
+
Integrate:
|
|
61
|
+
- Initialize the service (location depends on placement — `cc.ts` for top-level, parent service for sub-modules)
|
|
62
|
+
- Expose via `cc.serviceName` if developer confirmed public in pre-questions Q7
|
|
63
|
+
- Export types from `src/types.ts` (for public services only)
|
|
64
|
+
|
|
65
|
+
### Step 4: Generate Tests
|
|
66
|
+
**Template**: [`04-test-generation.md`](04-test-generation.md)
|
|
67
|
+
|
|
68
|
+
Create:
|
|
69
|
+
- Unit test file
|
|
70
|
+
- Mock service methods
|
|
71
|
+
- Test success and error cases
|
|
72
|
+
|
|
73
|
+
### Step 5: Validation
|
|
74
|
+
**Template**: [`05-validation.md`](05-validation.md)
|
|
75
|
+
|
|
76
|
+
Verify:
|
|
77
|
+
- All patterns followed
|
|
78
|
+
- Tests pass
|
|
79
|
+
- Types exported
|
|
80
|
+
- Documentation updated
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Patterns to Load
|
|
85
|
+
|
|
86
|
+
Before generating code, read:
|
|
87
|
+
1. [`../../patterns/typescript-patterns.md`](../../patterns/typescript-patterns.md) - Type conventions
|
|
88
|
+
2. [`../../patterns/event-driven-patterns.md`](../../patterns/event-driven-patterns.md) - Event and WebSocket patterns
|
|
89
|
+
3. [`../../patterns/testing-patterns.md`](../../patterns/testing-patterns.md) - Test patterns
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Reference Implementation
|
|
94
|
+
|
|
95
|
+
Study existing service: `src/services/AddressBook.ts` or `src/services/EntryPoint.ts`
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Quick Checklist
|
|
100
|
+
|
|
101
|
+
- [ ] Service class created with WebexSDK injection
|
|
102
|
+
- [ ] LoggerProxy used for all logging
|
|
103
|
+
- [ ] Metrics tracked for all operations (success + failure)
|
|
104
|
+
- [ ] Error handling follows `getErrorDetails` pattern
|
|
105
|
+
- [ ] Types defined and placed correctly (folder `types.ts` or root `src/types.ts`)
|
|
106
|
+
- [ ] Constants placed correctly (folder `constants.ts` or shared `src/services/constants.ts`)
|
|
107
|
+
- [ ] Initialized and integrated (in `cc.ts` for top-level, or parent service for sub-modules)
|
|
108
|
+
- [ ] Unit tests created
|
|
109
|
+
- [ ] JSDoc added for public methods
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# New Service - Pre-Questions
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Gather requirements from the developer before generating service code.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## STOP — Ask These Questions First
|
|
8
|
+
|
|
9
|
+
**You MUST present the following questions to the developer and wait for their answers before proceeding.** Do not infer answers from the developer's initial request. Do not fill in fields yourself. Do not read code or load patterns yet.
|
|
10
|
+
|
|
11
|
+
Present questions grouped by section. If the developer cannot answer a MANDATORY question, ask follow-up questions to help them clarify. Only proceed to code generation when all MANDATORY fields have explicit developer-provided answers.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Service Identity (MANDATORY)
|
|
16
|
+
|
|
17
|
+
Ask the developer:
|
|
18
|
+
|
|
19
|
+
1. **"What should the service be named?"**
|
|
20
|
+
- Must be PascalCase (e.g., "AddressBook", "Queue", "EntryPoint")
|
|
21
|
+
|
|
22
|
+
2. **"What problem does this service solve? What data does it manage?"**
|
|
23
|
+
- Need a one-sentence purpose description.
|
|
24
|
+
|
|
25
|
+
3. **"Where should this service live?"**
|
|
26
|
+
- **Folder-based service**: `src/services/ServiceName/` — complex service with its own folder, `index.ts`, `types.ts`, and optionally `constants.ts` (e.g., `agent/`, `config/`, `task/`)
|
|
27
|
+
- **Single-file service**: `src/services/ServiceName.ts` — lightweight service as a single file; types go in `src/types.ts`, constants go in `src/services/constants.ts` (e.g., `AddressBook.ts`, `EntryPoint.ts`, `Queue.ts`)
|
|
28
|
+
- **Sub-module under existing service**: a file within an existing service folder (e.g., `task/Voice.ts`, `task/Digital.ts`)
|
|
29
|
+
|
|
30
|
+
This determines the file structure and where types/constants are placed.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. API Contract (MANDATORY)
|
|
35
|
+
|
|
36
|
+
Ask the developer to provide the complete API signature for **each** API the service will use:
|
|
37
|
+
|
|
38
|
+
4. **"What API endpoint(s) will this service call? For each, provide:"**
|
|
39
|
+
|
|
40
|
+
| Field | What to Ask |
|
|
41
|
+
|---|---|
|
|
42
|
+
| API Name | "What should the method be called?" (e.g., `getEntries`, `createItem`) |
|
|
43
|
+
| HTTP Method | "Is this a GET, POST, PUT, or DELETE?" |
|
|
44
|
+
| Endpoint | "What is the full endpoint path?" (e.g., `/v1/address-books/{id}/entries`) |
|
|
45
|
+
| Request Payload | "What fields does the request body contain? Which are required vs optional?" |
|
|
46
|
+
| Response Structure | "What does the response look like? What fields does `data` contain?" |
|
|
47
|
+
| Error Shape | "What error reason codes can this return?" |
|
|
48
|
+
|
|
49
|
+
**If any API field is unknown, STOP and ask the developer before proceeding. Do not guess endpoint structures or payload shapes.**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 3. Event Contract (MANDATORY if the service uses events, otherwise skip)
|
|
54
|
+
|
|
55
|
+
Ask the developer:
|
|
56
|
+
|
|
57
|
+
5. **"Does this service listen to or emit any events?"**
|
|
58
|
+
- If YES, for each event ask:
|
|
59
|
+
|
|
60
|
+
| Field | What to Ask |
|
|
61
|
+
|---|---|
|
|
62
|
+
| Event Name | "What is the event name?" |
|
|
63
|
+
| Direction | "Is this incoming (received from WebSocket) or outgoing (emitted by SDK)?" |
|
|
64
|
+
| Source | "Is this a WebSocket event, or an internal EventEmitter event?" |
|
|
65
|
+
| Listen/Emit Object | "Where do consumers subscribe to this event?" (`cc`, `task`, `taskManager`, service) |
|
|
66
|
+
| Payload Type/Shape | "What data does the event carry? What are the field names and types?" |
|
|
67
|
+
| Emitted From | "Which class/file/method emits this event?" |
|
|
68
|
+
| Emission Trigger | "What causes this event to fire?" |
|
|
69
|
+
|
|
70
|
+
- If any events come from WebSocket: "How should these WebSocket events map to service behavior?"
|
|
71
|
+
- If NO events at all, skip to section 4.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 4. Dependencies & Exposure (MANDATORY)
|
|
76
|
+
|
|
77
|
+
Ask the developer:
|
|
78
|
+
|
|
79
|
+
6. **"Does this service need any data from the agent profile?"**
|
|
80
|
+
- If YES: "Which specific fields?" (e.g., `addressBookId`, `teamIds`)
|
|
81
|
+
- If NO: note "No profile dependency"
|
|
82
|
+
|
|
83
|
+
7. **"Should this service be accessible as `cc.serviceName` (public API), or is it internal only?"**
|
|
84
|
+
- If public: it will be exposed on the `cc` object and types will be re-exported from `src/types.ts`
|
|
85
|
+
- If internal: it will only be used by other services within the SDK
|
|
86
|
+
|
|
87
|
+
8. **"What methods should be exposed? For each method, what is the expected behavior?"**
|
|
88
|
+
- e.g., `getEntries(params)` — Fetch paginated list
|
|
89
|
+
- e.g., `getEntryById(id)` — Fetch single item
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 6. Caching (OPTIONAL)
|
|
94
|
+
|
|
95
|
+
Ask the developer:
|
|
96
|
+
|
|
97
|
+
9. **"Should responses be cached in memory, or should every call fetch fresh data?"**
|
|
98
|
+
- If caching: "What is the cache invalidation strategy?"
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Completion Gate
|
|
103
|
+
|
|
104
|
+
**Before proceeding, verify:**
|
|
105
|
+
|
|
106
|
+
- [ ] Service name provided by developer
|
|
107
|
+
- [ ] Service purpose described by developer
|
|
108
|
+
- [ ] Service placement decided (top-level, sub-module, or single file)
|
|
109
|
+
- [ ] At least one API endpoint fully specified (method, path, request, response, errors)
|
|
110
|
+
- [ ] Event contract captured (or developer confirmed no events)
|
|
111
|
+
- [ ] Dependencies identified (or developer confirmed none)
|
|
112
|
+
- [ ] Exposure decision made (public vs internal)
|
|
113
|
+
- [ ] Methods to expose listed
|
|
114
|
+
|
|
115
|
+
**If any MANDATORY field above is missing an explicit developer answer, ask a targeted follow-up question. Do not proceed.**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Spec Summary
|
|
120
|
+
|
|
121
|
+
Once all questions are answered, present this summary to the developer for approval before proceeding to code generation:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
## Spec Summary — New Service
|
|
125
|
+
|
|
126
|
+
**Service Name**: [from Q1]
|
|
127
|
+
**Purpose**: [from Q2]
|
|
128
|
+
**Placement**: [from Q3 — folder-based / single-file / sub-module under {parent}]
|
|
129
|
+
**Target location**: [derived from Q3, e.g., `src/services/ServiceName/` or `src/services/ServiceName.ts` or `src/services/{parent}/ServiceName.ts`]
|
|
130
|
+
|
|
131
|
+
### API Contract:
|
|
132
|
+
| Method | HTTP | Endpoint | Request | Response |
|
|
133
|
+
|---|---|---|---|---|
|
|
134
|
+
| [method] | [GET/POST/...] | [path] | [payload] | [response] |
|
|
135
|
+
|
|
136
|
+
### Events:
|
|
137
|
+
[event table or "None"]
|
|
138
|
+
|
|
139
|
+
### Dependencies:
|
|
140
|
+
- Profile fields: [list or "None"]
|
|
141
|
+
|
|
142
|
+
### Exposure:
|
|
143
|
+
- Public API: [Yes/No] — `cc.[serviceName]`
|
|
144
|
+
- Methods: [list]
|
|
145
|
+
|
|
146
|
+
### Caching: [Yes/No]
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
Does this match your intent? (Yes / No / Adjust)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Wait for developer approval. Do not proceed to [`02-code-generation.md`](02-code-generation.md) until confirmed.**
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Next Step
|
|
157
|
+
|
|
158
|
+
Once the developer approves the spec summary, proceed to:
|
|
159
|
+
[`02-code-generation.md`](02-code-generation.md)
|