Skip to content

Commit c37bae0

Browse files
committed
docs: add team documentation and development patterns @W-21315032
- Add docs/team/ structure for patterns, configs, runbooks - Add Web Component communication pattern documentation - Add debugging runbook for common issues - Add .claude/ folder to .gitignore for local AI-generated files This establishes team knowledge base with: - Web Components best practices (properties, events, Shadow DOM) - Common debugging scenarios and solutions - Development workflow guidelines - Testing patterns Benefits: - Onboard new contributors faster - Document tribal knowledge - Consistent patterns across components - Context preservation for AI assistants Work Item: @W-21315032
1 parent 114a9bf commit c37bae0

4 files changed

Lines changed: 511 additions & 1 deletion

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,7 @@ demo/models/flattened/*.json
7070

7171
.idea/
7272
.sfdx
73-
.codegenie
73+
.codegenie
74+
# Claude/Cursor working files
75+
.claude/
76+
.cursor/

docs/team/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# API Console Team Shared Documentation
2+
3+
This directory contains **team-shared** documentation and configurations.
4+
These files ARE committed to Git and shared with all team members and community contributors.
5+
6+
## Structure
7+
8+
- `patterns/` - Code patterns, architectural decisions (Web Components, LitElement)
9+
- `configs/` - Team configuration files (IDE settings, linters, etc.)
10+
- `runbooks/` - Operational guides (release process, debugging, common issues)
11+
12+
## Usage
13+
14+
### For AI Assistants (Claude/Cursor)
15+
When starting work on this repo, read:
16+
```
17+
Read docs/team/patterns/*.md
18+
Read docs/team/runbooks/*.md
19+
```
20+
21+
### For Team Members & Contributors
22+
1. Add new patterns when making architectural decisions
23+
2. Update runbooks when solving common issues
24+
3. Share configs that improve team productivity
25+
26+
## Difference vs `.claude/`
27+
- `.claude/` = Personal, local, NOT committed (your drafts)
28+
- `docs/team/` = Shared, committed, team knowledge base
29+
30+
## Context
31+
32+
**api-console** is an open-source project:
33+
- LitElement/Polymer Web Components
34+
- Distributed as separate npm packages
35+
- Used by MuleSoft, Salesforce, and external developers
36+
- Shadow DOM, custom events, AMF integration
37+
38+
Document patterns that help new contributors understand how to work with this codebase.
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# Pattern: Web Component Communication
2+
3+
**Date**: 2026-02-26
4+
**Author**: ACM Team
5+
**Status**: Accepted
6+
**Applies to**: All Web Components in api-console
7+
8+
---
9+
10+
## Problem
11+
12+
Web Components in api-console need to communicate with each other:
13+
- Parent → Child: Pass data down
14+
- Child → Parent: Notify of events
15+
- Sibling → Sibling: Share state
16+
17+
Without clear patterns, components become tightly coupled and hard to test.
18+
19+
---
20+
21+
## Solution
22+
23+
Use **Properties + Custom Events** pattern:
24+
25+
```
26+
┌─────────────────────────────────────┐
27+
│ Parent Component │
28+
│ - Sets properties on children │
29+
│ - Listens to custom events │
30+
└──────────────┬──────────────────────┘
31+
32+
│ properties (down)
33+
34+
┌─────────────────────────────────────┐
35+
│ Child Component │
36+
│ - Receives data via @property │
37+
│ - Emits custom events (up) │
38+
└─────────────────────────────────────┘
39+
```
40+
41+
---
42+
43+
## Implementation
44+
45+
### Parent → Child (Properties)
46+
47+
**Parent sets property**:
48+
```javascript
49+
// parent-component.js
50+
import { LitElement, html } from 'lit-element';
51+
52+
class ParentComponent extends LitElement {
53+
render() {
54+
return html`
55+
<api-navigation
56+
.amf="${this.amf}"
57+
.selected="${this.selectedId}">
58+
</api-navigation>
59+
`;
60+
}
61+
}
62+
```
63+
64+
**Child receives property**:
65+
```javascript
66+
// api-navigation.js
67+
import { LitElement, html } from 'lit-element';
68+
69+
class ApiNavigation extends LitElement {
70+
static get properties() {
71+
return {
72+
amf: { type: Object },
73+
selected: { type: String }
74+
};
75+
}
76+
77+
updated(changedProps) {
78+
if (changedProps.has('amf')) {
79+
this._processAmf(this.amf);
80+
}
81+
}
82+
}
83+
```
84+
85+
### Child → Parent (Custom Events)
86+
87+
**Child dispatches event**:
88+
```javascript
89+
// api-navigation.js
90+
_handleSelection(endpointId) {
91+
this.dispatchEvent(new CustomEvent('api-navigation-selection-changed', {
92+
bubbles: true,
93+
composed: true,
94+
detail: { selected: endpointId }
95+
}));
96+
}
97+
```
98+
99+
**Parent listens to event**:
100+
```javascript
101+
// parent-component.js
102+
render() {
103+
return html`
104+
<api-navigation
105+
@api-navigation-selection-changed="${this._onSelectionChanged}">
106+
</api-navigation>
107+
`;
108+
}
109+
110+
_onSelectionChanged(e) {
111+
this.selectedId = e.detail.selected;
112+
}
113+
```
114+
115+
### Sibling → Sibling (Shared State)
116+
117+
**Option 1: State in parent** (preferred for simple cases):
118+
```javascript
119+
// parent manages state, passes to both children
120+
class ParentComponent extends LitElement {
121+
render() {
122+
return html`
123+
<api-navigation
124+
.selected="${this.selectedId}"
125+
@selection-changed="${this._onSelectionChanged}">
126+
</api-navigation>
127+
128+
<api-documentation
129+
.selected="${this.selectedId}">
130+
</api-documentation>
131+
`;
132+
}
133+
}
134+
```
135+
136+
**Option 2: Event bus** (for complex cases):
137+
```javascript
138+
// Avoid unless absolutely necessary - harder to debug
139+
```
140+
141+
---
142+
143+
## Rules
144+
145+
### ✅ DO
146+
- Use `.property` syntax for Object/Array properties (not attributes)
147+
- Use `bubbles: true, composed: true` for events that cross shadow DOM
148+
- Prefix event names with component name (`api-navigation-*`)
149+
- Document event details in JSDoc
150+
- Keep event payloads simple (primitives, plain objects)
151+
152+
### ❌ DON'T
153+
- Don't access child component methods directly (`this.querySelector('api-nav').selectEndpoint()`)
154+
- Don't use global variables for component communication
155+
- Don't mutate objects passed as properties (create new objects instead)
156+
- Don't listen to events on `window` unless truly global
157+
158+
---
159+
160+
## Example from Codebase
161+
162+
See `api-console/src/ApiConsole.js` for complete parent-child pattern:
163+
- Properties: `amf`, `selected`, `baseUri`
164+
- Events: `api-navigation-selection-changed`, `api-request-send`
165+
166+
---
167+
168+
## Testing
169+
170+
```javascript
171+
import { fixture, html } from '@open-wc/testing';
172+
173+
it('emits selection event when item clicked', async () => {
174+
const el = await fixture(html`<api-navigation></api-navigation>`);
175+
176+
setTimeout(() => el._handleSelection('endpoint-1'));
177+
const event = await oneEvent(el, 'api-navigation-selection-changed');
178+
179+
expect(event.detail.selected).to.equal('endpoint-1');
180+
});
181+
```
182+
183+
---
184+
185+
## Related
186+
- [Shadow DOM Styling Pattern](./01-shadow-dom-styling.md)
187+
- [AMF Integration Pattern](./02-amf-integration.md)
188+
189+
---
190+
191+
**Last Updated**: 2026-02-26

0 commit comments

Comments
 (0)