diff --git a/ai-docs/templates/README.md b/ai-docs/templates/README.md new file mode 100644 index 000000000..d14e2949e --- /dev/null +++ b/ai-docs/templates/README.md @@ -0,0 +1,71 @@ +# AI Templates Directory + +## Purpose + +Templates for generating and maintaining contact center widgets and components. + +## Structure + +``` +templates/ +├── new-widget/ # Widget generation (7 modules) +├── existing-widget/ # Bug fixes, features (2 modules) +└── documentation/ # Documentation generation (2 modules, reusable for all packages) +``` + +## Templates + +### 1. New Widget Generation + +**Directory:** [new-widget/](./new-widget/) + +**Modules:** +- [00-master.md](./new-widget/00-master.md) - Orchestrator & workflow +- [01-pre-questions.md](./new-widget/01-pre-questions.md) - Requirements gathering +- [02-code-generation.md](./new-widget/02-code-generation.md) - Widget code patterns +- [03-component-generation.md](./new-widget/03-component-generation.md) - Presentational components (conditional) +- [04-integration.md](./new-widget/04-integration.md) - cc-widgets + samples integration +- [05-test-generation.md](./new-widget/05-test-generation.md) - Test patterns +- [06-validation.md](./new-widget/06-validation.md) - Quality checklist + +### 2. Existing Widget Maintenance + +**Directory:** [existing-widget/](./existing-widget/) + +**Modules:** +- [bug-fix.md](./existing-widget/bug-fix.md) - Bug fix workflow +- [feature-enhancement.md](./existing-widget/feature-enhancement.md) - Feature addition workflow + +### 3. Documentation Generation + +**Directory:** [documentation/](./documentation/) + +**Reusable for:** Widgets, store, components, utilities + +**Modules:** +- [create-agent-md.md](./documentation/create-agent-md.md) - Generate AGENTS.md +- [create-architecture-md.md](./documentation/create-architecture-md.md) - Generate ARCHITECTURE.md + +--- + +## Usage + +**New Widget:** Start with [new-widget/00-master.md](./new-widget/00-master.md) + +**Bug Fix:** Read [existing-widget/bug-fix.md](./existing-widget/bug-fix.md) + +**Feature Addition:** Read [existing-widget/feature-enhancement.md](./existing-widget/feature-enhancement.md) + +**Documentation Only:** Use [documentation/](./documentation/) templates + +## Pattern References + +- [TypeScript Patterns](../patterns/typescript-patterns.md) +- [React Patterns](../patterns/react-patterns.md) +- [MobX Patterns](../patterns/mobx-patterns.md) +- [Web Component Patterns](../patterns/web-component-patterns.md) +- [Testing Patterns](../patterns/testing-patterns.md) + +--- + +_Last Updated: 2025-11-26_ diff --git a/ai-docs/templates/documentation/create-agent-md.md b/ai-docs/templates/documentation/create-agent-md.md new file mode 100644 index 000000000..9eb8d6fd0 --- /dev/null +++ b/ai-docs/templates/documentation/create-agent-md.md @@ -0,0 +1,507 @@ +# Create AGENTS.md Template + +## Overview + +This template generates the `AGENTS.md` file for any package (widgets, store, components, utilities). It provides usage documentation optimized for LLM consumption. + +**Purpose:** User-facing documentation with examples and API reference + +**Token Optimized:** Architecture link at the END for token efficiency + +**Reusable For:** All packages in the monorepo + +--- + +## When to Use + +- Creating new widget documentation +- Creating new package documentation +- Updating existing AGENTS.md +- Adding missing examples + +--- + +## Pre-Generation Questions + +### 1. Package Information + +- **Package name:** _______________ + - Example: `@webex/cc-agent-directory`, `@webex/cc-store` +- **Package type:** Widget | Store | Component Library | Utility +- **Display name:** _______________ + - Example: "Agent Directory", "CC Store", "CC Components" + +### 2. Purpose & Capabilities + +- **Primary purpose (one sentence):** _______________ +- **Key capabilities (3-5 bullet points):** _______________ +- **Problem it solves:** _______________ + +### 3. Usage Examples Needed + +- **How many examples to include:** 4-6 (recommended) +- **Example scenarios:** _______________ + - Basic usage (always include) + - Common use cases + - Integration patterns + - Error handling + +### 4. API Surface + +- **Props/Parameters:** List all public props/parameters +- **Callbacks/Events:** List all callbacks/events +- **Methods (if applicable):** List all public methods + +--- + +## AGENTS.md Structure + +```markdown +# {Display Name} + +## Overview + +{Brief description of the package - 2-3 sentences} + +**Package:** `{package-name}` + +**Version:** See [package.json](../package.json) + +--- + +## Why and What is This Used For? + +### Purpose + +{Explain the purpose and problem it solves - 3-4 sentences} + +### Key Capabilities + +- **Capability 1** - Brief description +- **Capability 2** - Brief description +- **Capability 3** - Brief description +- **Capability 4** - Brief description +- **Capability 5** - Brief description + +--- + +## Examples and Use Cases + +### Getting Started + +#### Basic Usage (React) + +```typescript +import { {PackageName} } from '{package-name}'; + +function MyApp() { + const handleEvent = (data) => { + console.log('Event:', data); + }; + + return ( + <{PackageName} + requiredProp="value" + onEvent={handleEvent} + /> + ); +} +``` + +#### Web Component Usage (If Applicable) + +```html + + + + + + + + + + + + +``` + +### Common Use Cases + +#### 1. {Use Case Title} + +{Brief description of the use case} + +```typescript +import { {PackageName} } from '{package-name}'; + +// Code example demonstrating this use case +// Include comments explaining key parts +``` + +**Key Points:** +- Point about this use case +- Another important note +- When to use this pattern + +#### 2. {Use Case Title} + +{Brief description of the use case} + +```typescript +// Code example +``` + +**Key Points:** +- Point about this use case +- Another important note + +#### 3. {Use Case Title} + +{Continue with 4-6 realistic examples total} + +### Integration Patterns (Optional) + +#### Pattern 1: {Pattern Name} + +```typescript +// Integration pattern example +``` + +#### Pattern 2: {Pattern Name} + +```typescript +// Integration pattern example +``` + +--- + +## Dependencies + +**Note:** For exact versions, see [package.json](../package.json) + +### Runtime Dependencies + +| Package | Purpose | +|---------|---------| +| `{dependency-1}` | Purpose description | +| `{dependency-2}` | Purpose description | +| `{dependency-3}` | Purpose description | + +### Peer Dependencies + +| Package | Purpose | +|---------|---------| +| `{peer-dep-1}` | Purpose description | +| `{peer-dep-2}` | Purpose description | + +### Development Dependencies + +Key development tools (see [package.json](../package.json) for versions): +- TypeScript +- Jest (testing) +- Webpack (bundling) +- ESLint (linting) + +--- + +## API Reference + +{Choose the appropriate section based on package type} + +### For Widgets: Props API + +| Prop | Type | Required | Default | Description | +|------|------|----------|---------|-------------| +| `requiredProp` | `string` | Yes | - | Description of what this prop does | +| `optionalProp` | `number` | No | `10` | Description with default value | +| `onEvent` | `(data: Type) => void` | No | - | Callback description | +| `onError` | `(error: Error) => void` | No | - | Error callback | + +### For Store: Methods API + +| Method | Parameters | Returns | Description | +|--------|------------|---------|-------------| +| `init()` | `config: Config` | `Promise` | Initializes the store | +| `getItems()` | `params?: Params` | `Promise` | Fetches items | +| `setItem()` | `item: Item` | `void` | Sets an item | + +### For Components: Exported Components + +| Component | Purpose | Props Interface | +|-----------|---------|-----------------| +| `Component1` | Purpose | `Component1Props` | +| `Component2` | Purpose | `Component2Props` | +| `Component3` | Purpose | `Component3Props` | + +### For Utilities: Functions API + +| Function | Parameters | Returns | Description | +|----------|------------|---------|-------------| +| `utilityFn1()` | `param: Type` | `ReturnType` | What it does | +| `utilityFn2()` | `param: Type` | `ReturnType` | What it does | + +--- + +## Installation + +```bash +yarn add {package-name} +``` + +{If peer dependencies required, add:} + +### Peer Dependencies Required + +```bash +yarn add @momentum-ui/react-collaboration react react-dom +``` + +--- + +## Additional Resources + +For detailed {architecture/implementation/technical details}, see [ARCHITECTURE.md](./ARCHITECTURE.md). + +--- + +_Last Updated: {YYYY-MM-DD}_ +``` + +--- + +## Content Guidelines + +### Overview Section + +**Do:** +- Keep it brief (2-3 sentences) +- Mention package name clearly +- Reference package.json for version +- Explain at high level what it is + +**Don't:** +- Go into technical details (save for ARCHITECTURE.md) +- Include code examples yet +- Hardcode version numbers + +--- + +### Purpose Section + +**Do:** +- Explain why this package exists +- Describe the problem it solves +- List 3-5 key capabilities +- Be clear and concise + +**Don't:** +- Duplicate overview content +- Go into implementation details +- Use jargon without explanation + +--- + +### Examples Section + +**Do:** +- Start with simplest example +- Include 4-6 realistic use cases +- Add comments explaining key parts +- Show both success and error handling +- Include Web Component example if applicable + +**Don't:** +- Show overly complex examples first +- Skip error handling +- Use unrealistic scenarios +- Include incomplete code + +**Example Structure:** +1. Basic usage (required) +2. Common use case 1 +3. Common use case 2 +4. Error handling +5. Advanced pattern +6. Integration pattern + +--- + +### Dependencies Section + +**Do:** +- Reference package.json for versions +- Explain purpose of each dependency +- Separate runtime, peer, and dev dependencies +- Keep descriptions brief + +**Don't:** +- Hardcode version numbers +- List every dev dependency +- Skip explaining purpose + +--- + +### API Section + +**Do:** +- Use table format for easy scanning +- Include all required information +- Mark required vs optional +- Include default values +- Link to type definitions + +**Don't:** +- Skip descriptions +- Forget to mark required fields +- Use ambiguous type names +- Skip examples for complex props + +--- + +### Token Optimization + +**Key Strategy:** +- **Architecture link goes at the END** +- LLM reads AGENTS.md first for most queries +- Only loads ARCHITECTURE.md when needed +- Saves 500+ tokens for simple queries + +**Example Query Paths:** + +Query: "How do I use AgentDirectory?" +- LLM reads: AGENTS.md only (~400 tokens) +- Finds: Basic usage example +- Returns: Answer without needing ARCHITECTURE.md + +Query: "How does AgentDirectory integrate with the store?" +- LLM reads: AGENTS.md (~400 tokens) +- Sees: Link to ARCHITECTURE.md at end +- Reads: ARCHITECTURE.md (~500 tokens) +- Returns: Detailed architecture answer + +--- + +## Validation Checklist + +Before considering AGENTS.md complete: + +### Content Completeness +- [ ] Overview section complete +- [ ] Purpose clearly explained +- [ ] 3-5 key capabilities listed +- [ ] 4-6 usage examples provided +- [ ] Dependencies documented +- [ ] API reference complete +- [ ] Installation instructions included + +### Quality Checks +- [ ] All code examples work +- [ ] No hardcoded versions (references package.json) +- [ ] Examples have comments +- [ ] Error handling shown +- [ ] Props/methods fully documented +- [ ] Link to ARCHITECTURE.md at END + +### Formatting +- [ ] Markdown renders correctly +- [ ] Code blocks have language tags +- [ ] Tables format properly +- [ ] No broken links +- [ ] Consistent heading levels + +--- + +## Examples by Package Type + +### Widget Package Example + +**Package:** `@webex/cc-agent-directory` + +**Key Sections:** +- Props API table (all props documented) +- Both React and Web Component examples +- Common use cases: search, filter, select +- Integration with store and SDK +- Error handling patterns + +**Example Count:** 6 +1. Basic usage +2. Search functionality +3. Filter by availability +4. Agent selection +5. Error handling +6. Custom styling + +--- + +### Store Package Example + +**Package:** `@webex/cc-store` + +**Key Sections:** +- Methods API table (all methods documented) +- Initialization examples +- Observable usage +- Event subscription +- Data fetching patterns + +**Example Count:** 5 +1. Basic initialization +2. Reading observables +3. Setting callbacks +4. Fetching data +5. Error handling + +--- + +### Component Library Example + +**Package:** `@webex/cc-components` + +**Key Sections:** +- Exported components table +- Component usage examples +- Props patterns +- Styling approach +- Integration with widgets + +**Example Count:** 4 +1. Basic component usage +2. Composing components +3. Custom styling +4. Integration with widgets + +--- + +### Utility Package Example + +**Package:** `@webex/cc-ui-logging` + +**Key Sections:** +- Functions API table +- HOC usage +- Direct function calls +- Integration patterns + +**Example Count:** 4 +1. Using withMetrics HOC +2. Direct logMetrics call +3. Custom metrics +4. Integration with widgets + +--- + +## Related Templates + +- **[create-architecture-md.md](./create-architecture-md.md)** - Technical architecture docs + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/documentation/create-architecture-md.md b/ai-docs/templates/documentation/create-architecture-md.md new file mode 100644 index 000000000..de2af39f0 --- /dev/null +++ b/ai-docs/templates/documentation/create-architecture-md.md @@ -0,0 +1,683 @@ +# Create ARCHITECTURE.md Template + +## Overview + +This template generates the `ARCHITECTURE.md` file for any package. It provides technical documentation about implementation, data flows, and troubleshooting. + +**Purpose:** Technical deep-dive for developers and AI assistants + +**Required:** Mermaid diagrams (not PlantUML) for native rendering + +**Reusable For:** All packages in the monorepo + +--- + +## When to Use + +- Creating new package documentation +- Documenting complex architecture +- Adding sequence diagrams +- Creating troubleshooting guides +- Updating after architectural changes + +--- + +## Pre-Generation Questions + +### 1. Package Information + +- **Package name:** _______________ +- **Package type:** Widget | Store | Component Library | Utility +- **Display name:** _______________ + +### 2. Architecture Details + +- **Number of components/modules:** _______________ +- **Key files to document:** _______________ +- **Layer interactions:** Which layers does this package touch? +- **External dependencies:** SDK, store, other packages? + +### 3. Diagrams Needed + +- **Layer communication diagram:** Yes / No +- **Sequence diagrams:** How many scenarios? (recommend 3-5) +- **Flow diagrams:** Any special flows to document? + +### 4. Troubleshooting + +- **Common issues:** List 5-8 common issues users face +- **For each issue:** + - Symptoms + - Possible causes + - Solutions + +--- + +## ARCHITECTURE.md Structure + +```markdown +# {Display Name} - Architecture + +## Component Overview + +{Brief architectural overview - 2-3 sentences explaining the design} + +### Component Table + +| Component/Module | File | Purpose | Props/Params | State | Callbacks | Tests | Dependencies | +|------------------|------|---------|--------------|-------|-----------|-------|--------------| +| **Component1** | `src/file.tsx` | Purpose | PropType | Local state | onEvent | `tests/file.tsx` | Dependencies | +| **Component2** | `src/file2.ts` | Purpose | ParamType | Returns X | N/A | `tests/file2.ts` | Dependencies | +| **Component3** | `src/file3.tsx` | Purpose | PropType | N/A | onCallback | `tests/file3.tsx` | Dependencies | + +{Add rows for each major component/module in the package} + +--- + +## SDK Integration (If Applicable) + +{Only include if package integrates with SDK} + +| Area | SDK Methods Used | SDK Events Subscribed | Package Methods | +|------|------------------|----------------------|-----------------| +| Initialization | `register()`, `LoggerProxy` | `agent:dnRegistered` | `init()`, `setup()` | +| Operations | `someMethod()` | `event:name` | `handler()` | + +--- + +## File Structure + +``` +{package-name}/ +├── src/ +│ ├── {main-component}/ +│ │ ├── index.tsx # Main component +│ │ └── {name}.types.ts # Type definitions +│ ├── helper.ts # Helper functions +│ ├── utils.ts # Utilities +│ ├── constants.ts # Constants +│ ├── index.ts # Package exports +│ └── wc.ts # Web Component export (if applicable) +├── ai-docs/ +│ ├── AGENTS.md # Usage docs +│ └── ARCHITECTURE.md # This file +├── tests/ +│ ├── {main-component}/ +│ │ └── index.tsx # Component tests +│ ├── helper.ts # Helper tests +│ └── utils.ts # Utility tests +├── package.json +├── tsconfig.json +├── webpack.config.js +└── ... config files +``` + +--- + +## Data Flows + +### Layer Communication Flow + +{Show how this package fits into the overall architecture} + +```mermaid +graph TB + subgraph "Layer 1" + A[Component A] + B[Component B] + end + + subgraph "Layer 2" + C[Module C] + D[Module D] + end + + subgraph "Layer 3" + E[External System] + end + + A -->|Action| C + B -->|Action| C + C -->|Calls| E + E -->|Response| C + C -->|Update| A + C -->|Update| B + + style A fill:#e1f5ff + style C fill:#fff4e1 + style E fill:#ffe1e1 +``` + +### Hook/Module Details (If Applicable) + +{For widgets, explain hook logic. For utilities, explain key functions} + +**Key Responsibilities:** +- Responsibility 1 +- Responsibility 2 +- Responsibility 3 + +**Data Transformations:** +- Input → Processing → Output + +--- + +## Sequence Diagrams + +{Include 3-5 sequence diagrams for key scenarios} + +### Scenario 1: {Initialization/Setup/Main Flow} + +{Brief description of this scenario} + +```mermaid +sequenceDiagram + participant A as Component A + participant B as Module B + participant C as External System + participant D as Store/State + + A->>B: Action initiated + activate B + + B->>D: Read state + D-->>B: Current state + + B->>C: API call + C-->>B: Response + + B->>D: Update state + + B-->>A: Action complete + deactivate B + + A->>A: Update UI +``` + +### Scenario 2: {User Interaction/Event Handling} + +{Brief description} + +```mermaid +sequenceDiagram + participant User + participant Component + participant Hook + participant Store + participant SDK + + User->>Component: Interaction + Component->>Hook: Handler called + activate Hook + + Hook->>Store: Read data + Store-->>Hook: Data + + Hook->>SDK: SDK method + SDK-->>Hook: Success/Error + + alt Success + Hook->>Store: Update (runInAction) + Hook->>Component: Callback + else Error + Hook->>Component: Error callback + end + + deactivate Hook + Component-->>User: UI updated +``` + +### Scenario 3: {Error Handling/Edge Case} + +{Brief description} + +```mermaid +sequenceDiagram + participant Component + participant Module + participant External + + Component->>Module: Request + activate Module + + Module->>External: Call + External-->>Module: Error + + Module->>Module: Handle error + Module->>Module: Log error + Module->>Module: Set error state + + Module-->>Component: Error response + deactivate Module + + Component->>Component: Display error UI +``` + +{Add 2-3 more scenarios as needed} + +--- + +## Integration Architecture (If Applicable) + +{For widgets, show how they integrate with cc-widgets} +{For components, show how they're used by widgets} +{For utilities, show usage patterns} + +### Integration Pattern + +```mermaid +graph LR + subgraph "Consumer" + A[Application] + end + + subgraph "This Package" + B[Main Export] + C[Module 1] + D[Module 2] + end + + subgraph "Dependencies" + E[Dependency 1] + F[Dependency 2] + end + + A -->|Uses| B + B -->|Imports| C + B -->|Imports| D + C -->|Calls| E + D -->|Calls| F +``` + +--- + +## Troubleshooting Guide + +### Common Issues + +{Include 5-8 common issues with detailed solutions} + +#### 1. {Issue Title} + +**Symptoms:** +- Symptom 1 +- Symptom 2 +- What the user sees + +**Possible Causes:** +- Cause 1 with explanation +- Cause 2 with explanation +- Cause 3 with explanation + +**Solutions:** + +```typescript +// Solution 1: Check X +import { Package } from '{package-name}'; + +// Verify condition +console.log('Check:', condition); + +// Fix approach +const fixed = correctWay(); +``` + +```typescript +// Solution 2: Alternative approach +// Step-by-step fix with code +``` + +**Prevention:** +- How to avoid this issue in future +- Best practices + +--- + +#### 2. {Issue Title} + +**Symptoms:** +- What happens + +**Possible Causes:** +- Why this happens + +**Solutions:** + +```typescript +// Code solution +``` + +--- + +{Continue with 5-8 total issues} + +--- + +## Performance Considerations (Optional) + +{Include if package has performance implications} + +### Optimization Strategies + +1. **Strategy 1** + - Description + - When to use + - Code example + +2. **Strategy 2** + - Description + - When to use + - Code example + +### Common Performance Issues + +- Issue and solution +- Issue and solution + +--- + +## Related Documentation + +- [Agent Documentation](./AGENTS.md) - Usage examples and API +- [{Related Pattern}](../../../../ai-docs/patterns/{pattern}.md) - Pattern documentation +- [{Related Package}](../../{package}/ai-docs/AGENTS.md) - Related package docs +- [{Another Related}](../../{package}/ai-docs/ARCHITECTURE.md) - Related architecture + +--- + +_Last Updated: {YYYY-MM-DD}_ +``` + +--- + +## Content Guidelines + +### Component Overview Section + +**Do:** +- Provide architectural context +- Explain design decisions +- Use component table for structure +- Include all major files + +**Don't:** +- Duplicate AGENTS.md content +- Skip test file locations +- Forget dependencies column + +**Component Table Requirements:** +- List all major components/modules +- Include file paths +- Document props/parameters +- Note callbacks/events +- Reference test locations +- List key dependencies + +--- + +### File Structure Section + +**Do:** +- Show complete directory tree +- Include all important files +- Add comments explaining purpose +- Match actual structure + +**Don't:** +- Include build artifacts +- Show node_modules +- Skip configuration files + +--- + +### Data Flows Section + +**Do:** +- Use Mermaid diagrams (not PlantUML) +- Show layer interactions +- Include data direction arrows +- Color-code by layer +- Keep diagrams focused + +**Don't:** +- Make diagrams too complex +- Skip important connections +- Use PlantUML syntax +- Forget to label arrows + +**Mermaid Tips:** +- `graph TB` for top-to-bottom flow +- `graph LR` for left-to-right flow +- `subgraph` for grouping +- `style X fill:#color` for coloring +- `-->` for arrows, `-->>` for returns + +--- + +### Sequence Diagrams Section + +**Do:** +- Show 3-5 key scenarios +- Include initialization flow +- Show error handling +- Document edge cases +- Use clear participant names +- Add activation boxes +- Use alt/else for conditionals + +**Don't:** +- Show every possible flow +- Make diagrams too detailed +- Skip error scenarios +- Use ambiguous names + +**Mermaid Sequence Tips:** +- `participant A as Name` for custom names +- `activate/deactivate` for active periods +- `alt/else/end` for conditionals +- `loop/end` for loops +- `Note over A,B: text` for notes + +--- + +### Troubleshooting Section + +**Do:** +- Include 5-8 common issues +- Use consistent structure +- Provide code solutions +- Explain prevention +- Cover both simple and complex issues + +**Don't:** +- Skip symptoms or causes +- Provide solutions without context +- Use vague descriptions +- Forget to include code examples + +**Issue Structure:** +1. **Title:** Clear, specific issue name +2. **Symptoms:** What user experiences +3. **Possible Causes:** Why it happens (2-3 causes) +4. **Solutions:** Code-based fixes (2-3 solutions) +5. **Prevention:** How to avoid + +--- + +## Diagram Guidelines + +### Use Mermaid (Not PlantUML) + +**Why Mermaid:** +- Native GitHub/GitLab rendering +- Better IDE support +- Simpler syntax +- No external server needed + +**Conversion from PlantUML:** + +PlantUML: +```plantuml +@startuml +Alice -> Bob: Hello +Bob --> Alice: Hi +@enduml +``` + +Mermaid: +```mermaid +sequenceDiagram + Alice->>Bob: Hello + Bob-->>Alice: Hi +``` + +### Diagram Types + +**Layer Communication:** +```mermaid +graph TB + A[Widget] --> B[Hook] + B --> C[Store] + C --> D[SDK] +``` + +**Sequence Diagram:** +```mermaid +sequenceDiagram + participant A + participant B + A->>B: Request + B-->>A: Response +``` + +**Integration Flow:** +```mermaid +graph LR + A[App] -->|uses| B[Package] + B -->|calls| C[Dependency] +``` + +--- + +## Validation Checklist + +Before considering ARCHITECTURE.md complete: + +### Content Completeness +- [ ] Component overview complete +- [ ] Component table has all major components +- [ ] File structure matches reality +- [ ] Data flow diagram included +- [ ] 3-5 sequence diagrams included +- [ ] 5-8 troubleshooting issues documented +- [ ] Related docs linked + +### Diagram Quality +- [ ] All diagrams use Mermaid (not PlantUML) +- [ ] Diagrams render correctly +- [ ] Labels are clear +- [ ] Arrows show data flow direction +- [ ] Colors used for emphasis (optional) +- [ ] Diagrams are focused (not too complex) + +### Troubleshooting Quality +- [ ] Each issue has symptoms +- [ ] Each issue has 2-3 causes +- [ ] Each issue has code solutions +- [ ] Prevention tips included +- [ ] Issues cover common scenarios + +### Formatting +- [ ] Markdown renders correctly +- [ ] Code blocks have language tags +- [ ] Tables format properly +- [ ] No broken links +- [ ] Consistent heading levels + +--- + +## Examples by Package Type + +### Widget Architecture + +**Focus:** +- Widget → Hook → Component → Store → SDK flow +- Initialization sequence +- User interaction flows +- Error handling +- Store integration + +**Diagrams:** +- Layer communication (5 layers) +- Initialization sequence +- User interaction sequence +- Error handling sequence +- Store update sequence + +**Troubleshooting:** +- Widget not rendering +- Callbacks not firing +- Store not updating +- Props not passing +- Performance issues + +--- + +### Store Architecture + +**Focus:** +- Store structure +- Observable management +- Event handling +- SDK integration +- Data fetching + +**Diagrams:** +- Store modules +- Initialization flow +- Event subscription +- Data fetch flow +- State update flow + +**Troubleshooting:** +- Store not initializing +- Events not firing +- Data not updating +- Memory leaks +- Performance issues + +--- + +### Component Library Architecture + +**Focus:** +- Component structure +- Props patterns +- Composition +- Styling approach +- Momentum UI integration + +**Diagrams:** +- Component hierarchy +- Props flow +- Event bubbling +- Styling approach + +**Troubleshooting:** +- Components not rendering +- Props not passing +- Styles not applying +- Event handlers not firing +- Performance issues + +--- + +## Related Templates + +- **[create-agent-md.md](./create-agent-md.md)** - User-facing documentation + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/existing-widget/bug-fix.md b/ai-docs/templates/existing-widget/bug-fix.md new file mode 100644 index 000000000..3ed087eff --- /dev/null +++ b/ai-docs/templates/existing-widget/bug-fix.md @@ -0,0 +1,596 @@ +# Bug Fix Template + +## Overview + +This template guides you through fixing bugs in existing widgets following established patterns and ensuring no regressions. + +**Purpose:** Systematic approach to bug fixes + +**Scope:** Widgets, components, hooks, store integration + +--- + +## When to Use + +- Reported bug in existing widget +- UI not rendering correctly +- Callbacks not firing +- Store integration issues +- Performance problems +- Test failures + +--- + +## Pre-Fix Questions + +### 1. Bug Information + +- **Which widget/component has the bug?** _______________ +- **Bug description (one sentence):** _______________ +- **Steps to reproduce:** + 1. _______________ + 2. _______________ + 3. _______________ +- **Expected behavior:** _______________ +- **Actual behavior:** _______________ + +### 2. Bug Scope + +- **Which layer is affected?** + - [ ] Widget component + - [ ] Hook (helper.ts) + - [ ] Presentational component + - [ ] Store integration + - [ ] SDK integration + +- **Error messages:** + - Console errors: _______________ + - Linter errors: _______________ + - Test failures: _______________ + +### 3. Impact Assessment + +- **Severity:** Critical / High / Medium / Low +- **User Impact:** _______________ +- **Affects other widgets?** Yes / No + - If yes, which ones: _______________ +- **Is there a workaround?** Yes / No + - If yes, describe: _______________ + +### 4. Existing Tests + +- **Is there a test for this scenario?** Yes / No +- **Are tests failing?** Yes / No +- **Test file location:** _______________ + +--- + +## Step 1: Understand the Bug + +### 1.1 Reproduce the Bug + +```typescript +// Create minimal reproduction +// 1. Set up component +// 2. Trigger the bug +// 3. Observe the issue +``` + +**Reproduction confirmed:** Yes / No + +### 1.2 Identify the Root Cause + +**Read relevant files:** +- Widget component: `src/{widget-name}/index.tsx` +- Hook: `src/helper.ts` +- Presentational component: Check cc-components +- Store: Check store integration +- Types: `src/{widget-name}/{widget-name}.types.ts` + +**Check for:** +- [ ] Missing null/undefined checks +- [ ] Incorrect MobX usage (missing observer, runInAction) +- [ ] Wrong prop types +- [ ] Missing error boundaries +- [ ] Race conditions +- [ ] Memory leaks +- [ ] Event listener issues + +**Root cause:** _______________ + +### 1.3 Verify Layer Boundaries + +**Architecture check:** +``` +✅ Widget → Hook → Component → Store → SDK +❌ Widget → SDK (layer violation) +❌ Component → Store (layer violation) +``` + +**Is there a layer violation?** Yes / No +- If yes, this is likely the root cause + +--- + +## Step 2: Plan the Fix + +### 2.1 Fix Strategy + +**Choose approach:** + +- [ ] **Defensive Fix:** Add null checks, error handling +- [ ] **Refactor Fix:** Restructure code to prevent issue +- [ ] **Pattern Fix:** Apply correct pattern (MobX, React) +- [ ] **Integration Fix:** Fix store/SDK integration +- [ ] **Type Fix:** Add/fix TypeScript types + +**Fix description:** _______________ + +### 2.2 Files to Modify + +List all files that need changes: +- [ ] `src/{widget-name}/index.tsx` +- [ ] `src/helper.ts` +- [ ] `src/{widget-name}/{widget-name}.types.ts` +- [ ] `tests/{widget-name}/index.tsx` +- [ ] `tests/helper.ts` +- [ ] `ai-docs/ARCHITECTURE.md` +- [ ] Other: _______________ + +### 2.3 Breaking Changes? + +**Will this fix break existing functionality?** Yes / No + +If Yes: +- Document breaking change +- Update version (major/minor) +- Update migration guide + +--- + +## Step 3: Implement the Fix + +### 3.1 Widget Layer Fix (if needed) + +**File:** `src/{widget-name}/index.tsx` + +**Common fixes:** + +```typescript +// Fix 1: Add null checks +const {WidgetName}Internal: React.FC = observer((props) => { + const { data } = useHook(props); + + // ✅ Add null check + if (!data) { + return
Loading...
; + } + + return ; +}); +``` + +```typescript +// Fix 2: Add error boundary +Error occurred} + onError={(error) => { + console.error('Widget Error:', error); + props.onError?.(error); // Notify parent + }} +> + <{WidgetName}Internal {...props} /> + +``` + +```typescript +// Fix 3: Fix observer HOC +// ❌ Wrong +const Widget = (props) => { ... }; + +// ✅ Correct +const Widget = observer((props) => { ... }); +``` + +### 3.2 Hook Layer Fix (if needed) + +**File:** `src/helper.ts` + +**Common fixes:** + +```typescript +// Fix 1: Add proper cleanup +useEffect(() => { + const subscription = store.cc.on('event', handler); + + // ✅ Add cleanup + return () => { + subscription.unsubscribe(); + }; +}, []); +``` + +```typescript +// Fix 2: Fix runInAction usage +// ❌ Wrong +const handler = () => { + store.setSomeValue(newValue); // Direct mutation +}; + +// ✅ Correct +const handler = () => { + runInAction(() => { + store.setSomeValue(newValue); + }); +}; +``` + +```typescript +// Fix 3: Fix dependency array +// ❌ Wrong - missing dependency +useCallback(() => { + doSomething(props.value); +}, []); // Missing props.value + +// ✅ Correct +useCallback(() => { + doSomething(props.value); +}, [props.value]); +``` + +```typescript +// Fix 4: Add error handling +const fetchData = useCallback(async () => { + try { + const result = await store.cc.someMethod(); + setData(result); + } catch (error) { + setError(error as Error); + props.onError?.(error as Error); // Notify parent + } +}, [props]); +``` + +### 3.3 Component Layer Fix (if needed) + +**File:** cc-components component + +**Common fixes:** + +```typescript +// Fix 1: Fix prop destructuring +// ❌ Wrong - missing default +const Component: React.FC = ({ items }) => { + return items.map(...); // Crashes if undefined +}; + +// ✅ Correct +const Component: React.FC = ({ items = [] }) => { + return items.map(...); +}; +``` + +```typescript +// Fix 2: Fix event handler +// ❌ Wrong - inline function creates new reference + + + )} + + )} + + ); +}; +``` + +--- + +## Step 4: Update Integration + +### 4.1 Update cc-widgets (if needed) + +**Only if adding new Web Component props** + +**File:** `packages/contact-center/cc-widgets/src/wc.ts` + +```typescript +const Web{WidgetName} = r2wc({WidgetName}, { + props: { + // Existing + existingProp: 'string', + onExisting: 'function', + // NEW: Add new props + newFeatureEnabled: 'boolean', + newFeatureConfig: 'json', + onNewFeature: 'function', + }, +}); +``` + +--- + +### 4.2 Update React Sample App + +**File:** `widgets-samples/cc/samples-cc-react-app/src/App.tsx` + +```typescript +// Add new callback handler +const onNewFeature = (data) => { + console.log('{WidgetName} new feature:', data); +}; + +// Update widget usage +{selectedWidgets.{widgetName} && ( +
+
+
+ {Widget Display Name} + + {/* NEW: Add feature toggle (optional) */} + + + <{WidgetName} + // Existing props + existingProp="value" + onExisting={onExisting} + + // NEW: Feature props + newFeatureEnabled={featureEnabled} + newFeatureConfig={{ option1: 'value', option2: 10 }} + onNewFeature={onNewFeature} + /> +
+
+
+)} +``` + +--- + +### 4.3 Update Web Component Sample App + +**File:** `widgets-samples/cc/samples-cc-wc-app/app.js` + +```javascript +// NEW: Set feature properties +cc{WidgetName}.newFeatureEnabled = true; +cc{WidgetName}.newFeatureConfig = { option1: 'value', option2: 10 }; + +// NEW: Add feature event listener +cc{WidgetName}.addEventListener('newFeature', (event) => { + console.log('{WidgetName} new feature:', event.detail); +}); +``` + +--- + +## Step 5: Update Tests + +### 5.1 Add Feature Tests + +**File:** `tests/{widget-name}/index.tsx` + +```typescript +describe('{WidgetName} - New Feature', () => { + it('renders without feature when disabled', () => { + render( + <{WidgetName} + existingProp="test" + newFeatureEnabled={false} + /> + ); + + expect(screen.queryByText('Feature')).not.toBeInTheDocument(); + }); + + it('renders with feature when enabled', () => { + render( + <{WidgetName} + existingProp="test" + newFeatureEnabled={true} + newFeatureConfig={{ option1: 'test', option2: 10 }} + /> + ); + + expect(screen.getByText('Feature')).toBeInTheDocument(); + }); + + it('calls onNewFeature callback', async () => { + const mockCallback = jest.fn(); + + render( + <{WidgetName} + existingProp="test" + newFeatureEnabled={true} + onNewFeature={mockCallback} + /> + ); + + fireEvent.click(screen.getByRole('button', { name: /use feature/i })); + + await waitFor(() => { + expect(mockCallback).toHaveBeenCalledWith({ + result: expect.any(String), + timestamp: expect.any(Number), + }); + }); + }); + + it('maintains backward compatibility', () => { + // Test widget works without new props + render(<{WidgetName} existingProp="test" />); + + expect(screen.getByText('Existing')).toBeInTheDocument(); + }); +}); +``` + +### 5.2 Update Hook Tests + +**File:** `tests/helper.ts` + +```typescript +describe('use{WidgetName} - New Feature', () => { + it('initializes feature when enabled', async () => { + mockCC.newFeatureMethod.mockResolvedValue({ data: 'test' }); + + const { result } = renderHook(() => + use{WidgetName}({ + existingProp: 'test', + newFeatureEnabled: true, + newFeatureConfig: { option1: 'test', option2: 10 }, + }) + ); + + await act(async () => { + // Wait for initialization + }); + + expect(mockCC.newFeatureMethod).toHaveBeenCalled(); + expect(result.current.featureData).toBeDefined(); + }); + + it('does not initialize feature when disabled', () => { + const { result } = renderHook(() => + use{WidgetName}({ + existingProp: 'test', + newFeatureEnabled: false, + }) + ); + + expect(mockCC.newFeatureMethod).not.toHaveBeenCalled(); + expect(result.current.featureData).toBeNull(); + }); + + it('calls feature handler correctly', async () => { + const mockCallback = jest.fn(); + + const { result } = renderHook(() => + use{WidgetName}({ + existingProp: 'test', + newFeatureEnabled: true, + onNewFeature: mockCallback, + }) + ); + + await act(async () => { + result.current.handleNewFeature('param'); + }); + + expect(mockCallback).toHaveBeenCalled(); + }); +}); +``` + +--- + +## Step 6: Update Documentation + +### 6.1 Update AGENTS.md + +**File:** `ai-docs/AGENTS.md` + +**Add to Examples section:** + +```markdown +#### {N}. Using New Feature + +{Description of the new feature} + +```typescript +import { {WidgetName} } from '@webex/cc-widgets'; + +function App() { + const handleNewFeature = (data) => { + console.log('Feature triggered:', data); + }; + + return ( + <{WidgetName} + existingProp="value" + // NEW: Enable and configure feature + newFeatureEnabled={true} + newFeatureConfig={{ + option1: 'value', + option2: 10 + }} + onNewFeature={handleNewFeature} + /> + ); +} +``` + +**Key Points:** +- Feature is optional (backward compatible) +- Configure via newFeatureConfig prop +- Subscribe to onNewFeature for events +``` + +**Update Props API table:** + +```markdown +| Prop | Type | Required | Default | Description | +|------|------|----------|---------|-------------| +| `existingProp` | `string` | Yes | - | Existing description | +| `newFeatureEnabled` | `boolean` | No | `false` | Enables the new feature | +| `newFeatureConfig` | `NewFeatureConfig` | No | `undefined` | Configuration for new feature | +| `onNewFeature` | `(data: FeatureData) => void` | No | - | Callback when feature is triggered | +``` + +--- + +### 6.2 Update ARCHITECTURE.md + +**File:** `ai-docs/ARCHITECTURE.md` + +**Update Component Table:** + +Add new props/callbacks to table + +**Add Sequence Diagram:** + +```markdown +### New Feature Flow + +```mermaid +sequenceDiagram + participant User + participant Widget as {WidgetName} + participant Hook as use{WidgetName} + participant SDK as Contact Center SDK + + User->>Widget: Enable feature + Widget->>Hook: Initialize feature + activate Hook + + Hook->>SDK: newFeatureMethod() + SDK-->>Hook: Feature data + + Hook->>Hook: Set feature state + Hook-->>Widget: Feature ready + deactivate Hook + + User->>Widget: Trigger feature + Widget->>Hook: handleNewFeature() + activate Hook + + Hook->>SDK: Feature action + SDK-->>Hook: Result + + Hook->>Widget: onNewFeature callback + deactivate Hook + + Widget-->>User: UI updated +``` +``` + +--- + +## Step 7: Validation + +### 7.1 Code Quality Checks + +- [ ] Follows TypeScript patterns +- [ ] Follows React patterns +- [ ] Follows MobX patterns +- [ ] No layer violations +- [ ] Error handling in place +- [ ] Proper cleanup + +### 7.2 Backward Compatibility + +- [ ] Widget works without new props +- [ ] Existing functionality unchanged +- [ ] No breaking changes +- [ ] Default values provided +- [ ] Optional props used + +### 7.3 Testing Checks + +- [ ] Feature tests added +- [ ] Backward compatibility tested +- [ ] All tests pass +- [ ] Linting passes +- [ ] Build succeeds +- [ ] E2E tests updated (if needed) + +### 7.4 Integration Checks + +- [ ] Works in React sample +- [ ] Works in WC sample +- [ ] Feature toggle works +- [ ] Callbacks fire correctly +- [ ] No console errors + +### 7.5 Documentation Checks + +- [ ] AGENTS.md examples added +- [ ] Props table updated +- [ ] ARCHITECTURE.md updated +- [ ] Sequence diagram added +- [ ] CHANGELOG updated + +--- + +## Related Templates + +- **[bug-fix.md](./bug-fix.md)** - Fix bugs in existing widgets +- **[../documentation/create-agent-md.md](../documentation/create-agent-md.md)** - Documentation template + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/00-master.md b/ai-docs/templates/new-widget/00-master.md new file mode 100644 index 000000000..2b025549f --- /dev/null +++ b/ai-docs/templates/new-widget/00-master.md @@ -0,0 +1,74 @@ +# New Widget Generation - Master Template + +## Purpose + +Orchestrator template for creating contact center widgets following the architecture pattern: **Widget → Hook → Component → Store → SDK** + +## Workflow + +1. **Gather Requirements** → [01-pre-questions.md](./01-pre-questions.md) +2. **Generate Code** → [02-code-generation.md](./02-code-generation.md) +3. **Generate Components** (if needed) → [03-component-generation.md](./03-component-generation.md) +4. **Integration** → [04-integration.md](./04-integration.md) +5. **Generate Tests** → [05-test-generation.md](./05-test-generation.md) +6. **Validation** → [06-validation.md](./06-validation.md) + +## Module Selection + +**Display-Only Widget:** +- Modules: 01, 02, 04, 05, 06 +- Skip: 03 (use existing components) + +**Interactive Widget:** +- Modules: 01, 02, 04, 05, 06 +- Skip: 03 (unless new components needed) + +**Complex Widget (Store + SDK):** +- Modules: 01, 02, 03 (if new components), 04, 05, 06 + +## Step Details + +### Step 1: Requirements ([01-pre-questions.md](./01-pre-questions.md)) +Gather widget name, design input, and 4 essential technical inputs: high-level user flow, detailed technical sequences, data structure mappings, and required API details. + +### Step 2: Code Generation ([02-code-generation.md](./02-code-generation.md)) +Generate widget component, custom hook, type definitions, package configuration, and config files. + +### Step 3: Component Generation ([03-component-generation.md](./03-component-generation.md)) +**Conditional:** Create presentational components in cc-components if new components are needed. + +### Step 4: Integration ([04-integration.md](./04-integration.md)) +Integrate widget into cc-widgets (React + Web Component exports) and sample apps (React + WC). + +### Step 5: Test Generation ([05-test-generation.md](./05-test-generation.md)) +Generate widget unit tests, hook unit tests, and optional E2E tests. + +### Step 6: Validation ([06-validation.md](./06-validation.md)) +Verify code quality, tests, documentation, integration, and manual testing. + +## Documentation + +Generate documentation using reusable templates: +- **AGENTS.md:** [../documentation/create-agent-md.md](../documentation/create-agent-md.md) +- **ARCHITECTURE.md:** [../documentation/create-architecture-md.md](../documentation/create-architecture-md.md) + +## Pattern References + +- [TypeScript Patterns](../../patterns/typescript-patterns.md) +- [React Patterns](../../patterns/react-patterns.md) +- [MobX Patterns](../../patterns/mobx-patterns.md) +- [Web Component Patterns](../../patterns/web-component-patterns.md) +- [Testing Patterns](../../patterns/testing-patterns.md) + +## Execution Guidelines + +1. Start with [01-pre-questions.md](./01-pre-questions.md) to gather requirements +2. Read modules sequentially based on requirements +3. Skip 03-component-generation.md if using existing components +4. Generate code as you progress through modules +5. Complete validation checklist at the end + +--- + +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/01-pre-questions.md b/ai-docs/templates/new-widget/01-pre-questions.md new file mode 100644 index 000000000..b9f0065d2 --- /dev/null +++ b/ai-docs/templates/new-widget/01-pre-questions.md @@ -0,0 +1,273 @@ +# Pre-Generation Questions + +## Overview + +This module collects the essential information needed to generate a widget. The user will provide ONLY the 4 required technical inputs. + +**Purpose:** Gather minimal, focused requirements for widget generation + +**Read this:** Before generating any code + +--- + +## Widget Identification + +### 1. Basic Information + +**Widget name (kebab-case):** +``` +Example: agent-directory, team-performance, activity-feed +Your answer: _______________ +``` + +--- + +## ⚠️ MANDATORY: Design Input + +### 2. Design Specifications (REQUIRED) + +**User MUST provide ONE of the following:** + +**[ ] Figma link** +**[ ] Screenshot(s)** +**[ ] Design specification document** +**[ ] Reference existing widget** + +### ⚠️ If NO design input provided: + +**STOP and ask the user:** + +``` +⚠️ Design Input Required + +Please provide ONE of: +1. Figma link or file +2. Screenshot(s) of desired UI +3. Design specification document +4. Reference to existing widget to clone visually + +This ensures the generated widget matches your design system. +``` + +**DO NOT proceed without design input.** + +--- + +## ⚠️ MANDATORY: Technical Requirements (4 Items ONLY) + +### 3. High-Level User Flow + +**User must provide a simple flowchart showing:** +- Main user journey through the widget +- Key user actions +- Decision points +- End states + +**Format:** Mermaid flowchart or textual description + +**Example:** +```mermaid +flowchart TD + A[User Opens Widget] --> B[Click Load Button] + B --> C[Fetch Data from SDK] + C --> D{Success?} + D -->|Yes| E[Display Records] + D -->|No| F[Show Error] + E --> G[User Clicks Item] + G --> H[Perform Action] +``` + +**Your flow:** +``` +[Paste Mermaid diagram or describe the flow] +``` + +--- + +### 4. Detailed Technical Sequences + +**User must provide Mermaid sequence diagrams for EACH major scenario.** + +**Required for each scenario:** +- Complete flow from User → Widget → Hook → Store → SDK +- Exact SDK API paths (e.g., `store.cc.someService.someMethod()`) +- All parameters with types +- Response structure +- Data transformation steps +- State updates +- Error handling + +**Scenario Template:** +```mermaid +sequenceDiagram + participant User + participant Widget + participant Hook + participant Store + participant SDK + + User->>Widget: [Action] + Widget->>Hook: [Method(params)] + Hook->>Hook: setState(loading: true) + Hook->>Store: store.cc.[exact.path] + Store->>SDK: [method(param1, param2)] + + Note over SDK: What SDK does + + SDK-->>Store: [Response structure] + Store-->>Hook: [Data] + Hook->>Hook: Transform data + Hook->>Hook: setState(data, loading: false) + Hook-->>Widget: Re-render + Widget->>Widget: Display updated UI +``` + +**Your scenarios:** + +**Scenario 1: [Name]** +``` +[Paste complete Mermaid sequence diagram] +``` + +**Scenario 2: [Name]** +``` +[Paste complete Mermaid sequence diagram] +``` + +**Scenario 3: [Name]** (if applicable) +``` +[Paste complete Mermaid sequence diagram] +``` + +--- + +### 5. Data Structure Mappings + +**User must provide explicit field-by-field mappings from SDK response to widget state.** + +**Format:** + +**Source (SDK Response):** +```typescript +// From: store.cc.[exact.path.to.method()] +// Returns: +{ + data: { + items: Array<{ + field1: string; + field2: number; + nested: { + subField1: string; + subField2?: string; + }; + }> + } +} +``` + +**Target (Widget State):** +```typescript +// Internal widget type: +interface WidgetRecord { + id: string; // maps to: item.field1 + value: number; // maps to: item.field2 + name: string; // maps to: item.nested.subField1 || item.nested.subField2 || 'Default' + timestamp: number; // maps to: new Date(item.dateField).getTime() +} +``` + +**Transformation Logic:** +```typescript +// Exact transformation code: +const transform = (sdkResponse) => { + return sdkResponse.data.items.map(item => ({ + id: item.field1, + value: item.field2, + name: item.nested.subField1 || item.nested.subField2 || 'Default', + timestamp: new Date(item.dateField).getTime() + })); +}; +``` + +**Your mappings:** +``` +[Provide Source, Target, and Transformation Logic] +``` + +--- + +### 6. Required API Details + +**User must document EVERY SDK API call that will be used.** + +**For each API:** + +**API #1:** +``` +Path: store.cc.[exact.nested.path.to.method] +Method: methodName(param1, param2, ...) +Parameters: + - param1: [type] - [description] - [example value] + - param2: [type] - [description] - [example value] +Returns: [exact return type] +Response Structure: + { + field1: type, + field2: type, + nested: { + ... + } + } +Errors: [possible error cases] +``` + +**API #2:** (if applicable) +``` +Path: store.cc.[exact.nested.path.to.method] +Method: methodName(param1) +Parameters: + - param1: [type] - [description] - [example value] +Returns: [exact return type] +Response Structure: + { + ... + } +Errors: [possible error cases] +``` + +**Your API details:** +``` +[Document all APIs] +``` + +--- + +## Summary Checklist + +Before proceeding to code generation, verify user has provided: + +- [ ] Widget name (kebab-case) +- [ ] Design input (Figma, screenshots, spec, or reference) +- [ ] **High-Level User Flow** (flowchart or description) +- [ ] **Detailed Technical Sequences** (Mermaid diagrams for all scenarios) +- [ ] **Data Structure Mappings** (SDK → Widget with transformations) +- [ ] **Required API Details** (exact paths, params, returns, errors) + +**If ANY item missing, STOP and ask the user to provide it.** + +--- + +## Next Steps + +Once all 6 items are provided: +1. Proceed to 02-code-generation.md +2. Generate widget code following the provided sequences +3. Implement exact data transformations from mappings +4. Use exact SDK paths from API details +5. Generate documentation +6. Validate against provided sequences + +--- + +_Template Version: 2.0.0_ +_Last Updated: 2025-11-27_ diff --git a/ai-docs/templates/new-widget/02-code-generation.md b/ai-docs/templates/new-widget/02-code-generation.md new file mode 100644 index 000000000..f019e023d --- /dev/null +++ b/ai-docs/templates/new-widget/02-code-generation.md @@ -0,0 +1,806 @@ +# Code Generation Module + +## Overview + +This module provides templates and patterns for generating widget code following the architecture: **Widget → Hook → Component → Store → SDK** + +**Purpose:** Generate complete widget code with proper layer separation + +**Prerequisites:** Completed 01-pre-questions.md + +--- + +## ⚠️ Import Pattern Rules (PREVENT CIRCULAR DEPENDENCIES) + +**Before writing ANY import statements, review these rules.** + +### Widget File Imports - ONLY These Patterns + +```typescript +// ✅ CORRECT - External dependencies +import React, { useState, useCallback } from 'react'; +import { observer } from 'mobx-react-lite'; +import { ErrorBoundary } from 'react-error-boundary'; + +// ✅ CORRECT - Internal widget files +import { useWidgetName } from '../helper'; +import type { WidgetNameProps } from './widget-name.types'; + +// ✅ CORRECT - cc-components (presentational layer) +import { WidgetNameComponent } from '@webex/cc-components'; + +// ❌ NEVER - cc-widgets aggregator +// import { AnotherWidget } from '@webex/cc-widgets'; // CIRCULAR DEPENDENCY! +``` + +### Hook File Imports + +```typescript +// ✅ CORRECT - Store access +import store from '@webex/cc-store'; +import { runInAction } from 'mobx'; + +// ✅ CORRECT - SDK via store +store.cc.methodName() // Accessed through store instance + +// ❌ NEVER - Direct SDK import +// import webex from '@webex/contact-center'; // WRONG PATTERN! +``` + +### Validation Before Committing Code + +**Run this checklist:** + +- [ ] No `import ... from '@webex/cc-widgets'` in widget code +- [ ] No `import ... from '@webex/cc-*-widget'` in cc-components +- [ ] All SDK calls via `store.cc.methodName()` +- [ ] All imports follow: Widget → cc-components → store → SDK +- [ ] No circular dependencies between packages + +**If ANY check fails, refactor imports before proceeding.** + +--- + +## ⚠️ Validate Sequence Diagrams Before Coding + +**Before writing ANY code, validate your implementation plan against approved sequence diagrams.** + +### Step 1: Load Approved Diagrams + +From 01-pre-questions.md, load: +- Primary data load/fetch sequence diagram +- User interaction sequence diagrams +- Error handling flow diagram +- Data transformation documentation +- SDK API documentation + +### Step 2: Verify SDK API Calls + +**For EACH SDK call in the sequence diagrams:** + +1. **Find exact API path in SDK knowledge base:** + ```typescript + // Open: ai-docs/contact-centre-sdk-apis/contact-center.json + // Search for method name + // Verify path exists and is correct + ``` + +2. **Match method signatures:** + ```typescript + // Diagram says: store.cc.someService.someMethod(param1, param2) + + // Verify in SDK JSON: + // - Method exists at this path + // - Parameters are correct (param1: type1, param2: type2) + // - Return type matches expected response + ``` + +3. **Document response structure:** + ```typescript + // From SDK docs and sequence diagram: + // Response: {statusCode: 200, data: {userSessions: UserSession[]}} + // Extract: response.data.userSessions + ``` + +### Step 3: Map Data Transformations + +**For EACH data transformation in sequence diagrams:** + +1. **Define source type (SDK response):** + ```typescript + // From sequence diagram: + type UserSession = { + sessionId: string; + startTime: string; // ISO date + endTime: string; // ISO date + durationSeconds: number; + other: { + name?: string; + phoneNumber?: string; + }; + }; + ``` + +2. **Define target type (widget state):** + ```typescript + // From sequence diagram: + type CallRecord = { + id: string; + name: string; + phone: string; + timestamp: number; + }; + ``` + +3. **Write transformation function:** + ```typescript + // Follow sequence diagram field mappings: + const transform = (session: UserSession): CallRecord => ({ + id: session.sessionId, + name: session.other?.name || 'Unknown', + phone: session.other?.phoneNumber || '', + timestamp: new Date(session.startTime).getTime(), + }); + ``` + +### Step 4: Verify State Flow + +**For EACH state update in sequence diagrams:** + +1. **Identify state variable:** + ```typescript + // Diagram shows: setIsLoading(true) + const [isLoading, setIsLoading] = useState(false); + ``` + +2. **Match update timing:** + ```typescript + // Sequence diagram order: + // 1. setIsLoading(true) + // 2. setError(null) + // 3. Call SDK + // 4. Transform data + // 5. setData(records) + // 6. setIsLoading(false) + ``` + +3. **Verify error handling:** + ```typescript + // Diagram shows error path: + try { + setIsLoading(true); + setError(null); + const response = await sdk.method(); + setData(transform(response)); + } catch (err) { + setError(err); // As per diagram + } finally { + setIsLoading(false); // Always runs + } + ``` + +### Step 5: Validation Checklist + +**Before writing hook/widget code, confirm:** + +- [ ] All SDK calls match exact paths from sequence diagrams +- [ ] All parameters match diagram specifications +- [ ] All response structures verified in SDK JSON +- [ ] All data transformations documented with field mappings +- [ ] All state updates follow diagram sequence +- [ ] Error handling paths match diagrams +- [ ] Logging calls placed as per diagrams +- [ ] Callback invocations match diagram timing + +**If ANY item unchecked, return to sequence diagrams and clarify.** + +--- + +## Key Implementation Guidelines + +**Follow these generic best practices when implementing widgets:** + +### SDK Integration +1. **Always validate SDK object existence before calling methods** + - Check if nested objects exist (e.g., nested SDK services and clients) + - Throw descriptive errors if missing + - Don't assume SDK objects are available + +2. **Use exact SDK paths from sequence diagrams** + - Copy paths exactly as documented + - Don't modify or simplify SDK access patterns + - Follow tested patterns from reference examples + +3. **Let SDK handle validation** + - Don't add manual agent state checks + - Don't duplicate SDK permission logic + - Trust SDK to manage state transitions + +### Data Handling +4. **Handle data variations with fallback chains** + - Use `||` operator for string fallbacks: `field1 || field2 || 'Default'` + - Use `??` operator for numeric fallbacks: `value1 ?? value2 ?? 0` + - Handle optional fields with `?.` operator + - Provide sensible defaults for missing data + +5. **Transform data as documented in mappings** + - Follow exact field mappings from sequence diagrams + - Apply type conversions (ISO strings → timestamps, etc.) + - Maintain transformation logic consistency + +### Patterns +6. **Follow existing widget patterns** + - Reference similar widgets for behavior (e.g., OutdialCall for outdial) + - Match error handling patterns + - Use same logging patterns + - Copy proven state management approaches + +7. **Expected behaviors are not bugs** + - IncomingTask shows agent ANI, not destination (by design) + - SDK manages complex state transitions (trust it) + - Some UI behaviors match backend logic (document, don't fix) + +--- + +## Directory Structure + +First, create the widget directory structure: + +```bash +packages/contact-center/{widget-name}/ +├── src/ +│ ├── {widget-name}/ +│ │ ├── index.tsx # Main widget component +│ │ └── {widget-name}.types.ts # Type definitions +│ ├── helper.ts # Custom hook (business logic) +│ ├── index.ts # Package exports with metrics +│ └── wc.ts # Web Component export +├── ai-docs/ +│ ├── AGENTS.md # Usage documentation (use template) +│ └── ARCHITECTURE.md # Technical documentation (use template) +├── tests/ +│ ├── helper.ts # Hook tests +│ └── {widget-name}/ +│ └── index.tsx # Widget tests +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── webpack.config.js +├── babel.config.js +└── eslint.config.mjs +``` + +--- + +## Step 1: Type Definitions + +**File:** `src/{widget-name}/{widget-name}.types.ts` + +```typescript +/** + * Props for {WidgetName} widget + */ +export interface {WidgetName}Props { + // ======================================== + // REQUIRED PROPS + // ======================================== + + /** + * Required prop description + * @example "example-value" + */ + requiredProp: string; + + // ======================================== + // OPTIONAL PROPS + // ======================================== + + /** + * Optional prop description + * @default defaultValue + */ + optionalProp?: number; + + /** + * Custom styles to apply + */ + className?: string; + + /** + * Custom inline styles + */ + customStyles?: React.CSSProperties; + + // ======================================== + // CALLBACKS + // ======================================== + + /** + * Called when primary action occurs + * @param data - Event data + */ + onSomeEvent?: (data: SomeData) => void; + + /** + * Called when error occurs + * @param error - Error object + */ + onError?: (error: Error) => void; +} + +// ======================================== +// SUPPORTING TYPES +// ======================================== + +/** + * Data structure for event + */ +export interface SomeData { + id: string; + value: string; + timestamp: number; + metadata?: Record; +} + +/** + * Add other interfaces as needed + */ +``` + +**Pattern Notes:** +- Document ALL props with JSDoc comments +- Group props logically (required, optional, callbacks) +- Use descriptive names +- Add @example tags for complex props +- Export all types that consumers need + +--- + +## Step 2: Custom Hook (Business Logic) + +**File:** `src/helper.ts` + +```typescript +import { useEffect, useState, useCallback } from 'react'; +import { runInAction } from 'mobx'; +import store from '@webex/cc-store'; +import type { {WidgetName}Props, SomeData } from './{widget-name}/{widget-name}.types'; + +/** + * Custom hook for {WidgetName} business logic + * Handles store integration, SDK calls, and state management + */ +export function use{WidgetName}(props: {WidgetName}Props) { + // ======================================== + // LOCAL STATE + // ======================================== + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [data, setData] = useState(null); + + // ======================================== + // STORE OBSERVABLES (READ) + // ======================================== + + // Read observable values from store + const storeValue = store.someObservable; + const anotherValue = store.anotherObservable; + + // ======================================== + // INITIALIZATION + // ======================================== + + useEffect(() => { + const initialize = async () => { + try { + setIsLoading(true); + setError(null); + + // Fetch initial data from SDK (if needed) + // const result = await store.cc.someMethod(params); + // setData(result); + + } catch (err) { + const error = err as Error; + setError(error); + props.onError?.(error); + } finally { + setIsLoading(false); + } + }; + + initialize(); + + // Cleanup + return () => { + // Unsubscribe from events + // Clear timers + // Cancel pending requests + }; + }, []); // Add dependencies as needed + + // ======================================== + // EVENT HANDLERS + // ======================================== + + /** + * Handles primary action + */ + const handleAction = useCallback(async (param: string) => { + try { + // Call SDK method + // const result = await store.cc.someAction(param); + + // Update store (if needed) + runInAction(() => { + // store.setSomeValue(newValue); + }); + + // Call callback + props.onSomeEvent?.({ + id: 'id', + value: param, + timestamp: Date.now(), + }); + + } catch (err) { + const error = err as Error; + setError(error); + props.onError?.(error); + } + }, [props]); + + /** + * Handles secondary action + */ + const handleSecondaryAction = useCallback(() => { + // Implementation + }, []); + + // ======================================== + // RETURN API + // ======================================== + + return { + // State + data, + isLoading, + error, + storeValue, + + // Handlers + handleAction, + handleSecondaryAction, + }; +} +``` + +**Pattern Notes:** +- Use `useCallback` for handlers to prevent re-renders +- Use `runInAction` for store mutations +- Handle errors and call `onError` callback +- Clean up subscriptions in useEffect return +- Document all returned values + +--- + +## Step 3: Widget Component + +**File:** `src/{widget-name}/index.tsx` + +```typescript +import React from 'react'; +import { observer } from 'mobx-react-lite'; +import { ErrorBoundary } from 'react-error-boundary'; +import { use{WidgetName} } from '../helper'; +import { {WidgetName}Component } from '@webex/cc-components'; +import type { {WidgetName}Props } from './{widget-name}.types'; + +/** + * Internal widget component (with observer HOC) + * This is the smart/container component + */ +const {WidgetName}Internal: React.FC<{WidgetName}Props> = observer((props) => { + const { + className = '', + customStyles, + ...restProps + } = props; + + // Use custom hook for business logic + const { + data, + isLoading, + error, + storeValue, + handleAction, + handleSecondaryAction, + } = use{WidgetName}(props); + + // Handle error state + if (error) { + return ( +
+
+ Error: {error.message} +
+
+ ); + } + + // Handle loading state + if (isLoading) { + return ( +
+
Loading...
+
+ ); + } + + // Render presentational component + return ( + <{WidgetName}Component + className={className} + customStyles={customStyles} + data={data} + storeValue={storeValue} + onAction={handleAction} + onSecondaryAction={handleSecondaryAction} + {...restProps} + /> + ); +}); + +// Display name for debugging +{WidgetName}Internal.displayName = '{WidgetName}Internal'; + +/** + * {WidgetName} widget with error boundary + * This is the public export + */ +const {WidgetName}: React.FC<{WidgetName}Props> = (props) => ( + +
+ Something went wrong. Please try again. +
+ + } + onError={(error, errorInfo) => { + console.error('{WidgetName} Error:', error, errorInfo); + props.onError?.(error); + }} + > + <{WidgetName}Internal {...props} /> +
+); + +// Display name for debugging +{WidgetName}.displayName = '{WidgetName}'; + +export { {WidgetName} }; +export type { {WidgetName}Props }; +``` + +**Pattern Notes:** +- MUST use `observer` HOC for MobX reactivity +- MUST wrap with `ErrorBoundary` +- Handle loading and error states +- Pass only processed data to presentational component +- Set display names for debugging + +--- + +## Step 4: Package Exports + +**File:** `src/index.ts` + +```typescript +import { {WidgetName} } from './{widget-name}'; +import { withMetrics } from '@webex/cc-ui-logging'; + +/** + * {WidgetName} wrapped with metrics tracking + * Automatically logs: + * - WIDGET_MOUNTED + * - WIDGET_UNMOUNTED + * - Errors (if onError not handled) + */ +const {WidgetName}WithMetrics = withMetrics({WidgetName}, '{WidgetName}'); + +// Export with metrics wrapper +export { {WidgetName}WithMetrics as {WidgetName} }; + +// Export types +export type { {WidgetName}Props } from './{widget-name}/{widget-name}.types'; +``` + +**Pattern Notes:** +- ALWAYS wrap with `withMetrics` HOC +- Export wrapped version as default +- Export types separately + +--- + +## Step 5: Web Component Export + +**File:** `src/wc.ts` + +```typescript +import { {WidgetName} } from './{widget-name}'; + +/** + * Export unwrapped component for r2wc conversion + * The metrics wrapper interferes with r2wc, so we export clean component + */ +export { {WidgetName} }; +``` + +**Pattern Notes:** +- Export WITHOUT metrics wrapper +- r2wc wrapping happens in cc-widgets +- Keep minimal - just re-export + +--- + +## Step 6: Package Configuration + +### package.json + +**File:** `package.json` + +```json +{ + "name": "@webex/cc-{widget-name}", + "description": "Webex Contact Center Widgets: {Widget Display Name}", + "license": "Cisco's General Terms (https://www.cisco.com/site/us/en/about/legal/contract-experience/index.html)", + "version": "1.28.0-ccwidgets.124", + "main": "dist/index.js", + "types": "dist/types/index.d.ts", + "publishConfig": { + "access": "public" + }, + "files": [ + "dist/", + "package.json" + ], + "scripts": { + "clean": "rm -rf dist && rm -rf node_modules", + "clean:dist": "rm -rf dist", + "build": "yarn run -T tsc", + "build:src": "yarn run clean:dist && webpack", + "build:watch": "webpack --watch", + "test:unit": "tsc --project tsconfig.test.json && jest --coverage", + "test:styles": "eslint" + }, + "dependencies": { + "@webex/cc-components": "workspace:*", + "@webex/cc-store": "workspace:*", + "mobx-react-lite": "^4.1.0", + "react-error-boundary": "^6.0.0" + }, + "devDependencies": { + "@babel/core": "7.25.2", + "@babel/preset-env": "7.25.4", + "@babel/preset-react": "7.24.7", + "@babel/preset-typescript": "7.25.9", + "@eslint/js": "^9.20.0", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.6.2", + "@testing-library/react": "16.0.1", + "@types/jest": "29.5.14", + "@types/node": "^22.13.13", + "@webex/test-fixtures": "workspace:*", + "babel-jest": "29.7.0", + "babel-loader": "9.2.1", + "eslint": "^9.20.1", + "jest": "29.7.0", + "jest-environment-jsdom": "29.7.0", + "typescript": "5.6.3", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + }, + "peerDependencies": { + "@momentum-ui/react-collaboration": ">=26.201.9", + "react": ">=18.3.1", + "react-dom": ">=18.3.1" + } +} +``` + +--- + +### Configuration Files + +**Copy these from station-login without modification:** + +1. **tsconfig.json** - TypeScript configuration +2. **tsconfig.test.json** - TypeScript test configuration +3. **webpack.config.js** - Webpack bundling +4. **babel.config.js** - Babel transpilation +5. **eslint.config.mjs** - ESLint rules + +**Command to copy:** +```bash +# From project root +cp packages/contact-center/station-login/tsconfig.json packages/contact-center/{widget-name}/ +cp packages/contact-center/station-login/tsconfig.test.json packages/contact-center/{widget-name}/ +cp packages/contact-center/station-login/webpack.config.js packages/contact-center/{widget-name}/ +cp packages/contact-center/station-login/babel.config.js packages/contact-center/{widget-name}/ +cp packages/contact-center/station-login/eslint.config.mjs packages/contact-center/{widget-name}/ +``` + +--- + +## Code Quality Checklist + +Before proceeding to next module, verify: + +### Architecture +- [ ] Widget → Hook → Component layer separation maintained +- [ ] No layer violations (Widget doesn't call SDK directly) +- [ ] Component doesn't access store directly + +### MobX Integration +- [ ] Widget wrapped with `observer` HOC +- [ ] Store mutations use `runInAction` +- [ ] No reactions created in render + +### Error Handling +- [ ] ErrorBoundary wraps widget +- [ ] Try-catch in async operations +- [ ] onError callback called on errors +- [ ] Error states displayed to user + +### TypeScript +- [ ] All types exported +- [ ] Props interface documented with JSDoc +- [ ] No `any` types (use proper types) +- [ ] Optional props marked with `?` + +### React Best Practices +- [ ] useCallback for handlers +- [ ] useEffect cleanup functions +- [ ] Display names set +- [ ] Loading states handled +- [ ] Error states handled + +### Metrics +- [ ] Widget wrapped with `withMetrics` in index.ts +- [ ] NOT wrapped in wc.ts (for r2wc compatibility) + +--- + +## Next Steps + +**After code generation complete:** + +1. **If new components needed:** + - Go to: 03-component-generation.md + +2. **If using existing components:** + - Skip to: 04-integration.md + +3. **Always required:** + - 04-integration.md + - 05-test-generation.md + - ../documentation/create-agent-md.md + - ../documentation/create-architecture-md.md + - 06-validation.md + +--- + +## Reference Widgets + +**For patterns and examples, see:** +- Simple: `packages/contact-center/station-login/` +- Medium: `packages/contact-center/user-state/` +- Complex: `packages/contact-center/task/` + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/03-component-generation.md b/ai-docs/templates/new-widget/03-component-generation.md new file mode 100644 index 000000000..38454e456 --- /dev/null +++ b/ai-docs/templates/new-widget/03-component-generation.md @@ -0,0 +1,552 @@ +# Component Generation Module + +## Overview + +This module guides you through creating new presentational components in the cc-components library. + +**⚠️ Only use this module if:** Pre-questions indicated new components are needed + +**Purpose:** Generate pure presentational components + +**Location:** `packages/contact-center/cc-components/` + +--- + +## When to Create New Components + +**Create new component when:** +- Widget needs UI that doesn't exist in cc-components +- Reusable UI pattern that other widgets might use +- Complex UI that should be tested in isolation + +**Use existing component when:** +- Similar component already exists +- Component can be customized via props +- Minor styling changes only + +--- + +## Component Directory Structure + +Create in `packages/contact-center/cc-components/src/components/{ComponentName}/`: + +``` +{ComponentName}/ +├── {component-name}.tsx # Component implementation +├── {component-name}.types.ts # TypeScript interfaces +├── {component-name}.scss # Styles (optional) +├── {component-name}.utils.ts # Helper functions (optional) +└── constants.ts # Constants (optional) +``` + +--- + +## Step 1: Component Types + +**File:** `src/components/{ComponentName}/{component-name}.types.ts` + +```typescript +import { CSSProperties } from 'react'; + +/** + * Props for {ComponentName} component + */ +export interface {ComponentName}Props { + // ======================================== + // DATA PROPS + // ======================================== + + /** + * Main data to display + */ + data: SomeDataType; + + /** + * Additional data (optional) + */ + metadata?: MetadataType; + + // ======================================== + // BEHAVIOR PROPS + // ======================================== + + /** + * Callback when user interacts + * @param data - Interaction data + */ + onAction?: (data: ActionData) => void; + + /** + * Callback on error + * @param error - Error object + */ + onError?: (error: Error) => void; + + // ======================================== + // STYLING PROPS + // ======================================== + + /** + * Custom CSS class + */ + className?: string; + + /** + * Custom inline styles + */ + customStyles?: CSSProperties; + + /** + * Disable the component + * @default false + */ + disabled?: boolean; + + /** + * Loading state + * @default false + */ + isLoading?: boolean; +} + +/** + * Supporting types + */ +export interface SomeDataType { + id: string; + name: string; + value: string; +} + +export interface ActionData { + id: string; + action: string; + timestamp: number; +} +``` + +--- + +## Step 2: Component Implementation + +**File:** `src/components/{ComponentName}/{component-name}.tsx` + +```typescript +import React from 'react'; +import { Button, Icon, Input, Text } from '@momentum-design/components/dist/react'; +import type { {ComponentName}Props } from './{component-name}.types'; +import './{component-name}.scss'; + +/** + * {ComponentName} - Pure presentational component + * + * @param props - Component props + * @returns Rendered component + */ +export const {ComponentName}: React.FC<{ComponentName}Props> = (props) => { + const { + data, + metadata, + onAction, + onError, + className = '', + customStyles, + disabled = false, + isLoading = false, + } = props; + + // ======================================== + // EVENT HANDLERS (LOCAL ONLY) + // ======================================== + + const handleClick = () => { + if (disabled) return; + + try { + onAction?.({ + id: data.id, + action: 'clicked', + timestamp: Date.now(), + }); + } catch (error) { + onError?.(error as Error); + } + }; + + // ======================================== + // RENDER + // ======================================== + + // Handle loading state + if (isLoading) { + return ( +
+
Loading...
+
+ ); + } + + // Handle no data + if (!data) { + return ( +
+
No data available
+
+ ); + } + + // Main render + return ( +
+
+ {data.name} +
+ +
+ {data.value} + + {metadata && ( +
+ {metadata.info} +
+ )} +
+ +
+ +
+
+ ); +}; + +// Display name +{ComponentName}.displayName = '{ComponentName}'; +``` + +**Pattern Notes:** +- **Pure presentational** - No store access +- **All data via props** - No side effects +- **Use Momentum UI** - Button, Icon, Input, Text, etc. +- **Handle states** - Loading, error, empty, disabled +- **BEM naming** - Use consistent class names +- **Accessibility** - Add aria-labels + +--- + +## Step 3: Component Styles (Optional) + +**File:** `src/components/{ComponentName}/{component-name}.scss` + +```scss +// BEM naming convention +.{component-name} { + padding: 1rem; + border: 1px solid var(--mds-color-theme-outline-secondary-normal); + border-radius: 0.5rem; + + // Modifiers + &--loading { + opacity: 0.6; + } + + &--disabled { + opacity: 0.5; + pointer-events: none; + } + + &--error { + border-color: var(--mds-color-theme-outline-error-normal); + } + + &--empty { + text-align: center; + padding: 2rem; + } + + // Elements + &__header { + margin-bottom: 0.75rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--mds-color-theme-outline-secondary-normal); + } + + &__content { + margin-bottom: 1rem; + } + + &__metadata { + margin-top: 0.5rem; + color: var(--mds-color-theme-text-secondary-normal); + } + + &__actions { + display: flex; + gap: 0.5rem; + justify-content: flex-end; + } + + &__loader, + &__error-message, + &__empty { + padding: 1rem; + text-align: center; + } + + &__error-message { + color: var(--mds-color-theme-text-error-normal); + } +} +``` + +**Pattern Notes:** +- Use BEM naming (block__element--modifier) +- Use Momentum UI CSS variables +- Support light and dark themes +- Keep selectors simple +- Avoid deep nesting + +--- + +## Step 4: Component Utils (Optional) + +**File:** `src/components/{ComponentName}/{component-name}.utils.ts` + +```typescript +import type { SomeDataType } from './{component-name}.types'; + +/** + * Helper function to transform data + * @param input - Raw data + * @returns Transformed data + */ +export const transformData = (input: any): SomeDataType => { + return { + id: input.id, + name: input.name || 'Unknown', + value: input.value || '', + }; +}; + +/** + * Validate data + * @param data - Data to validate + * @returns True if valid + */ +export const validateData = (data: SomeDataType): boolean => { + return Boolean(data.id && data.name); +}; + +/** + * Format value for display + * @param value - Raw value + * @returns Formatted value + */ +export const formatValue = (value: string): string => { + return value.trim().toUpperCase(); +}; +``` + +--- + +## Step 5: Export from cc-components + +**File:** `packages/contact-center/cc-components/src/index.ts` + +Add exports for new component: + +```typescript +// ... existing exports ... + +// NEW: Add component export +export { {ComponentName} } from './components/{ComponentName}/{component-name}'; +export type { {ComponentName}Props } from './components/{ComponentName}/{component-name}.types'; +``` + +--- + +## Step 6: Component Tests + +**File:** `packages/contact-center/cc-components/tests/components/{ComponentName}/{component-name}.tsx` + +```typescript +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { {ComponentName} } from '../../../src/components/{ComponentName}/{component-name}'; +import type { {ComponentName}Props } from '../../../src/components/{ComponentName}/{component-name}.types'; + +describe('{ComponentName}', () => { + const mockData = { + id: 'test-id', + name: 'Test Name', + value: 'Test Value', + }; + + const defaultProps: {ComponentName}Props = { + data: mockData, + onAction: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders without crashing', () => { + render(<{ComponentName} {...defaultProps} />); + expect(screen.getByText('Test Name')).toBeInTheDocument(); + }); + + it('displays data correctly', () => { + render(<{ComponentName} {...defaultProps} />); + + expect(screen.getByText('Test Name')).toBeInTheDocument(); + expect(screen.getByText('Test Value')).toBeInTheDocument(); + }); + + it('calls onAction when button clicked', () => { + const mockAction = jest.fn(); + + render( + <{ComponentName} + {...defaultProps} + onAction={mockAction} + /> + ); + + fireEvent.click(screen.getByRole('button', { name: /action/i })); + + expect(mockAction).toHaveBeenCalledWith({ + id: 'test-id', + action: 'clicked', + timestamp: expect.any(Number), + }); + }); + + it('handles disabled state', () => { + render( + <{ComponentName} + {...defaultProps} + disabled={true} + /> + ); + + const button = screen.getByRole('button'); + expect(button).toBeDisabled(); + }); + + it('handles loading state', () => { + render( + <{ComponentName} + {...defaultProps} + isLoading={true} + /> + ); + + expect(screen.getByText('Loading...')).toBeInTheDocument(); + }); + + it('handles no data state', () => { + render( + <{ComponentName} + {...defaultProps} + data={null} + /> + ); + + expect(screen.getByText('No data available')).toBeInTheDocument(); + }); + + it('applies custom className', () => { + const { container } = render( + <{ComponentName} + {...defaultProps} + className="custom-class" + /> + ); + + expect(container.firstChild).toHaveClass('custom-class'); + }); + + it('matches snapshot', () => { + const { container } = render(<{ComponentName} {...defaultProps} />); + expect(container.firstChild).toMatchSnapshot(); + }); +}); +``` + +--- + +## Component Checklist + +Before proceeding, verify: + +### Component Quality +- [ ] Pure presentational (no store access) +- [ ] All data via props +- [ ] Uses Momentum UI components +- [ ] Handles loading state +- [ ] Handles error state +- [ ] Handles empty state +- [ ] Handles disabled state +- [ ] Accessible (aria-labels, keyboard navigation) + +### Types & Documentation +- [ ] Types exported from component +- [ ] JSDoc comments on props +- [ ] Examples in comments +- [ ] Display name set + +### Styling +- [ ] SCSS file created (if needed) +- [ ] BEM naming used +- [ ] Momentum UI variables used +- [ ] Theme support (light/dark) +- [ ] Responsive design + +### Testing +- [ ] Test file created +- [ ] Tests all states (loading, error, empty, disabled) +- [ ] Tests callbacks +- [ ] Tests props +- [ ] Snapshot test included +- [ ] All tests pass + +### Exports +- [ ] Component exported from cc-components/src/index.ts +- [ ] Types exported from cc-components/src/index.ts + +--- + +## Next Steps + +**After component generation:** +1. Go to: 04-integration.md +2. Then: 05-test-generation.md (widget tests) +3. Then: Documentation templates +4. Finally: 06-validation.md + +--- + +## Reference Components + +**For patterns and examples:** +- `packages/contact-center/cc-components/src/components/StationLogin/` +- `packages/contact-center/cc-components/src/components/UserState/` +- `packages/contact-center/cc-components/src/components/task/CallControl/` + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/04-integration.md b/ai-docs/templates/new-widget/04-integration.md new file mode 100644 index 000000000..e53582e25 --- /dev/null +++ b/ai-docs/templates/new-widget/04-integration.md @@ -0,0 +1,668 @@ +# Integration Module + +## Overview + +This module guides you through integrating the new widget into: +1. cc-widgets package (React + Web Component exports) +2. React sample application +3. Web Component sample application + +**Purpose:** Make widget available for consumption + +**Prerequisites:** Widget code generated + +--- + +## Step 1: Update cc-widgets React Export + +**File:** `packages/contact-center/cc-widgets/src/index.ts` + +### 1.1 Add Import + +```typescript +// ... existing imports ... + +// NEW: Add widget import +import { {WidgetName} } from '@webex/cc-{widget-name}'; +``` + +### 1.2 Add to Exports + +```typescript +// ... existing exports ... + +// NEW: Export widget +export { {WidgetName} }; +``` + +**Complete example:** +```typescript +// Station Login +import { StationLogin } from '@webex/cc-station-login'; + +// User State +import { UserState } from '@webex/cc-user-state'; + +// NEW: {Widget Display Name} +import { {WidgetName} } from '@webex/cc-{widget-name}'; + +// Exports +export { + StationLogin, + UserState, + {WidgetName}, // NEW +}; +``` + +--- + +## Step 2: Update cc-widgets Web Component Export + +**File:** `packages/contact-center/cc-widgets/src/wc.ts` + +### 2.1 Add Import + +```typescript +// ... existing imports ... + +// NEW: Import from wc.ts (NOT index.ts - to avoid metrics wrapper) +import { {WidgetName} } from '@webex/cc-{widget-name}/dist/wc'; +``` + +### 2.2 Create r2wc Wrapper + +Map React props to Web Component attributes: + +```typescript +// NEW: Create Web Component wrapper +const Web{WidgetName} = r2wc({WidgetName}, { + props: { + // String props + stringProp: 'string', + + // Number props + numberProp: 'number', + + // Boolean props + booleanProp: 'boolean', + + // Object/Array props (use 'json') + configObject: 'json', + arrayProp: 'json', + + // Function props (callbacks) + onSomeEvent: 'function', + onError: 'function', + }, +}); +``` + +**Prop type mapping:** + +| React Prop Type | r2wc Type | Example | +|-----------------|-----------|---------| +| `string` | `'string'` | `name: 'string'` | +| `number` | `'number'` | `count: 'number'` | +| `boolean` | `'boolean'` | `enabled: 'boolean'` | +| `object` / `interface` | `'json'` | `config: 'json'` | +| `array` | `'json'` | `items: 'json'` | +| `function` / `callback` | `'function'` | `onClick: 'function'` | + +### 2.3 Register Custom Element + +```typescript +const components = [ + // ... existing components ... + + // NEW: Add widget to components array + { name: 'widget-cc-{widget-name}', component: Web{WidgetName} }, +]; +``` + +**Complete example:** +```typescript +import r2wc from '@r2wc/react-to-web-component'; + +// Import widgets (from wc.ts exports) +import { StationLogin } from '@webex/cc-station-login/dist/wc'; +import { UserState } from '@webex/cc-user-state/dist/wc'; +// NEW +import { {WidgetName} } from '@webex/cc-{widget-name}/dist/wc'; + +// Create Web Components +const WebStationLogin = r2wc(StationLogin, { + props: { + desktop: 'json', + dialNumber: 'string', + teamId: 'string', + onStationLogin: 'function', + onError: 'function', + }, +}); + +const WebUserState = r2wc(UserState, { + props: { + idleCodes: 'json', + stateInfo: 'json', + onUserStateChange: 'function', + onError: 'function', + }, +}); + +// NEW: {Widget Display Name} +const Web{WidgetName} = r2wc({WidgetName}, { + props: { + requiredProp: 'string', + optionalConfig: 'json', + onSomeEvent: 'function', + onError: 'function', + }, +}); + +// Register all components +const components = [ + { name: 'widget-cc-station-login', component: WebStationLogin }, + { name: 'widget-cc-user-state', component: WebUserState }, + { name: 'widget-cc-{widget-name}', component: Web{WidgetName} }, // NEW +]; + +// Register with window.customElements +components.forEach(({ name, component }) => { + if (!window.customElements.get(name)) { + window.customElements.define(name, component); + } +}); +``` + +--- + +## Step 3: Update React Sample App + +**File:** `widgets-samples/cc/samples-cc-react-app/src/App.tsx` + +### 3.1 Add Import + +```typescript +import { + StationLogin, + UserState, + {WidgetName}, // NEW +} from '@webex/cc-widgets'; +``` + +### 3.2 Add Widget Toggle State + +In the `defaultWidgets` object: + +```typescript +const defaultWidgets = { + stationLogin: false, + userState: false, + {widgetName}: false, // NEW: camelCase name +}; +``` + +### 3.3 Add Callback Handlers + +```typescript +// NEW: {Widget Display Name} callbacks +const onSomeEvent = (data) => { + console.log('{WidgetName} event:', data); + // Handle event +}; + +const on{WidgetName}Error = (error) => { + console.error('{WidgetName} error:', error); + // Handle error +}; +``` + +### 3.4 Add Widget Checkbox + +In the widget selector section: + +```jsx +
+

Select Widgets to Display

+ + {/* Existing widgets */} + + + {/* NEW: Add checkbox */} + +
+``` + +### 3.5 Add Widget Rendering + +```jsx +{/* NEW: {Widget Display Name} Widget */} +{selectedWidgets.{widgetName} && ( +
+
+
+ {Widget Display Name} + + <{WidgetName} + requiredProp="value" + optionalConfig={{ key: 'value' }} + onSomeEvent={onSomeEvent} + onError={on{WidgetName}Error} + /> +
+
+
+)} +``` + +**Complete example section:** +```jsx +return ( +
+ {/* Widget Selector */} +
+ + + +
+ + {/* Widgets */} + {selectedWidgets.stationLogin && ( +
+ +
+ )} + + {selectedWidgets.{widgetName} && ( +
+
+
+ {Widget Display Name} + + <{WidgetName} + requiredProp="test-value" + optionalConfig={{ option1: 'value', option2: 10 }} + onSomeEvent={onSomeEvent} + onError={on{WidgetName}Error} + /> +
+
+
+ )} +
+); +``` + +--- + +## Step 4: Update Web Component Sample App + +**File:** `widgets-samples/cc/samples-cc-wc-app/app.js` + +### 4.1 Create Element Reference + +```javascript +// Widget references +let stationLoginWidget = null; +let userStateWidget = null; +let {widgetName}Widget = null; // NEW: camelCase name +``` + +### 4.2 Add Widget Toggle Checkbox + +In the HTML section: + +```javascript +const widgetSelectors = ` +
+

Select Widgets to Display

+ + + + + +
+`; +``` + +### 4.3 Add Widget Creation Function + +```javascript +/** + * Create {Widget Display Name} widget + */ +function create{WidgetName}Widget() { + // Create element + {widgetName}Widget = document.createElement('widget-cc-{widget-name}'); + + // Set properties + {widgetName}Widget.requiredProp = 'test-value'; + {widgetName}Widget.optionalConfig = { + option1: 'value', + option2: 10 + }; + + // Add event listeners + {widgetName}Widget.addEventListener('someEvent', (event) => { + console.log('{WidgetName} event:', event.detail); + // Handle event + }); + + {widgetName}Widget.addEventListener('error', (event) => { + console.error('{WidgetName} error:', event.detail); + // Handle error + }); + + // Append to container + const container = document.getElementById('widgets-container'); + const wrapper = document.createElement('div'); + wrapper.className = 'widget-box'; + wrapper.id = '{widget-name}-container'; + + const legend = document.createElement('h3'); + legend.textContent = '{Widget Display Name}'; + wrapper.appendChild(legend); + + wrapper.appendChild({widgetName}Widget); + container.appendChild(wrapper); + + console.log('{WidgetName} widget created'); +} + +/** + * Remove {Widget Display Name} widget + */ +function remove{WidgetName}Widget() { + if ({widgetName}Widget) { + const container = document.getElementById('{widget-name}-container'); + if (container) { + container.remove(); + } + {widgetName}Widget = null; + console.log('{WidgetName} widget removed'); + } +} +``` + +### 4.4 Add Toggle Handler + +```javascript +// Add event listener for toggle +document.getElementById('toggle-{widget-name}')?.addEventListener('change', (event) => { + if (event.target.checked) { + create{WidgetName}Widget(); + } else { + remove{WidgetName}Widget(); + } +}); +``` + +**Complete example:** +```javascript +// Widget references +let stationLoginWidget = null; +let {widgetName}Widget = null; + +// Initialize function +function initializeApp() { + // Setup widget toggles + document.getElementById('toggle-station-login')?.addEventListener('change', (e) => { + if (e.target.checked) { + createStationLoginWidget(); + } else { + removeStationLoginWidget(); + } + }); + + // NEW: {Widget Display Name} toggle + document.getElementById('toggle-{widget-name}')?.addEventListener('change', (e) => { + if (e.target.checked) { + create{WidgetName}Widget(); + } else { + remove{WidgetName}Widget(); + } + }); +} + +// NEW: Widget functions +function create{WidgetName}Widget() { + {widgetName}Widget = document.createElement('widget-cc-{widget-name}'); + + // Set props + {widgetName}Widget.requiredProp = 'test-value'; + {widgetName}Widget.optionalConfig = { option1: 'value', option2: 10 }; + + // Add listeners + {widgetName}Widget.addEventListener('someEvent', (e) => { + console.log('{WidgetName} event:', e.detail); + }); + + {widgetName}Widget.addEventListener('error', (e) => { + console.error('{WidgetName} error:', e.detail); + }); + + // Append to DOM + const container = document.getElementById('widgets-container'); + const wrapper = document.createElement('div'); + wrapper.className = 'widget-box'; + wrapper.id = '{widget-name}-container'; + + const legend = document.createElement('h3'); + legend.textContent = '{Widget Display Name}'; + wrapper.appendChild(legend); + wrapper.appendChild({widgetName}Widget); + + container.appendChild(wrapper); +} + +function remove{WidgetName}Widget() { + const container = document.getElementById('{widget-name}-container'); + if (container) container.remove(); + {widgetName}Widget = null; +} + +// Initialize on load +document.addEventListener('DOMContentLoaded', initializeApp); +``` + +--- + +## Integration Checklist + +Before proceeding, verify: + +### cc-widgets Package +- [ ] Widget imported in src/index.ts +- [ ] Widget exported in src/index.ts +- [ ] Widget imported in src/wc.ts (from dist/wc, not dist/index) +- [ ] r2wc wrapper created with correct prop mappings +- [ ] Custom element registered in components array +- [ ] Element name follows pattern: `widget-cc-{widget-name}` + +### React Sample App +- [ ] Widget imported from @webex/cc-widgets +- [ ] Widget toggle state added to defaultWidgets +- [ ] Callback handlers defined +- [ ] Checkbox added to widget selector +- [ ] Widget rendering added with conditional +- [ ] All required props passed +- [ ] Callbacks wired up correctly + +### Web Component Sample App +- [ ] Widget reference variable created +- [ ] Checkbox added to HTML +- [ ] Create widget function implemented +- [ ] Remove widget function implemented +- [ ] Toggle event listener added +- [ ] Properties set correctly +- [ ] Event listeners attached +- [ ] Widget appended to DOM + +### Testing +- [ ] Widget appears in both sample apps +- [ ] Toggling works (show/hide) +- [ ] Props passed correctly +- [ ] Callbacks fire correctly +- [ ] No console errors +- [ ] No console warnings + +--- + +## Build & Test + +### Build cc-widgets + +```bash +# From project root +cd packages/contact-center/cc-widgets +yarn build +``` + +### Build Widget + +```bash +# From project root +cd packages/contact-center/{widget-name} +yarn build +``` + +### Run React Sample + +```bash +# From project root +cd widgets-samples/cc/samples-cc-react-app +yarn start +``` + +**Test:** +1. Check widget checkbox +2. Verify widget renders +3. Interact with widget +4. Verify callbacks fire +5. Uncheck widget +6. Verify widget removed + +### Run Web Component Sample + +```bash +# From project root +cd widgets-samples/cc/samples-cc-wc-app +# Open index.html in browser +``` + +**Test:** +1. Check widget checkbox +2. Verify widget renders +3. Interact with widget +4. Check console for events +5. Uncheck widget +6. Verify widget removed + +--- + +## Common Issues + +### Issue 1: Widget Not Appearing + +**Symptoms:** +- Checkbox checked but widget doesn't render +- No errors in console + +**Possible Causes:** +- Widget not exported from cc-widgets +- Import path incorrect +- Build not run + +**Solutions:** +1. Verify exports in cc-widgets/src/index.ts +2. Rebuild cc-widgets: `yarn build` +3. Check import path in sample app +4. Check browser console for errors + +--- + +### Issue 2: Props Not Passing + +**Symptoms:** +- Widget renders but props undefined +- Default values used instead of passed values + +**Possible Causes:** +- r2wc mapping incorrect +- Prop type mismatch +- Prop name typo + +**Solutions:** +1. Check r2wc props mapping in wc.ts +2. Verify prop types (string, number, json, function) +3. Check prop names match exactly +4. For objects/arrays, use 'json' type + +--- + +### Issue 3: Callbacks Not Firing + +**Symptoms:** +- Interactions don't trigger callbacks +- Console shows no events + +**Possible Causes:** +- Callback not passed +- r2wc function mapping missing +- Event listener not attached (WC) + +**Solutions:** +1. Verify callback passed in React sample +2. Check r2wc maps callback as 'function' +3. Add addEventListener in WC sample +4. Check event name matches exactly + +--- + +## Next Steps + +**After integration complete:** +1. Go to: 05-test-generation.md +2. Then: ../documentation/create-agent-md.md +3. Then: ../documentation/create-architecture-md.md +4. Finally: 06-validation.md + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/05-test-generation.md b/ai-docs/templates/new-widget/05-test-generation.md new file mode 100644 index 000000000..5bd95234b --- /dev/null +++ b/ai-docs/templates/new-widget/05-test-generation.md @@ -0,0 +1,674 @@ +# Test Generation Module + +## Overview + +This module guides you through generating comprehensive tests for the widget: unit tests, hook tests, and E2E tests. + +**Purpose:** Ensure widget quality and prevent regressions + +**Prerequisites:** Widget and integration code complete + +--- + +## Test Structure + +``` +packages/contact-center/{widget-name}/tests/ +├── helper.ts # Hook unit tests +└── {widget-name}/ + └── index.tsx # Widget unit tests + +playwright/tests/ +└── {widget-name}-test.spec.ts # E2E tests (optional) +``` + +--- + +## Step 1: Widget Unit Tests + +**File:** `tests/{widget-name}/index.tsx` + +```typescript +import React from 'react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { {WidgetName} } from '../../src/{widget-name}'; +import type { {WidgetName}Props } from '../../src/{widget-name}/{widget-name}.types'; +import { mockCC, mockProfile } from '@webex/test-fixtures'; + +// Mock store +jest.mock('@webex/cc-store', () => ({ + __esModule: true, + default: { + getInstance: jest.fn(() => ({ + cc: mockCC, + profile: mockProfile, + // Add other store observables as needed + someObservable: 'test-value', + })), + someObservable: 'test-value', + }, +})); + +describe('{WidgetName}', () => { + let defaultProps: {WidgetName}Props; + + beforeEach(() => { + // Reset mocks before each test + jest.clearAllMocks(); + + // Setup default props + defaultProps = { + requiredProp: 'test-value', + onSomeEvent: jest.fn(), + onError: jest.fn(), + }; + + // Setup mock responses + mockCC.someMethod = jest.fn().mockResolvedValue({ success: true }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + // ======================================== + // RENDERING TESTS + // ======================================== + + describe('Rendering', () => { + it('renders without crashing', () => { + render(<{WidgetName} {...defaultProps} />); + expect(screen.getByText(/expected text/i)).toBeInTheDocument(); + }); + + it('renders with required props only', () => { + render( + <{WidgetName} + requiredProp={defaultProps.requiredProp} + /> + ); + + expect(screen.getByText(/expected text/i)).toBeInTheDocument(); + }); + + it('renders with all props', () => { + render( + <{WidgetName} + {...defaultProps} + optionalProp={10} + className="custom-class" + /> + ); + + expect(screen.getByText(/expected text/i)).toBeInTheDocument(); + }); + }); + + // ======================================== + // PROP TESTS + // ======================================== + + describe('Props', () => { + it('uses required prop correctly', () => { + render(<{WidgetName} {...defaultProps} requiredProp="custom-value" />); + + // Verify prop is used + expect(screen.getByText(/custom-value/i)).toBeInTheDocument(); + }); + + it('uses optional prop when provided', () => { + render(<{WidgetName} {...defaultProps} optionalProp={20} />); + + // Verify optional prop is used + expect(screen.getByText(/20/i)).toBeInTheDocument(); + }); + + it('uses default value when optional prop not provided', () => { + render(<{WidgetName} {...defaultProps} />); + + // Verify default value is used + expect(screen.getByText(/default/i)).toBeInTheDocument(); + }); + + it('applies custom className', () => { + const { container } = render( + <{WidgetName} {...defaultProps} className="custom-class" /> + ); + + expect(container.firstChild).toHaveClass('custom-class'); + }); + }); + + // ======================================== + // CALLBACK TESTS + // ======================================== + + describe('Callbacks', () => { + it('calls onSomeEvent when action occurs', async () => { + render(<{WidgetName} {...defaultProps} />); + + // Trigger action + fireEvent.click(screen.getByRole('button', { name: /action/i })); + + // Wait for callback + await waitFor(() => { + expect(defaultProps.onSomeEvent).toHaveBeenCalledWith({ + id: expect.any(String), + value: expect.any(String), + timestamp: expect.any(Number), + }); + }); + }); + + it('calls onError when error occurs', async () => { + // Setup mock to throw error + mockCC.someMethod = jest.fn().mockRejectedValue(new Error('Test error')); + + render(<{WidgetName} {...defaultProps} />); + + // Wait for error + await waitFor(() => { + expect(defaultProps.onError).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'Test error', + }) + ); + }); + }); + + it('does not crash when callbacks are undefined', () => { + render( + <{WidgetName} + requiredProp={defaultProps.requiredProp} + /> + ); + + // Trigger action + fireEvent.click(screen.getByRole('button', { name: /action/i })); + + // Should not crash + expect(screen.getByRole('button')).toBeInTheDocument(); + }); + }); + + // ======================================== + // STATE TESTS + // ======================================== + + describe('State Management', () => { + it('displays loading state initially', () => { + render(<{WidgetName} {...defaultProps} />); + + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + }); + + it('displays data after loading', async () => { + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(); + expect(screen.getByText(/expected data/i)).toBeInTheDocument(); + }); + }); + + it('displays error state when error occurs', async () => { + mockCC.someMethod = jest.fn().mockRejectedValue(new Error('Test error')); + + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.getByText(/error/i)).toBeInTheDocument(); + expect(screen.getByText(/test error/i)).toBeInTheDocument(); + }); + }); + }); + + // ======================================== + // INTERACTION TESTS + // ======================================== + + describe('User Interactions', () => { + it('handles button click', async () => { + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(); + }); + + fireEvent.click(screen.getByRole('button', { name: /action/i })); + + expect(mockCC.someMethod).toHaveBeenCalled(); + }); + + it('handles input change', async () => { + render(<{WidgetName} {...defaultProps} />); + + const input = screen.getByRole('textbox'); + fireEvent.change(input, { target: { value: 'test input' } }); + + expect(input).toHaveValue('test input'); + }); + + it('handles form submission', async () => { + render(<{WidgetName} {...defaultProps} />); + + const form = screen.getByRole('form'); + fireEvent.submit(form); + + await waitFor(() => { + expect(defaultProps.onSomeEvent).toHaveBeenCalled(); + }); + }); + }); + + // ======================================== + // STORE INTEGRATION TESTS + // ======================================== + + describe('Store Integration', () => { + it('reads from store observable', () => { + render(<{WidgetName} {...defaultProps} />); + + // Verify store value is displayed + expect(screen.getByText(/test-value/i)).toBeInTheDocument(); + }); + + it('calls SDK method', async () => { + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(mockCC.someMethod).toHaveBeenCalledWith( + expect.objectContaining({ + // Expected parameters + }) + ); + }); + }); + }); + + // ======================================== + // EDGE CASES + // ======================================== + + describe('Edge Cases', () => { + it('handles empty data', async () => { + mockCC.someMethod = jest.fn().mockResolvedValue(null); + + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.getByText(/no data/i)).toBeInTheDocument(); + }); + }); + + it('handles invalid prop values', () => { + render(<{WidgetName} {...defaultProps} requiredProp="" />); + + // Should handle gracefully + expect(screen.getByText(/invalid/i)).toBeInTheDocument(); + }); + + it('handles rapid interactions', async () => { + render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(); + }); + + const button = screen.getByRole('button', { name: /action/i }); + + // Rapid clicks + fireEvent.click(button); + fireEvent.click(button); + fireEvent.click(button); + + // Should handle gracefully (debounce or disable) + await waitFor(() => { + expect(mockCC.someMethod).toHaveBeenCalledTimes(1); + }); + }); + }); + + // ======================================== + // SNAPSHOT TEST + // ======================================== + + describe('Snapshot', () => { + it('matches snapshot', async () => { + const { container } = render(<{WidgetName} {...defaultProps} />); + + await waitFor(() => { + expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(); + }); + + expect(container.firstChild).toMatchSnapshot(); + }); + }); +}); +``` + +--- + +## Step 2: Hook Unit Tests + +**File:** `tests/helper.ts` + +```typescript +import { renderHook, act, waitFor } from '@testing-library/react'; +import { use{WidgetName} } from '../src/helper'; +import type { {WidgetName}Props } from '../src/{widget-name}/{widget-name}.types'; +import { mockCC, mockProfile } from '@webex/test-fixtures'; + +// Mock store +jest.mock('@webex/cc-store', () => ({ + __esModule: true, + default: { + getInstance: jest.fn(() => ({ + cc: mockCC, + profile: mockProfile, + someObservable: 'test-value', + })), + someObservable: 'test-value', + }, +})); + +describe('use{WidgetName}', () => { + let defaultProps: {WidgetName}Props; + + beforeEach(() => { + jest.clearAllMocks(); + + defaultProps = { + requiredProp: 'test-value', + onSomeEvent: jest.fn(), + onError: jest.fn(), + }; + + mockCC.someMethod = jest.fn().mockResolvedValue({ success: true }); + }); + + // ======================================== + // INITIALIZATION TESTS + // ======================================== + + describe('Initialization', () => { + it('initializes with correct default state', () => { + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + expect(result.current.data).toBeNull(); + expect(result.current.isLoading).toBe(true); + expect(result.current.error).toBeNull(); + }); + + it('fetches initial data', async () => { + mockCC.someMethod = jest.fn().mockResolvedValue({ + id: 'test-id', + value: 'test-value', + }); + + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.data).toEqual({ + id: 'test-id', + value: 'test-value', + }); + }); + }); + + it('handles initialization error', async () => { + const error = new Error('Init failed'); + mockCC.someMethod = jest.fn().mockRejectedValue(error); + + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.error).toEqual(error); + expect(defaultProps.onError).toHaveBeenCalledWith(error); + }); + }); + }); + + // ======================================== + // HANDLER TESTS + // ======================================== + + describe('Handlers', () => { + it('handleAction calls SDK method', async () => { + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + await act(async () => { + await result.current.handleAction('test-param'); + }); + + expect(mockCC.someAction).toHaveBeenCalledWith('test-param'); + }); + + it('handleAction calls callback on success', async () => { + mockCC.someAction = jest.fn().mockResolvedValue({ data: 'result' }); + + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + await act(async () => { + await result.current.handleAction('test-param'); + }); + + expect(defaultProps.onSomeEvent).toHaveBeenCalledWith({ + id: expect.any(String), + value: 'test-param', + timestamp: expect.any(Number), + }); + }); + + it('handleAction calls onError on failure', async () => { + const error = new Error('Action failed'); + mockCC.someAction = jest.fn().mockRejectedValue(error); + + const { result } = renderHook(() => use{WidgetName}(defaultProps)); + + await act(async () => { + await result.current.handleAction('test-param'); + }); + + expect(defaultProps.onError).toHaveBeenCalledWith(error); + }); + }); + + // ======================================== + // CLEANUP TESTS + // ======================================== + + describe('Cleanup', () => { + it('cleans up subscriptions on unmount', () => { + const unsubscribeMock = jest.fn(); + mockCC.on = jest.fn().mockReturnValue({ unsubscribe: unsubscribeMock }); + + const { unmount } = renderHook(() => use{WidgetName}(defaultProps)); + + unmount(); + + expect(unsubscribeMock).toHaveBeenCalled(); + }); + + it('cancels pending requests on unmount', async () => { + const abortMock = jest.fn(); + mockCC.someMethod = jest.fn().mockImplementation(() => { + return new Promise((resolve) => { + setTimeout(resolve, 1000); + }); + }); + + const { unmount } = renderHook(() => use{WidgetName}(defaultProps)); + + unmount(); + + // Verify no state updates after unmount + await waitFor(() => { + expect(abortMock).toHaveBeenCalled(); + }, { timeout: 100 }); + }); + }); + + // ======================================== + // DEPENDENCY TESTS + // ======================================== + + describe('Dependencies', () => { + it('re-initializes when props change', async () => { + const { rerender } = renderHook( + ({ props }) => use{WidgetName}(props), + { initialProps: { props: defaultProps } } + ); + + await waitFor(() => { + expect(mockCC.someMethod).toHaveBeenCalledTimes(1); + }); + + // Change props + rerender({ props: { ...defaultProps, requiredProp: 'new-value' } }); + + await waitFor(() => { + expect(mockCC.someMethod).toHaveBeenCalledTimes(2); + }); + }); + }); +}); +``` + +--- + +## Step 3: E2E Tests (Optional) + +**File:** `playwright/tests/{widget-name}-test.spec.ts` + +```typescript +import { test, expect } from '@playwright/test'; + +test.describe('{WidgetName} Widget E2E', () => { + test.beforeEach(async ({ page }) => { + // Navigate to sample app + await page.goto('http://localhost:3000'); + + // Enable widget + await page.check('input[type="checkbox"][id="toggle-{widget-name}"]'); + + // Wait for widget to appear + await page.waitForSelector('.{widget-name}', { state: 'visible' }); + }); + + test('renders widget correctly', async ({ page }) => { + // Verify widget is visible + const widget = page.locator('.{widget-name}'); + await expect(widget).toBeVisible(); + + // Verify expected elements + await expect(page.getByText('Expected Text')).toBeVisible(); + }); + + test('handles user interaction', async ({ page }) => { + // Click button + await page.click('button:has-text("Action")'); + + // Verify result + await expect(page.getByText('Success')).toBeVisible(); + }); + + test('displays error state', async ({ page }) => { + // Trigger error condition + await page.click('button:has-text("Trigger Error")'); + + // Verify error message + await expect(page.getByText('Error:')).toBeVisible(); + }); + + test('handles toggle off', async ({ page }) => { + // Verify widget is visible + await expect(page.locator('.{widget-name}')).toBeVisible(); + + // Toggle off + await page.uncheck('input[type="checkbox"][id="toggle-{widget-name}"]'); + + // Verify widget is removed + await expect(page.locator('.{widget-name}')).not.toBeVisible(); + }); +}); +``` + +--- + +## Test Checklist + +Before proceeding, verify: + +### Widget Unit Tests +- [ ] Rendering tests (with/without props) +- [ ] Prop tests (required, optional, defaults) +- [ ] Callback tests (all callbacks) +- [ ] State tests (loading, error, data) +- [ ] Interaction tests (clicks, inputs, forms) +- [ ] Store integration tests +- [ ] Edge case tests +- [ ] Snapshot test + +### Hook Unit Tests +- [ ] Initialization tests +- [ ] Handler tests (success, error) +- [ ] Cleanup tests +- [ ] Dependency tests + +### E2E Tests (Optional) +- [ ] Widget renders in sample app +- [ ] User interactions work +- [ ] Error states handled +- [ ] Toggle on/off works + +### Test Quality +- [ ] All tests pass: `yarn test:unit` +- [ ] Coverage > 80% +- [ ] No console errors +- [ ] No flaky tests +- [ ] Clear test descriptions + +--- + +## Run Tests + +### Unit Tests + +```bash +# From widget directory +cd packages/contact-center/{widget-name} +yarn test:unit +``` + +### E2E Tests + +```bash +# From project root +yarn test:e2e +``` + +### Coverage Report + +```bash +cd packages/contact-center/{widget-name} +yarn test:unit --coverage +``` + +--- + +## Next Steps + +**After tests complete:** +1. Go to: ../documentation/create-agent-md.md +2. Then: ../documentation/create-architecture-md.md +3. Finally: 06-validation.md + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ + diff --git a/ai-docs/templates/new-widget/06-validation.md b/ai-docs/templates/new-widget/06-validation.md new file mode 100644 index 000000000..ffb0ab8d8 --- /dev/null +++ b/ai-docs/templates/new-widget/06-validation.md @@ -0,0 +1,775 @@ +# Validation Module + +## Overview + +This module provides comprehensive validation checklists to ensure the widget is production-ready before deployment. + +**Purpose:** Quality assurance and completeness verification + +**Use:** After all code, tests, and documentation are complete + +--- + +## Validation Categories + +1. **Code Quality** - Architecture, patterns, best practices +2. **Testing** - Unit, hook, E2E tests +3. **Documentation** - AGENTS.md, ARCHITECTURE.md completeness +4. **Integration** - cc-widgets, sample apps +5. **Manual Testing** - Real-world usage verification + +--- + +## 1. Code Quality Validation + +### Architecture & Layer Separation + +- [ ] **Widget → Hook → Component → Store → SDK** pattern followed +- [ ] Widget component wrapped with `observer` HOC +- [ ] Widget wrapped with `ErrorBoundary` +- [ ] Hook contains all business logic +- [ ] Component is pure presentational (if separate component) +- [ ] No layer violations (Widget doesn't call SDK directly) +- [ ] No component accessing store directly + +### MobX Integration + +- [ ] Widget uses `observer` HOC from mobx-react-lite +- [ ] Store observables accessed correctly +- [ ] Store mutations wrapped in `runInAction` +- [ ] No direct store mutations outside runInAction +- [ ] No reactions created in render + +### TypeScript + +- [ ] All types exported from types file +- [ ] Props interface fully documented with JSDoc +- [ ] No `any` types used (proper types everywhere) +- [ ] Optional props marked with `?` +- [ ] Default values documented +- [ ] Return types specified on functions +- [ ] Complex types have interfaces/types +- [ ] Exported types available to consumers + +### React Best Practices + +- [ ] Functional components used (not class components) +- [ ] Hooks used correctly (rules of hooks) +- [ ] `useCallback` for event handlers +- [ ] `useMemo` for expensive computations +- [ ] `useEffect` dependencies correct +- [ ] `useEffect` cleanup functions present +- [ ] Display names set for debugging +- [ ] Loading states handled +- [ ] Error states handled +- [ ] Empty states handled + +### Error Handling + +- [ ] ErrorBoundary wraps widget +- [ ] Try-catch in all async operations +- [ ] Errors logged to console +- [ ] `onError` callback called on errors +- [ ] User-friendly error messages displayed +- [ ] Error recovery possible +- [ ] No unhandled promise rejections + +### Code Style + +- [ ] Linting passes: `yarn test:styles` +- [ ] No console.log statements (use proper logging) +- [ ] Comments explain "why", not "what" +- [ ] Complex logic documented +- [ ] TODO comments removed +- [ ] Dead code removed +- [ ] Consistent naming conventions + +### Metrics & Logging + +- [ ] Widget wrapped with `withMetrics` HOC in index.ts +- [ ] NOT wrapped with `withMetrics` in wc.ts +- [ ] WIDGET_MOUNTED logged automatically +- [ ] WIDGET_UNMOUNTED logged automatically +- [ ] Custom metrics logged where appropriate + +--- + +## 2. Functional Validation (NEW - CRITICAL) + +### Purpose + +Verify that the widget actually WORKS as intended, not just that it compiles. Test the complete data flow from user action to UI update. + +### Sequence Diagram Validation + +**FIRST STEP: Load approved sequence diagrams from 01-pre-questions.md** + +Before running any tests, verify implementation matches approved diagrams: + +- [ ] Load all sequence diagrams from pre-questions +- [ ] Load SDK API documentation from pre-questions +- [ ] Load data transformation mappings from pre-questions + +### SDK Integration Test + +**Compare implemented code against approved sequence diagrams:** + +**For each SDK method in sequence diagrams:** + +- [ ] Method exists in [contact-centre-sdk-apis/contact-center.json](../../contact-centre-sdk-apis/contact-center.json) +- [ ] **Exact path matches sequence diagram** (e.g., `store.cc.someService.someMethod`) +- [ ] **Parameters match diagram specification** (type, order, values) +- [ ] **Return type matches SDK documentation AND diagram** +- [ ] Accessed via `store.cc.methodName()` (not direct import) +- [ ] Error handling present (try/catch) as per error flow diagram +- [ ] Success callbacks fire on success (verify timing per diagram) +- [ ] Error callbacks fire on error (verify error path per diagram) +- [ ] Response structure matches documented structure + +**Example Verification:** + +```typescript +// From sequence diagram: store.cc.someService.someMethod(param1, param2) +// ✓ Exists in SDK JSON at exact path +// ✓ Parameters: (param1: value1, param2: value2) - matches diagram +// ✓ Return type: Promise<{statusCode: number, data: {...}}> +// ✓ Error handling: try/catch present with setError() call +// ✓ Callback: props.onSuccess?.(data) called on success +// ✓ Error callback: props.onError?.(error) called on failure +// ✓ Response accessed: response.data.items (matches diagram) +``` + +**If method not found in SDK or signature mismatch → RETURN to sequence diagrams and fix** + +**Data Transformation Validation:** + +- [ ] **Every transformation matches diagram mapping** +- [ ] Source fields extracted correctly (e.g., `session.other.name`) +- [ ] Fallback values match diagram (e.g., `|| 'Unknown'`) +- [ ] Type conversions correct (e.g., ISO string → timestamp) +- [ ] Optional field handling matches diagram (`?? operator`) + +**Example:** +```typescript +// Diagram says: contactName = session.other.name || session.other.primaryDisplayString || 'Unknown' +// Code implements: +contactName: session.other?.name || session.other?.primaryDisplayString || 'Unknown' +// ✓ Matches diagram +``` + +### Event Flow Test + +**Validate implementation against sequence diagrams:** + +**For EACH sequence diagram, manually test the flow:** + +#### Testing Procedure + +1. **Load sequence diagram** from pre-questions for scenario +2. **Perform user action** shown in diagram +3. **Verify EACH step** in diagram occurs in correct order +4. **Check state updates** match diagram timing +5. **Confirm UI updates** match diagram end state + +#### Example: Button Click Flow (from sequence diagram) + +Per diagram sequence: +1. User clicks button → Event handler called? ✓ +2. Handler sets `isLoading=true` → State updated? ✓ +3. Handler sets `error=null` → State cleared? ✓ +4. Handler calls SDK method → Method invoked with correct params? ✓ +5. SDK returns response → Response structure matches diagram? ✓ +6. Handler transforms data → Transformation per diagram mappings? ✓ +7. Handler sets `data=records` → State updated with transformed data? ✓ +8. Handler sets `isLoading=false` → Loading state cleared? ✓ +9. Component re-renders → UI shows new data? ✓ + +**If ANY step fails or order wrong → Debug against sequence diagram** + +**For YOUR widget, test ALL diagram scenarios:** + +**Scenario 1:** (from sequence diagram: _______________) +``` +Diagram step → Implemented code → Verified? +─────────────────────────────────────────── +User action: _______________ → _______________ → [ ] +Handler called: _______________ → _______________ → [ ] +State update 1: _______________ → _______________ → [ ] +State update 2: _______________ → _______________ → [ ] +SDK call: _______________ → _______________ → [ ] +SDK response: _______________ → _______________ → [ ] +Data transform: _______________ → _______________ → [ ] +Final state: _______________ → _______________ → [ ] +UI renders: _______________ → _______________ → [ ] + +Overall Status: [ ] VERIFIED [ ] FAILED +``` + +**Scenario 2:** (from sequence diagram: _______________) +``` +Diagram step → Implemented code → Verified? +─────────────────────────────────────────── +User action: _______________ → _______________ → [ ] +Handler called: _______________ → _______________ → [ ] +State update 1: _______________ → _______________ → [ ] +State update 2: _______________ → _______________ → [ ] +SDK call: _______________ → _______________ → [ ] +SDK response: _______________ → _______________ → [ ] +Data transform: _______________ → _______________ → [ ] +Final state: _______________ → _______________ → [ ] +UI renders: _______________ → _______________ → [ ] + +Overall Status: [ ] VERIFIED [ ] FAILED +``` + +**Scenario 3:** (from sequence diagram: _______________) +``` +Diagram step → Implemented code → Verified? +─────────────────────────────────────────── +User action: _______________ → _______________ → [ ] +Handler called: _______________ → _______________ → [ ] +State update 1: _______________ → _______________ → [ ] +State update 2: _______________ → _______________ → [ ] +SDK call: _______________ → _______________ → [ ] +SDK response: _______________ → _______________ → [ ] +Data transform: _______________ → _______________ → [ ] +Final state: _______________ → _______________ → [ ] +UI renders: _______________ → _______________ → [ ] + +Overall Status: [ ] VERIFIED [ ] FAILED +``` + +### Data Flow Test + +**Trace data through ALL layers:** + +``` +User Action (UI) + ↓ +Widget Handler (index.tsx) + ↓ +Hook Method (helper.ts) + ↓ +Store/SDK Call + ↓ +Response/Observable Update + ↓ +Hook State Update + ↓ +Component Props + ↓ +UI Render +``` + +**Verification:** + +- [ ] User action triggers widget handler +- [ ] Widget handler calls hook method correctly +- [ ] Hook method accesses store/SDK correctly +- [ ] Response updates hook state +- [ ] Hook state passes to component props +- [ ] Component renders with updated props +- [ ] UI reflects the change + +**If any transition fails → Debug and fix** + +### Import Validation Test + +**Check for circular dependencies:** + +```bash +# In widget code, search for cc-widgets import: +grep -r "from '@webex/cc-widgets'" packages/contact-center/{widget-name}/src/ +# Expected: NO MATCHES + +# In cc-components, search for widget imports: +grep -r "from '@webex/cc-.*-widget'" packages/contact-center/cc-components/src/ +# Expected: NO MATCHES +``` + +**Validation:** + +- [ ] No matches for `@webex/cc-widgets` in widget code +- [ ] No matches for widget packages in cc-components +- [ ] All imports follow one-directional flow +- [ ] No circular dependencies detected + +**If any matches found → Refactor imports** + +### UI Visual Test + +**Compare with design input (Figma/screenshot/spec):** + +- [ ] Colors match design (or use Momentum tokens) +- [ ] Spacing matches (8px/0.5rem grid adhered) +- [ ] Layout matches (flex/grid structure correct) +- [ ] Components match design (correct Momentum components used) +- [ ] Typography matches (sizes, weights correct) +- [ ] Interactions work (hover, active, focus states) +- [ ] Theme switching works (light/dark modes) + +**Visual differences found:** + +| Element | Design | Generated | Status | Notes | +|---------|--------|-----------|--------|-------| +| _____ | _____ | _____ | [ ] Fixed | _____ | +| _____ | _____ | _____ | [ ] Fixed | _____ | +| _____ | _____ | _____ | [ ] Fixed | _____ | + +**If visual mismatch → Update styling** + +### Compiler Test + +```bash +# Build the widget +yarn build + +# Expected: NO ERRORS +``` + +**Common compiler errors and fixes:** + +| Error | Cause | Fix | +|-------|-------|-----| +| Type error | Missing/incorrect types | Add proper type definitions | +| Import error | Wrong path or missing export | Check paths and exports | +| Circular dependency | Improper imports | Refactor to follow dependency flow | +| Syntax error | Code syntax issue | Fix syntax | + +**Validation:** + +- [ ] `yarn build` completes without errors +- [ ] No TypeScript errors +- [ ] No import errors +- [ ] No syntax errors +- [ ] Bundle size reasonable + +**Fix ALL compiler errors before completing** + +### Runtime Test (Manual) + +**Run sample app and test widget:** + +```bash +# Start React sample app +yarn samples:serve-react +``` + +**Test checklist:** + +- [ ] Widget renders without errors +- [ ] All buttons work +- [ ] All inputs work +- [ ] All dropdowns/selects work +- [ ] Callbacks fire correctly +- [ ] State updates reflect in UI immediately +- [ ] Error scenarios handled gracefully +- [ ] No console errors or warnings + +**Test scenarios:** + +1. **Happy Path:** + - [ ] Primary user flow works end-to-end + - [ ] UI updates correctly + - [ ] Callbacks fire with correct data + +2. **Error Scenarios:** + - [ ] Invalid input shows error message + - [ ] API errors handled gracefully + - [ ] Error callbacks fire + - [ ] User can recover from errors + +3. **Edge Cases:** + - [ ] Empty state handled + - [ ] Loading state shown + - [ ] No data scenario handled + - [ ] Rapid clicks handled + +**If runtime errors → Debug and fix** + +--- + +## 3. Testing Validation + +### Unit Tests - Widget + +- [ ] Widget renders without crashing +- [ ] Renders with required props only +- [ ] Renders with all props +- [ ] All required props tested +- [ ] All optional props tested +- [ ] Default values tested +- [ ] Custom className applied +- [ ] Custom styles applied +- [ ] All callbacks tested (called correctly) +- [ ] Callbacks work when undefined +- [ ] Loading state tested +- [ ] Error state tested +- [ ] Empty/no-data state tested +- [ ] User interactions tested (clicks, inputs, etc.) +- [ ] Store integration tested +- [ ] SDK calls tested +- [ ] Edge cases tested +- [ ] Snapshot test included + +### Unit Tests - Hook + +- [ ] Hook initializes correctly +- [ ] Initial data fetch tested +- [ ] Initialization errors handled +- [ ] All handlers tested (success cases) +- [ ] All handlers tested (error cases) +- [ ] Callbacks called correctly +- [ ] Cleanup functions tested +- [ ] Subscriptions unsubscribed +- [ ] Dependency changes tested +- [ ] Re-initialization tested + +### Test Quality + +- [ ] All tests pass: `yarn test:unit` +- [ ] Test coverage > 80% +- [ ] No skipped tests (.skip removed) +- [ ] No focused tests (.only removed) +- [ ] Tests are deterministic (not flaky) +- [ ] Tests are independent (can run in any order) +- [ ] Mock setup/teardown correct +- [ ] No console warnings during tests +- [ ] No console errors during tests + +### E2E Tests (Optional) + +- [ ] Widget renders in sample app +- [ ] User interactions work end-to-end +- [ ] Error scenarios tested +- [ ] Toggle on/off works +- [ ] Multi-widget scenarios tested + +--- + +## 3. Documentation Validation + +### AGENTS.md Completeness + +- [ ] Overview section complete +- [ ] Package name stated +- [ ] Version references package.json +- [ ] Purpose clearly explained +- [ ] 3-5 key capabilities listed +- [ ] 4-6 usage examples provided +- [ ] Basic usage example (React) +- [ ] Web Component usage example +- [ ] Common use case examples +- [ ] Error handling example +- [ ] Dependencies documented +- [ ] Dependencies reference package.json (no hardcoded versions) +- [ ] Props API table complete +- [ ] All props documented +- [ ] Required/optional marked +- [ ] Default values shown +- [ ] Installation instructions included +- [ ] Link to ARCHITECTURE.md at END (token optimization) + +### ARCHITECTURE.md Completeness + +- [ ] Component overview complete +- [ ] Component table has all components +- [ ] File structure documented +- [ ] Layer communication diagram (Mermaid) +- [ ] 3-5 sequence diagrams (Mermaid) +- [ ] All diagrams use Mermaid (not PlantUML) +- [ ] Diagrams render correctly +- [ ] Hook/business logic explained +- [ ] Store integration explained +- [ ] SDK integration explained +- [ ] 5-8 troubleshooting issues documented +- [ ] Each issue has symptoms, causes, solutions +- [ ] Code examples in troubleshooting +- [ ] Related documentation linked + +### Documentation Quality + +- [ ] Markdown renders correctly +- [ ] Code blocks have language tags +- [ ] Tables format properly +- [ ] No broken links +- [ ] Consistent heading levels +- [ ] No typos +- [ ] Examples are realistic +- [ ] Examples work (tested) + +--- + +## 4. Integration Validation + +### cc-widgets Package + +- [ ] Widget imported in `cc-widgets/src/index.ts` +- [ ] Widget exported in `cc-widgets/src/index.ts` +- [ ] Widget imported in `cc-widgets/src/wc.ts` (from dist/wc) +- [ ] r2wc wrapper created +- [ ] All props mapped correctly in r2wc +- [ ] String props use 'string' +- [ ] Number props use 'number' +- [ ] Boolean props use 'boolean' +- [ ] Object/Array props use 'json' +- [ ] Function props use 'function' +- [ ] Custom element registered +- [ ] Element name: `widget-cc-{widget-name}` +- [ ] cc-widgets builds successfully: `yarn build` + +### React Sample App + +- [ ] Widget imported from @webex/cc-widgets +- [ ] Widget toggle state added +- [ ] Checkbox added to widget selector +- [ ] Callback handlers defined +- [ ] Widget rendering section added +- [ ] All required props passed +- [ ] Callbacks wired correctly +- [ ] Sample app runs: `yarn start` +- [ ] Widget appears when toggled on +- [ ] Widget disappears when toggled off +- [ ] Widget functions correctly + +### Web Component Sample App + +- [ ] Widget reference variable created +- [ ] Checkbox added to HTML +- [ ] Create widget function implemented +- [ ] Remove widget function implemented +- [ ] Toggle event listener attached +- [ ] Properties set correctly +- [ ] Event listeners attached correctly +- [ ] Widget appended to DOM correctly +- [ ] Sample app loads in browser +- [ ] Widget appears when toggled on +- [ ] Widget disappears when toggled off +- [ ] Widget functions correctly +- [ ] Events fire correctly (check console) + +--- + +## 5. Manual Testing Validation + +### Functional Testing + +- [ ] Widget renders without errors +- [ ] All features work as expected +- [ ] Props passed correctly +- [ ] Callbacks fire correctly +- [ ] User interactions work +- [ ] Loading states display correctly +- [ ] Error states display correctly +- [ ] Empty states display correctly +- [ ] Data updates in real-time (if applicable) +- [ ] Store integration works +- [ ] SDK calls work + +### Visual Testing + +- [ ] Widget looks correct (matches design) +- [ ] Layout is correct +- [ ] Colors are correct +- [ ] Typography is correct +- [ ] Icons display correctly +- [ ] Spacing is correct +- [ ] Responsive (if applicable) +- [ ] Works in light theme +- [ ] Works in dark theme + +### Browser Testing + +- [ ] Chrome (latest) +- [ ] Firefox (latest) +- [ ] Safari (latest) +- [ ] Edge (latest) + +### Accessibility Testing + +- [ ] Keyboard navigation works +- [ ] Tab order is logical +- [ ] Focus visible +- [ ] Screen reader friendly +- [ ] ARIA labels present +- [ ] Color contrast sufficient +- [ ] No keyboard traps + +### Performance Testing + +- [ ] Widget renders quickly (< 1s) +- [ ] No memory leaks +- [ ] No excessive re-renders +- [ ] No console warnings +- [ ] No console errors + +### Error Scenarios + +- [ ] Invalid props handled gracefully +- [ ] Missing props handled gracefully +- [ ] SDK errors handled gracefully +- [ ] Network errors handled gracefully +- [ ] Empty data handled gracefully +- [ ] User shown appropriate error message +- [ ] Error logged to console +- [ ] `onError` callback called + +--- + +## 6. Build & Deploy Validation + +### Build Process + +- [ ] Widget builds successfully + ```bash + cd packages/contact-center/{widget-name} + yarn build + ``` +- [ ] No build errors +- [ ] No build warnings +- [ ] dist/ folder created +- [ ] Types generated (dist/types/) +- [ ] Source maps generated + +### Package Configuration + +- [ ] package.json name correct: `@webex/cc-{widget-name}` +- [ ] package.json description correct +- [ ] package.json version correct +- [ ] package.json main points to dist/index.js +- [ ] package.json types points to dist/types/index.d.ts +- [ ] Dependencies correct +- [ ] DevDependencies correct +- [ ] PeerDependencies correct + +### File Structure + +- [ ] All required files present +- [ ] No unnecessary files in dist/ +- [ ] README or link to docs present +- [ ] License file present + +--- + +## 7. Pattern Compliance + +### Check Against Pattern Docs + +- [ ] Follows [TypeScript Patterns](../../patterns/typescript-patterns.md) +- [ ] Follows [React Patterns](../../patterns/react-patterns.md) +- [ ] Follows [MobX Patterns](../../patterns/mobx-patterns.md) +- [ ] Follows [Web Component Patterns](../../patterns/web-component-patterns.md) +- [ ] Follows [Testing Patterns](../../patterns/testing-patterns.md) + +### Naming Conventions + +- [ ] Widget name is kebab-case: `agent-directory` +- [ ] Component name is PascalCase: `AgentDirectory` +- [ ] File names match conventions +- [ ] Function names are camelCase +- [ ] Constants are UPPER_SNAKE_CASE +- [ ] Types/Interfaces are PascalCase + +--- + +## 8. Final Checklist + +### Code Complete + +- [ ] All modules from 01-06 completed +- [ ] Widget code generated +- [ ] Hook code generated +- [ ] Types defined +- [ ] Component created (if needed) +- [ ] Tests written +- [ ] Documentation written + +### Quality Gates Passed + +- [ ] Linting passes +- [ ] Tests pass (100%) +- [ ] Build succeeds +- [ ] No console errors +- [ ] No console warnings + +### Integration Complete + +- [ ] cc-widgets updated +- [ ] React sample updated +- [ ] Web Component sample updated +- [ ] Both samples tested + +### Documentation Complete + +- [ ] AGENTS.md complete +- [ ] ARCHITECTURE.md complete +- [ ] All examples tested +- [ ] All diagrams render + +### Ready for Review + +- [ ] All checklists completed +- [ ] No known issues +- [ ] Ready for peer review +- [ ] Ready for QA +- [ ] Ready for production + +--- + +## Issue Tracking + +If any checklist items fail, document here: + +### Issues Found + +| Issue | Severity | Description | Solution | Status | +|-------|----------|-------------|----------|--------| +| 1. | High/Med/Low | Description | Solution | Open/Fixed | +| 2. | High/Med/Low | Description | Solution | Open/Fixed | +| 3. | High/Med/Low | Description | Solution | Open/Fixed | + +### Notes + +(Add any notes about the validation process, workarounds, or decisions made) + +--- + +## Sign-Off + +**Validation completed by:** _______________ + +**Date:** _______________ + +**Widget name:** _______________ + +**Version:** _______________ + +**Status:** ✅ READY FOR PRODUCTION / ⚠️ NEEDS WORK + +**Notes:** +``` +(Any final notes or observations) +``` + +--- + +## Next Steps After Validation + +**If all checks pass:** +1. Commit changes to version control +2. Create pull request +3. Request peer review +4. Update CHANGELOG +5. Prepare for release + +**If checks fail:** +1. Document issues in tracking table +2. Fix issues +3. Re-run validation +4. Repeat until all checks pass + +--- + +_Template Version: 1.0.0_ +_Last Updated: 2025-11-26_ +