diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..d066daa78 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Read(//Users/alexperez/mulesoft/context/products/api-console/v6/api-summary/**)", + "Bash(cd ~/mulesoft/context/products/api-console/v6/api-console && npm ls @api-components/api-summary @api-components/api-type-document)" + ] + } +} diff --git a/.claude/skills/update-api-console-components/SKILL.md b/.claude/skills/update-api-console-components/SKILL.md new file mode 100644 index 000000000..c3f6ad148 --- /dev/null +++ b/.claude/skills/update-api-console-components/SKILL.md @@ -0,0 +1,527 @@ +--- +name: update-api-console-components +description: Complete release workflow for api-console v6 and anypoint-api-console wrapper +triggers: + - update api console components + - bump api console version + - release api console v6 + - update console components + - release anypoint api console + - update wrapper +--- + +# Update API Console v6 Components & Release Wrapper + +Automates the complete release workflow: +1. Update component dependencies in `api-console` v6 (mulesoft/api-console) +2. Bump version and publish to npm +3. Update `anypoint-api-console` wrapper (mulesoft-emu/anypoint-api-console) with new version + +## Prerequisites + +### For api-console (mulesoft/api-console) + +1. **Components must be already published to npm** (check with `npm view @api-components/ version`) +2. **Working directory must be clean** (no untracked files, ensure `.claude/` in gitignore) +3. **Must be in `mulesoft/api-console` repo**: `~/mulesoft/context/products/api-console/v6/api-console` +4. **CRITICAL**: This is a MuleSoft repo - requires GPG signing with `alexperez@mulesoft.com` +5. Have GUS ticket numbers for components being updated (to reference in commit) + +### For anypoint-api-console (mulesoft-emu/anypoint-api-console) + +1. **api-console must be published to npm** (wait ~5-10 min after merge for CI) +2. **Must be in wrapper repo**: `~/mulesoft/context/products/api-console/wrapper` +3. **CRITICAL**: This is a Salesforce EMU repo - requires GPG signing with `alexperez@salesforce.com` +4. Have GUS work item for wrapper release (e.g., "APIC Release" W-XXXXXXXX) + +### GUS Conventions + +- **Component version comments**: Always comment in GUS tickets: `Fixed in @api-components/component@X.Y.Z` +- **PR titles with work items**: Always use `@W-XXXXXXXX` format (with `@` prefix) +- **Wrapper work item**: Create or reuse "APIC Release" work item (Type: User Story, 1 point) + +## Input Required + +Ask user for: +- List of components to update (e.g., `api-navigation`, `api-summary`, `api-type-document`) +- Expected versions (or "latest") +- GUS ticket numbers (for commit message) + +## Steps + +### 1. Verify location and checkout main branch + +```bash +cd ~/mulesoft/context/products/api-console/v6/api-console +git status # Verify we're in correct repo +git checkout master # Main branch (currently named 'master' in api-console repo) +git pull +``` + +### 2. Create release branch + +Read current version from `package.json`, calculate next patch version. + +```bash +# If current is 6.6.60, next is 6.6.61 +git checkout -b build/ +``` + +**Branch pattern**: `build/X.X.X` where X.X.X is the next patch version. + +### 3. Update components + +For each component in the update list: + +```bash +npm update @api-components/ +``` + +**Common components**: +- `@api-components/api-navigation` +- `@api-components/api-summary` +- `@api-components/api-type-document` +- `@api-components/api-documentation` +- `@api-components/api-request` + +### 4. Verify each update + +For each updated component: + +```bash +npm ls @api-components/ +``` + +**Check for**: +- ✅ Version matches expected (from GUS ticket comments or npm registry) +- ✅ No warnings about overrides or conflicts +- ✅ "deduped" is OK for transitive dependencies + +**If overrides/conflicts detected**: +```bash +rm package-lock.json +rm -rf node_modules +npm install +npm ls @api-components/ # verify again +``` + +### 5. Configure GPG signing (CRITICAL - DO NOT SKIP) + +**BEFORE any commits**, configure Git for MuleSoft repos: + +```bash +# Option 1: If you have the alias (see docs/team/configs/git-gpg-setup.md) +mulesoft-git + +# Option 2: Manual configuration +git config user.email "yourname@mulesoft.com" +git config user.signingkey YOUR_GPG_KEY_ID +``` + +This ensures commits are signed with your @mulesoft.com email. + +**⚠️ Skipping this step will result in rejected commits and broken git history.** + +**Setup guide**: See `docs/team/configs/git-gpg-setup.md` for GPG configuration options. + +### 6. Bump package version + +```bash +npm version patch --no-git-tag-version +``` + +This updates `package.json` to next patch version without creating a git commit. + +**Why `--no-git-tag-version`**: Avoids "Git working directory not clean" errors. We'll commit manually. + +### 7. Commit changes + +Prepare commit message listing all updated components: + +```bash +git add package.json package-lock.json + +git commit -m "chore: bump version to + +Updated components: +- @api-components/component1: oldVer → newVer +- @api-components/component2: oldVer → newVer +- @api-components/component3: oldVer → newVer + +Related: W-XXXXXXX, W-YYYYYYY" +``` + +**Commit message format**: +- Type: `chore:` +- Subject: `bump version to X.X.X` +- Body: List each updated component with version change +- Footer: Reference GUS tickets + +### 8. Verify GPG signature + +```bash +git log --show-signature -1 +``` + +**Must show**: +- `Good signature from "Your Name "` +- Author: `Your Name ` + +**If signature is wrong or missing**: +```bash +# Reconfigure (see docs/team/configs/git-gpg-setup.md) +git config user.email "yourname@mulesoft.com" +git config user.signingkey YOUR_GPG_KEY_ID + +# Amend commit +git commit --amend --no-edit -S +git log --show-signature -1 # verify again +``` + +### 9. Push branch + +```bash +git push -u origin build/ +``` + +### 10. Create Pull Request + +**⚠️ Cannot use `gh pr create`**: EMU account restrictions prevent gh CLI from accessing mulesoft/* repos. + +**Use GitHub web UI instead**: +1. Go to https://github.com/mulesoft/api-console +2. Click "Compare & pull request" banner +3. **Title**: `Release v` +4. **Body**: + ```markdown + ## Updated Components + + - @api-components/api-navigation: 4.3.20 → 4.3.22 + - @api-components/api-summary: 4.6.16 → 4.6.18 + - @api-components/api-type-document: (transitive) → 4.2.41 + + ## Related Tickets + + - W-XXXXXXX: Description + - W-YYYYYYY: Description + + All tickets currently in "Pending Release" status. + ``` +5. Request review +6. Provide PR URL to user + +## Post-Merge: Update anypoint-api-console (Wrapper) + +After api-console PR is merged and new version is published to npm (automatic via CI, ~5-10 min): + +### Prerequisites + +- Verify api-console published: `npm view api-console version` (should show new version) +- Have GUS work item for wrapper release (or create one: "APIC Release") + +### Steps + +#### 1. Navigate to wrapper repo + +**Location**: `~/mulesoft/context/products/api-console/wrapper` (NOT `v6/anypoint-api-console`) + +```bash +cd ~/mulesoft/context/products/api-console/wrapper +git status # Verify we're in correct repo +git checkout master # Main branch (currently named 'master' in wrapper repo) +``` + +#### 2. Configure GPG signing (CRITICAL) + +**IMPORTANT**: This is a `mulesoft-emu/*` repo (Salesforce EMU), NOT `mulesoft/*`. + +```bash +# Option 1: If you have the alias (see docs/team/configs/git-gpg-setup.md) +salesforce-git + +# Option 2: Manual configuration +git config user.email "yourname@salesforce.com" +git config user.signingkey YOUR_GPG_KEY_ID +``` + +This ensures commits are signed with your @salesforce.com email (NOT @mulesoft.com). + +#### 3. Pull latest changes + +```bash +git pull +``` + +**Note**: If pull fails with "Repository not found", verify remote: +```bash +git remote -v # Should show: mulesoft-emu/anypoint-api-console +``` + +#### 4. Create release branch + +**Branch naming**: Use wrapper version number directly (e.g., `6.6.88`), NOT `build/` or `feat/` prefix. + +**Version calculation**: +- Read current wrapper version from root `package.json` or recent branches +- Wrapper versions are independent from api-console versions +- Example: api-console 6.6.61 → wrapper 6.6.88 + +```bash +git checkout -b 6.6.88 # Direct number, no prefix +``` + +#### 5. Update api-console dependency + +Edit `builder/package.json`: + +```bash +# Change from: +"api-console": "6.6.60" + +# To: +"api-console": "6.6.61" +``` + +#### 6. Install dependencies (CRITICAL - Always delete lock) + +**IMPORTANT**: Always delete `package-lock.json` and `node_modules`. This is NOT optional. + +```bash +cd builder +rm package-lock.json +rm -rf node_modules +npm install +``` + +**Why**: Ensures transitive component dependencies update correctly. Skipping this step causes component version mismatches. + +#### 7. Verify component versions + +Check all three gRPC-related components: + +```bash +npm ls @api-components/api-navigation @api-components/api-summary @api-components/api-type-document +``` + +**Expected output**: +``` +api-console-builder@0.0.1 /path/to/wrapper/builder +└─┬ api-console@6.6.61 + ├── @api-components/api-navigation@4.3.22 + ├── @api-components/api-summary@4.6.18 + └── @api-components/api-type-document@4.2.41 (deduped in tree) +``` + +**If versions don't match**: Something went wrong. Re-run step 6. + +#### 8. Commit changes + +Return to repo root and commit: + +```bash +cd .. # Back to repo root +git add builder/package.json builder/package-lock.json +git commit -m "chore: update api-console to 6.6.61 + +Includes gRPC-related component updates: +- @api-components/api-navigation: 4.3.20 → 4.3.22 +- @api-components/api-summary: 4.6.16 → 4.6.18 +- @api-components/api-type-document: → 4.2.41 + +Related: W-XXXXXXX, W-YYYYYYY" +``` + +**Commit message format**: +- Type: `chore:` +- List component updates (NOT wrapper version bump) +- Reference original GUS tickets from api-console release + +#### 9. Verify GPG signature + +```bash +git log --show-signature -1 +``` + +**Must show**: +``` +gpg: Good signature from "Your Name " +Author: Your Name +``` + +**If wrong**: Reconfigure and amend commit (see docs/team/configs/git-gpg-setup.md). + +#### 10. Push branch + +```bash +git push -u origin 6.6.88 +``` + +#### 11. Create Pull Request + +**✅ Can use `gh pr create`**: EMU account DOES work with `mulesoft-emu/*` repos. + +**PR Title Format**: `@W-XXXXXXXX: Release X.X.X` + +**IMPORTANT**: +- Always prefix GUS work item with `@` (e.g., `@W-21411326`) +- Use wrapper version in title (e.g., `6.6.88`), NOT api-console version + +```bash +gh pr create --title "@W-21411326: Release 6.6.88" --body "Updates api-console dependency to v6.6.61 + +## Updated Components + +- @api-components/api-navigation: 4.3.20 → 4.3.22 +- @api-components/api-summary: 4.6.16 → 4.6.18 +- @api-components/api-type-document: → 4.2.41 + +## Related + +- api-console release: https://github.com/mulesoft/api-console/releases/tag/v6.6.61 +- api-console PR: https://github.com/mulesoft/api-console/pull/XXX +- npm: https://www.npmjs.com/package/api-console/v/6.6.61 +- GUS: W-21315017, W-21315032" +``` + +**GUS Work Item**: +- Use existing "APIC Release" work item (e.g., W-21411326) +- OR create new work item: "APIC Release" (Type: User Story, 1 story point) + +#### 12. Announce in Slack (after merge) + +Post in `#api-console-cloud-sync`: + +``` +Hi team, We've released a new API Console version: +api-console@6.6.61 (@mulesoft/api-console-build@6.6.88) + +Release Notes: https://github.com/mulesoft/api-console/releases/tag/v6.6.61 +``` + +**Format**: +- First line: `api-console@X.X.X (@mulesoft/api-console-build@Y.Y.Y)` +- Second line: Link to GitHub release notes (contains full details) + +### Validation Checklist (anypoint-api-console) + +Before pushing: + +- [ ] Correct repo: `~/mulesoft/context/products/api-console/wrapper` +- [ ] GPG configured: @salesforce.com email (see docs/team/configs/git-gpg-setup.md) +- [ ] Branch name: Direct number (e.g., `6.6.88`), no `build/` or `feat/` prefix +- [ ] `builder/package.json` updated to new api-console version +- [ ] Lock file deleted + reinstalled (NOT optional) +- [ ] Component versions verified: `npm ls @api-components/...` +- [ ] All components at expected versions (no old versions) +- [ ] Commit signed with @salesforce.com GPG key +- [ ] PR title: `@W-XXXXXXXX: Release X.X.X` (with `@` prefix) +- [ ] GUS work item exists for wrapper release + +### Key Differences: api-console vs anypoint-api-console + +| Aspect | api-console | anypoint-api-console | +|--------|-------------|----------------------| +| **Repo org** | `mulesoft/*` | `mulesoft-emu/*` | +| **GPG email** | @mulesoft.com | @salesforce.com | +| **GPG setup** | See docs/team/configs/git-gpg-setup.md | See docs/team/configs/git-gpg-setup.md | +| **Branch naming** | `build/6.6.61` | `6.6.88` (no prefix) | +| **Version bump** | Yes (`npm version patch`) | No (only update dependency) | +| **gh pr create** | ❌ Fails (use web UI) | ✅ Works | +| **PR title** | `Release vX.X.X` | `@W-XXXXXXXX: Release X.X.X` | +| **Lock file delete** | Optional (if conflicts) | Mandatory (always) | + +## Validation Checklist + +Before pushing branch, verify: + +- [ ] All target components updated to expected versions (via `npm ls`) +- [ ] No npm overrides or conflicts +- [ ] Version bumped in `package.json` (e.g., 6.6.60 → 6.6.61) +- [ ] Commit signed with `alexperez@mulesoft.com` GPG key (verified with `git log --show-signature -1`) +- [ ] Commit message follows conventional commits format +- [ ] GUS tickets referenced in commit message +- [ ] Working directory clean (no uncommitted changes) + +## Common Issues & Solutions + +### Issue: "Git working directory not clean" + +**Cause**: Untracked files (e.g., `.claude/`) or staged changes. + +**Solution**: +```bash +git status --porcelain # Find untracked files +# Add .claude/ to .gitignore if not present +# OR: Use --no-git-tag-version flag (already in workflow) +``` + +### Issue: Wrong GPG signature + +**Cause**: Git not configured with correct email/GPG key for this repo. + +**Solution**: +```bash +# Reconfigure (see docs/team/configs/git-gpg-setup.md for setup) +git config user.email "yourname@mulesoft.com" # or @salesforce.com for EMU repos +git config user.signingkey YOUR_GPG_KEY_ID + +# Amend commit +git commit --amend --no-edit -S +git log --show-signature -1 +``` + +### Issue: Component not updating to expected version + +**Cause**: Version constraint in `package.json` doesn't allow new version, OR new version not published to npm. + +**Solution**: +```bash +# Check if version exists in npm +npm view @api-components/ version + +# If exists but not updating, check package.json constraint +# Example: "^4.3.20" allows 4.3.22 but not 5.0.0 + +# If constraint is blocking, manually update package.json +# Then run npm install + +# If still not working, delete lock file +rm package-lock.json +npm install +``` + +### Issue: `npm ls` shows overrides + +**Cause**: Multiple versions of same dependency in tree, npm forced resolution. + +**Solution**: +```bash +cd builder # If in anypoint-api-console +rm package-lock.json +rm -rf node_modules +npm install +npm ls @api-components/ +``` + +### Issue: `gh pr create` fails with "Enterprise Managed User" error + +**Cause**: EMU account cannot use GitHub API for `mulesoft/*` repos (only `mulesoft-emu/*` works). + +**Solution**: Use GitHub web UI to create PR. `git push/pull` work fine (use SSH/HTTPS, not API). + +## Notes + +- **Release cycle**: Every 3 weeks on Fridays (see API Designer release calendar) +- **Build number**: Optional, use semantic version instead (X.X.X) +- **Components are separate repos**: Under `advanced-rest-client` GitHub org, NOT `mulesoft` +- **AMF models**: Not affected by component updates (unless AMF version changes) +- **CI/CD**: GitHub Actions automatically publishes to npm after merge to main branch +- **Downstream consumers**: ACM, Exchange, API Designer will pick up new version on their next update cycle + +## Related Documentation + +- Onboarding doc: Quip (ACM team folder) + Google Drive (acm-aeh-team) +- api-console repo: https://github.com/mulesoft/api-console +- anypoint-api-console repo: https://github.com/mulesoft/anypoint-api-console +- Advanced REST Client (components): https://github.com/advanced-rest-client +- Release calendar: [API Designer release calendar link] diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 000000000..25405c0c7 --- /dev/null +++ b/.cursorignore @@ -0,0 +1,47 @@ +# Cursor Ignore - Exclude from AI context for better performance + +# Build outputs +dist/ +coverage/ +demo/vendor.js + +# Dependencies +node_modules/ + +# Generated AMF models (except specific test models) +demo/models/*.json +demo/models/flattened/*.json +!demo/models/jldAsync26.json +!demo/models/avro.json +!demo/models/avro2.json +!demo/models/grpc-test.json +!demo/models/grpc-test-compact.json +!demo/models/product-order-deep-allof.json + +# IDE configs (keep lightweight) +.vscode/* +!.vscode/settings.json +.idea/ + +# OS files +.DS_Store +Thumbs.db +*.stackdump + +# Git internals +.git/ + +# Large log files +*.log +npm-debug.log* + +# Test screenshots (visual regression baselines - too many files) +test/visual/screenshots/ + +# Package lock files (too large, let Cursor use package.json) +package-lock.json + +# Temporary files +*.tmp +*.swp +*~ diff --git a/.gitignore b/.gitignore index a051f68b8..48064e904 100644 --- a/.gitignore +++ b/.gitignore @@ -71,4 +71,13 @@ demo/models/flattened/*.json .idea/ .sfdx -.codegenie \ No newline at end of file +.codegenie +# Claude/Cursor working files +# Note: Skills are committed (team workflows), other .claude/ content is not +.claude/analyses/ +.claude/plans/ +.claude/investigations/ +.claude/context/ +.claude/temp/ +.claude/README.md +.cursor/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..530585430 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,195 @@ +# AGENTS.md - api-console v6 + +AI context file for assistants (Claude Code, Cursor, Copilot) working with this open-source Web Components project. + +> **Full docs**: [README.md](./README.md) | **Team patterns**: [docs/team/](./docs/team/) + +--- + +## Tech Stack + +- **LitElement 2.x** + Web Components (Shadow DOM) +- **AMF v4.0+** (API Modeling Framework - RAML/OAS/AsyncAPI/gRPC) +- **npm workspace** (18+ packages, main: `api-console`, components: `api-navigation`, `api-documentation`, etc.) +- **@web/test-runner** (testing, **NOT Jest** - poor Shadow DOM support) +- **Rollup** (builds), **Playwright** (visual regression) + +### Two Entry Points +- `src/ApiConsoleApp.js` - Standalone app (routing, layout, OAuth) +- `src/ApiConsole.js` - Embeddable component (no routing/layout) + +--- + +## AMF Model Architecture (CRITICAL) + +**IMPORTANT**: API Console does **NOT** parse API files directly. It requires **pre-generated AMF models**. + +### What is AMF? +MuleSoft's unified model for RAML, OAS, AsyncAPI, gRPC. Format: JSON-LD (AMF v4.0+). + +### Generate Models +```bash +# 1. Define APIs in demo/apis.json: { "path/to/api.raml": "RAML 1.0" } +# 2. Generate models +npm run build:models +# 3. Models saved to demo/models/*.json +``` + +### Load Models +```javascript +// Direct model +apiConsole.amf = await generateApiModel(); + +// URL to JSON +apiConsole.modelLocation = 'models/my-api.json'; +``` + +--- + +## Coding Patterns (CRITICAL) + +### 1. Component Communication + +**IMPORTANT**: Use custom events, **NOT** direct method calls. + +```javascript +// ✅ GOOD: Custom event (bubbles across Shadow DOM) +this.dispatchEvent(new CustomEvent('api-navigation-selection-changed', { + bubbles: true, + composed: true, + detail: { selected, type } +})); + +// ❌ BAD: Direct method call (breaks encapsulation) +this.parentElement.onNavigationChange(selected); +``` + +**Why**: Shadow DOM isolation requires composed events to bubble across boundaries. + +### 2. AMF Queries + +**IMPORTANT**: Use AmfHelperMixin utilities, **NOT** direct JSON access. + +```javascript +// ✅ GOOD: AmfHelperMixin +import { AmfHelperMixin } from '@api-components/amf-helper-mixin'; + +class MyComponent extends AmfHelperMixin(LitElement) { + _computeEndpoints(model) { + return this._computeWebApi(model); // Helper method + } +} + +// ❌ BAD: Direct JSON access (structure changes) +const endpoints = model['@graph'][0]['http://raml.org/vocabularies/http#endpoint']; +``` + +**Why**: AMF model structure can change; helpers abstract this. + +### 3. Shadow DOM Styling + +Use CSS custom properties for theming: +```css +:host { + --api-console-primary-color: #00A1E0; +} +``` + +❌ **Never** manipulate DOM styles directly (`document.querySelector('#api-console').style...`). + +### 4. Lazy Loading + +For large APIs, lazy load components on demand: +```javascript +if (this.selectedShape) { + import('@api-components/api-documentation') + .then(() => this._renderDocumentation()); +} +``` + +--- + +## Testing Strategy + +### Commands +```bash +npm test # All tests (chromium + firefox) +npm run test:watch # Watch mode +npm run test:visual # Visual regression +npm run test:visual:update # Update baselines (after intentional UI changes) +``` + +### Write Tests with @web/test-runner +**IMPORTANT**: Use @web/test-runner, **NOT Jest** (poor Shadow DOM support). + +```javascript +import { fixture, expect } from '@open-wc/testing'; +it('renders navigation', async () => { + const el = await fixture(''); + expect(el.shadowRoot.querySelector('api-navigation')).to.exist; +}); +``` + +--- + +## Anti-Patterns + +### Code +- **IMPORTANT: Never parse API files directly** → Use AMF models +- **IMPORTANT: Never access AMF JSON directly** → Use AmfHelperMixin +- **IMPORTANT: Never use direct method calls between components** → Use custom events +- **Never use Jest** → Use @web/test-runner +- **Never use `any` in TypeScript** → Proper types + +### Dependencies +- **Never import CodeMirror/crypto as ES modules** → Use `vendor.js` (non-ES6 dependencies bundled separately) +- **Never modify AMF model structure** → External standard, use helpers + +### Git +- **Never commit directly to master** → Always create branch first (`fix/W-XXXXXXXX-desc` or `build/X.X.X`) +- **Never skip GPG signing** → Run `mulesoft-git` before committing +- **Never commit large models** → Generate locally (`npm run build:models`) + +--- + +## Build & Verification Strategy + +**Rule**: Don't run build after every small change (saves tokens, avoids error loops). + +**Workflow**: +1. Implement feature +2. Write tests +3. Run `npm test` (once) +4. Run `npm run build` only when: user asks explicitly, before PR, or after major type changes + +--- + +## Quick Commands + +```bash +npm run prepare # Build vendor.js + generate AMF models (required after clone) +npm start # Dev server +npm test # Run all tests +npm run build # Production build +npm run build:models # Generate AMF models from demo/apis.json +npm update @api-components/* # Update workspace components +``` + +--- + +## Links + +### Team Documentation +- **Runbooks**: [docs/team/runbooks/](./docs/team/runbooks/) - Release process, debugging +- **Patterns**: [docs/team/patterns/](./docs/team/patterns/) - Web Component communication, architecture +- **Configs**: [docs/team/configs/](./docs/team/configs/) - Git GPG setup, IDE settings + +### External Resources +- **Full docs**: https://docs.api-console.io +- **AMF**: https://github.com/aml-org/amf +- **LitElement v2**: https://lit.dev/docs/v2/ +- **@web/test-runner**: https://modern-web.dev/docs/test-runner/overview/ + +--- + +**Last Updated**: 2026-03-20 (Ultra-optimized for AI context efficiency) diff --git a/README.md b/README.md index 5ac485912..6c1cef537 100644 --- a/README.md +++ b/README.md @@ -152,3 +152,16 @@ For the same reasons as for CodeMirror this dependencies are required for OAuth1 ``` + +--- + +## For AI Assistants + +This repo includes AI context for tools like Claude Code, Cursor, and Copilot: + +- **[AGENTS.md](./AGENTS.md)**: Tech stack, architecture patterns, AMF model usage, testing strategy +- **[docs/team/](./docs/team/)**: Runbooks (release process, debugging), patterns (Web Component communication), configs + +**For contributors**: See [docs/team/README.md](./docs/team/README.md) for how to use and contribute. + +--- diff --git a/demo/models/grpc-ecommerce/grpc-ecommerce.proto b/demo/models/grpc-ecommerce/grpc-ecommerce.proto new file mode 100644 index 000000000..c1fe6cf63 --- /dev/null +++ b/demo/models/grpc-ecommerce/grpc-ecommerce.proto @@ -0,0 +1,871 @@ +syntax = "proto3"; + +package ecommerce.v1; + +// ─── Enums ─────────────────────────────────────────── + +enum OrderStatus { + ORDER_STATUS_UNSPECIFIED = 0; + ORDER_STATUS_PENDING = 1; + ORDER_STATUS_CONFIRMED = 2; + ORDER_STATUS_PROCESSING = 3; + ORDER_STATUS_SHIPPED = 4; + ORDER_STATUS_DELIVERED = 5; + ORDER_STATUS_CANCELLED = 6; + ORDER_STATUS_REFUNDED = 7; + ORDER_STATUS_RETURNED = 8; +} + +enum Currency { + CURRENCY_UNSPECIFIED = 0; + CURRENCY_USD = 1; + CURRENCY_EUR = 2; + CURRENCY_GBP = 3; + CURRENCY_ARS = 4; + CURRENCY_BRL = 5; + CURRENCY_JPY = 6; +} + +enum PaymentMethod { + PAYMENT_METHOD_UNSPECIFIED = 0; + PAYMENT_METHOD_CREDIT_CARD = 1; + PAYMENT_METHOD_DEBIT_CARD = 2; + PAYMENT_METHOD_PAYPAL = 3; + PAYMENT_METHOD_BANK_TRANSFER = 4; + PAYMENT_METHOD_CRYPTO = 5; + PAYMENT_METHOD_APPLE_PAY = 6; + PAYMENT_METHOD_GOOGLE_PAY = 7; +} + +enum ProductCategory { + PRODUCT_CATEGORY_UNSPECIFIED = 0; + PRODUCT_CATEGORY_ELECTRONICS = 1; + PRODUCT_CATEGORY_CLOTHING = 2; + PRODUCT_CATEGORY_BOOKS = 3; + PRODUCT_CATEGORY_HOME = 4; + PRODUCT_CATEGORY_SPORTS = 5; + PRODUCT_CATEGORY_FOOD = 6; + PRODUCT_CATEGORY_TOYS = 7; + PRODUCT_CATEGORY_AUTOMOTIVE = 8; +} + +enum ShipmentCarrier { + SHIPMENT_CARRIER_UNSPECIFIED = 0; + SHIPMENT_CARRIER_FEDEX = 1; + SHIPMENT_CARRIER_UPS = 2; + SHIPMENT_CARRIER_DHL = 3; + SHIPMENT_CARRIER_USPS = 4; + SHIPMENT_CARRIER_CUSTOM = 5; +} + +enum NotificationType { + NOTIFICATION_TYPE_UNSPECIFIED = 0; + NOTIFICATION_TYPE_ORDER_UPDATE = 1; + NOTIFICATION_TYPE_PRICE_DROP = 2; + NOTIFICATION_TYPE_BACK_IN_STOCK = 3; + NOTIFICATION_TYPE_PROMOTION = 4; + NOTIFICATION_TYPE_SHIPMENT_UPDATE = 5; + NOTIFICATION_TYPE_REVIEW_REPLY = 6; +} + +enum SortDirection { + SORT_DIRECTION_UNSPECIFIED = 0; + SORT_DIRECTION_ASC = 1; + SORT_DIRECTION_DESC = 2; +} + +// ─── Shared / Reusable Messages ────────────────────── + +message Money { + int64 units = 1; + int32 nanos = 2; + Currency currency = 3; +} + +message Timestamp { + int64 seconds = 1; + int32 nanos = 2; +} + +message DateRange { + Timestamp start = 1; + Timestamp end = 2; +} + +message GeoPoint { + double latitude = 1; + double longitude = 2; +} + +message Address { + string street_line1 = 1; + string street_line2 = 2; + string city = 3; + string state = 4; + string zip_code = 5; + string country_code = 6; + GeoPoint coordinates = 7; + + oneof address_label { + string custom_label = 8; + AddressType predefined_label = 9; + } + + enum AddressType { + ADDRESS_TYPE_UNSPECIFIED = 0; + ADDRESS_TYPE_HOME = 1; + ADDRESS_TYPE_WORK = 2; + ADDRESS_TYPE_BILLING = 3; + ADDRESS_TYPE_SHIPPING = 4; + ADDRESS_TYPE_WAREHOUSE = 5; + } +} + +message PaginationRequest { + int32 page_size = 1; + string page_token = 2; + SortDirection sort_direction = 3; +} + +message PaginationResponse { + string next_page_token = 1; + int32 total_count = 2; + bool has_more = 3; +} + +message Empty {} + +// ─── Product Domain ────────────────────────────────── + +message Product { + string id = 1; + string name = 2; + string description = 3; + string slug = 4; + Money price = 5; + Money compare_at_price = 6; + ProductCategory category = 7; + repeated string tags = 8; + repeated ProductVariant variants = 9; + map metadata = 10; + map localized_names = 11; + int32 stock_quantity = 12; + bool is_active = 13; + bool is_featured = 14; + float rating = 15; + int32 review_count = 16; + Timestamp created_at = 17; + Timestamp updated_at = 18; + repeated ProductImage images = 19; + ProductDimensions dimensions = 20; + repeated ProductAttribute attributes = 21; + + oneof availability { + bool in_stock = 22; + Timestamp restock_date = 23; + string discontinued_reason = 24; + } + + message ProductDimensions { + float weight_kg = 1; + float length_cm = 2; + float width_cm = 3; + float height_cm = 4; + } + + message ProductAttribute { + string key = 1; + oneof value { + string string_value = 2; + int64 int_value = 3; + double double_value = 4; + bool bool_value = 5; + StringList list_value = 6; + } + } + + message StringList { + repeated string values = 1; + } +} + +message ProductVariant { + string id = 1; + string sku = 2; + Money price_override = 3; + int32 stock = 4; + map options = 5; + repeated string image_ids = 6; + + oneof variant_status { + bool active = 7; + string deactivation_reason = 8; + } +} + +message ProductImage { + string id = 1; + string url = 2; + string alt_text = 3; + bool is_primary = 4; + int32 sort_order = 5; + ImageDimensions dimensions = 6; + + message ImageDimensions { + int32 width = 1; + int32 height = 2; + } +} + +// ─── Product Service Requests/Responses ────────────── + +message SearchProductsRequest { + string query = 1; + repeated ProductCategory categories = 2; + Money min_price = 3; + Money max_price = 4; + repeated string tags = 5; + bool in_stock_only = 6; + bool featured_only = 7; + float min_rating = 8; + PaginationRequest pagination = 9; + map attribute_filters = 10; + + oneof sort_by { + bool sort_by_price = 11; + bool sort_by_rating = 12; + bool sort_by_newest = 13; + bool sort_by_popularity = 14; + bool sort_by_relevance = 15; + } +} + +message SearchProductsResponse { + repeated Product products = 1; + PaginationResponse pagination = 2; + int32 total_results = 3; + map category_facets = 4; + map tag_facets = 5; + PriceRange price_range = 6; + string search_id = 7; + + message PriceRange { + Money min = 1; + Money max = 2; + } +} + +message GetProductRequest { + string product_id = 1; + + oneof lookup { + string slug = 2; + string sku = 3; + } + + repeated ProductFieldMask fields = 4; + + enum ProductFieldMask { + PRODUCT_FIELD_MASK_UNSPECIFIED = 0; + PRODUCT_FIELD_MASK_BASIC = 1; + PRODUCT_FIELD_MASK_VARIANTS = 2; + PRODUCT_FIELD_MASK_IMAGES = 3; + PRODUCT_FIELD_MASK_ATTRIBUTES = 4; + PRODUCT_FIELD_MASK_FULL = 5; + } +} + +message CreateProductRequest { + string name = 1; + string description = 2; + Money price = 3; + ProductCategory category = 4; + repeated string tags = 5; + repeated ProductVariant variants = 6; + map metadata = 7; + map localized_names = 8; + repeated Product.ProductAttribute attributes = 9; + bool is_featured = 10; +} + +message UpdateProductRequest { + string product_id = 1; + + oneof update { + ProductInfoUpdate info = 2; + ProductPriceUpdate price = 3; + ProductStockUpdate stock = 4; + ProductStatusUpdate status = 5; + } + + message ProductInfoUpdate { + string name = 1; + string description = 2; + repeated string tags = 3; + map metadata = 4; + } + + message ProductPriceUpdate { + Money new_price = 1; + Money compare_at_price = 2; + map variant_prices = 3; + } + + message ProductStockUpdate { + int32 quantity = 1; + string reason = 2; + map variant_stock = 3; + } + + message ProductStatusUpdate { + bool is_active = 1; + bool is_featured = 2; + string status_reason = 3; + } +} + +message DeleteProductRequest { + string product_id = 1; + bool hard_delete = 2; +} + +message BatchGetProductsRequest { + repeated string product_ids = 1; + repeated GetProductRequest.ProductFieldMask fields = 2; +} + +message BatchGetProductsResponse { + map products = 1; + repeated string not_found_ids = 2; +} + +message ProductImportRecord { + string external_id = 1; + string name = 2; + string description = 3; + Money price = 4; + ProductCategory category = 5; + int32 stock = 6; + map metadata = 7; + + oneof source { + string csv_row = 8; + string json_payload = 9; + string xml_payload = 10; + } +} + +message ProductImportResult { + string external_id = 1; + bool success = 2; + string product_id = 3; + string error_message = 4; + int32 row_number = 5; +} + +message ProductImportSummary { + int32 total = 1; + int32 succeeded = 2; + int32 failed = 3; + int32 skipped = 4; + repeated ProductImportResult failures = 5; +} + +// ─── Order Domain ──────────────────────────────────── + +message Order { + string id = 1; + string customer_id = 2; + repeated OrderItem items = 3; + Money subtotal = 4; + Money tax = 5; + Money shipping_cost = 6; + Money discount = 7; + Money total = 8; + OrderStatus status = 9; + Address shipping_address = 10; + Address billing_address = 11; + PaymentInfo payment = 12; + ShipmentInfo shipment = 13; + Timestamp created_at = 14; + Timestamp updated_at = 15; + repeated OrderEvent history = 16; + map notes = 17; + string coupon_code = 18; + + oneof fulfillment { + ShipmentInfo delivery = 19; + PickupInfo store_pickup = 20; + DigitalDeliveryInfo digital_delivery = 21; + } +} + +message OrderItem { + string product_id = 1; + string variant_id = 2; + string product_name = 3; + int32 quantity = 4; + Money unit_price = 5; + Money total_price = 6; + Money discount_amount = 7; + map customizations = 8; + + oneof item_status { + bool confirmed = 9; + string backorder_eta = 10; + string cancellation_reason = 11; + } +} + +message PaymentInfo { + PaymentMethod method = 1; + string transaction_id = 2; + string gateway_response = 3; + Timestamp paid_at = 4; + Money amount_charged = 5; + Money amount_refunded = 6; + + oneof payment_details { + CardDetails card = 7; + BankTransferDetails bank = 8; + CryptoDetails crypto = 9; + WalletDetails wallet = 10; + } + + message CardDetails { + string last_four = 1; + string brand = 2; + int32 exp_month = 3; + int32 exp_year = 4; + } + + message BankTransferDetails { + string bank_name = 1; + string reference_code = 2; + } + + message CryptoDetails { + string wallet_address = 1; + string network = 2; + string tx_hash = 3; + } + + message WalletDetails { + string provider = 1; + string account_email = 2; + } +} + +message ShipmentInfo { + ShipmentCarrier carrier = 1; + string tracking_number = 2; + string tracking_url = 3; + Timestamp shipped_at = 4; + Timestamp estimated_delivery = 5; + float weight_kg = 6; + repeated ShipmentEvent events = 7; + + message ShipmentEvent { + string status = 1; + string location = 2; + Timestamp occurred_at = 3; + string description = 4; + } +} + +message PickupInfo { + string store_id = 1; + string store_name = 2; + Address store_address = 3; + Timestamp ready_at = 4; + Timestamp pickup_deadline = 5; + string confirmation_code = 6; +} + +message DigitalDeliveryInfo { + repeated string download_urls = 1; + repeated string license_keys = 2; + Timestamp expires_at = 3; + int32 max_downloads = 4; +} + +message OrderEvent { + OrderStatus from_status = 1; + OrderStatus to_status = 2; + string description = 3; + string actor = 4; + Timestamp occurred_at = 5; + map context = 6; +} + +message CreateOrderRequest { + string customer_id = 1; + repeated OrderItemInput items = 2; + Address shipping_address = 3; + Address billing_address = 4; + PaymentMethod payment_method = 5; + string coupon_code = 6; + map notes = 7; + + oneof delivery_preference { + ShippingPreference shipping = 8; + string pickup_store_id = 9; + bool digital_delivery = 10; + } + + message ShippingPreference { + ShipmentCarrier preferred_carrier = 1; + bool express = 2; + bool signature_required = 3; + string delivery_instructions = 4; + } +} + +message OrderItemInput { + string product_id = 1; + string variant_id = 2; + int32 quantity = 3; + map customizations = 4; +} + +message GetOrderRequest { + string order_id = 1; + bool include_history = 2; + bool include_shipment_events = 3; +} + +message ListOrdersRequest { + string customer_id = 1; + repeated OrderStatus status_filter = 2; + DateRange date_range = 3; + PaginationRequest pagination = 4; + Money min_total = 5; + Money max_total = 6; + + oneof sort_by { + bool sort_by_date = 7; + bool sort_by_total = 8; + bool sort_by_status = 9; + } +} + +message ListOrdersResponse { + repeated Order orders = 1; + PaginationResponse pagination = 2; + map status_counts = 3; + Money total_revenue = 4; +} + +message UpdateOrderStatusRequest { + string order_id = 1; + OrderStatus new_status = 2; + string reason = 3; + map context = 4; +} + +message CancelOrderRequest { + string order_id = 1; + string cancellation_reason = 2; + bool refund_immediately = 3; +} + +// ─── Review Domain ─────────────────────────────────── + +message Review { + string id = 1; + string product_id = 2; + string customer_id = 3; + string customer_display_name = 4; + int32 rating = 5; + string title = 6; + string body = 7; + repeated string image_urls = 8; + bool verified_purchase = 9; + int32 helpful_count = 10; + int32 report_count = 11; + Timestamp created_at = 12; + Timestamp updated_at = 13; + ReviewReply seller_reply = 14; + map aspect_ratings = 15; + + oneof moderation_status { + bool approved = 16; + string rejection_reason = 17; + bool pending_review = 18; + } + + message ReviewReply { + string body = 1; + Timestamp replied_at = 2; + string replied_by = 3; + } +} + +message CreateReviewRequest { + string product_id = 1; + string customer_id = 2; + int32 rating = 3; + string title = 4; + string body = 5; + repeated string image_urls = 6; + map aspect_ratings = 7; +} + +message ListReviewsRequest { + string product_id = 1; + PaginationRequest pagination = 2; + int32 min_rating = 3; + bool verified_only = 4; + bool with_images_only = 5; + + oneof sort_by { + bool sort_by_date = 6; + bool sort_by_rating = 7; + bool sort_by_helpful = 8; + } +} + +message ListReviewsResponse { + repeated Review reviews = 1; + PaginationResponse pagination = 2; + float average_rating = 3; + map rating_distribution = 4; + map aspect_averages = 5; +} + +// ─── Inventory / Streaming Messages ────────────────── + +message InventoryUpdate { + string product_id = 1; + string variant_id = 2; + int32 previous_quantity = 3; + int32 new_quantity = 4; + int32 delta = 5; + Timestamp timestamp = 6; + + oneof trigger { + string order_id = 7; + string import_batch_id = 8; + string manual_adjustment_by = 9; + string return_id = 10; + } +} + +message WatchInventoryRequest { + repeated string product_ids = 1; + bool low_stock_only = 2; + int32 low_stock_threshold = 3; + bool include_variant_detail = 4; +} + +message PriceWatchRequest { + repeated string product_ids = 1; + Money max_price = 2; + bool notify_on_any_change = 3; +} + +message PriceChangeEvent { + string product_id = 1; + string variant_id = 2; + Money old_price = 3; + Money new_price = 4; + float change_percentage = 5; + Timestamp changed_at = 6; + string reason = 7; +} + +message ChatMessage { + string session_id = 1; + string sender_id = 2; + Timestamp sent_at = 3; + + oneof content { + string text = 4; + ImageAttachment image = 5; + OrderReference order_ref = 6; + ProductReference product_ref = 7; + QuickAction action = 8; + } + + message ImageAttachment { + string url = 1; + string caption = 2; + int32 width = 3; + int32 height = 4; + } + + message OrderReference { + string order_id = 1; + OrderStatus status = 2; + string summary = 3; + } + + message ProductReference { + string product_id = 1; + string name = 2; + Money price = 3; + string image_url = 4; + } + + message QuickAction { + string action_type = 1; + map params = 2; + string display_text = 3; + } +} + +message Notification { + string id = 1; + string user_id = 2; + NotificationType type = 3; + string title = 4; + string body = 5; + Timestamp created_at = 6; + bool read = 7; + map data = 8; + + oneof reference { + string order_id = 9; + string product_id = 10; + string review_id = 11; + string promotion_id = 12; + } +} + +message SubscribeNotificationsRequest { + string user_id = 1; + repeated NotificationType types = 2; +} + +message AnalyticsEvent { + string event_id = 1; + string session_id = 2; + string user_id = 3; + Timestamp timestamp = 4; + map properties = 5; + + oneof event { + PageView page_view = 6; + ProductView product_view = 7; + CartAction cart_action = 8; + SearchAction search_action = 9; + CheckoutStep checkout_step = 10; + } + + message PageView { + string url = 1; + string referrer = 2; + int32 duration_ms = 3; + } + + message ProductView { + string product_id = 1; + string source = 2; + int32 position_in_list = 3; + } + + message CartAction { + string product_id = 1; + int32 quantity = 2; + string action = 3; + } + + message SearchAction { + string query = 1; + int32 results_count = 2; + int32 page = 3; + repeated string filters_used = 4; + } + + message CheckoutStep { + int32 step = 1; + string step_name = 2; + Money cart_total = 3; + int32 item_count = 4; + } +} + +message AnalyticsAck { + string event_id = 1; + bool accepted = 2; +} + +message HealthCheckRequest { + string service_name = 1; +} + +message HealthCheckResponse { + string service_name = 1; + bool healthy = 2; + string version = 3; + int64 uptime_seconds = 4; + map components = 5; + + message ComponentHealth { + bool healthy = 1; + string message = 2; + int64 latency_ms = 3; + } +} + +// ─── Services ──────────────────────────────────────── + +// Unary + Server Streaming +service ProductService { + // Unary + rpc GetProduct(GetProductRequest) returns (Product); + rpc CreateProduct(CreateProductRequest) returns (Product); + rpc DeleteProduct(DeleteProductRequest) returns (Empty); + rpc BatchGetProducts(BatchGetProductsRequest) returns (BatchGetProductsResponse); + + // Unary (search) + rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse); + + // Unary (update with oneof) + rpc UpdateProduct(UpdateProductRequest) returns (Product); + + // Server streaming: watch prices + rpc WatchPrices(PriceWatchRequest) returns (stream PriceChangeEvent); + + // Client streaming: bulk import + rpc ImportProducts(stream ProductImportRecord) returns (ProductImportSummary); +} + +// Unary + Server Streaming +service OrderService { + // Unary + rpc CreateOrder(CreateOrderRequest) returns (Order); + rpc GetOrder(GetOrderRequest) returns (Order); + rpc ListOrders(ListOrdersRequest) returns (ListOrdersResponse); + rpc UpdateOrderStatus(UpdateOrderStatusRequest) returns (Order); + rpc CancelOrder(CancelOrderRequest) returns (Order); + + // Server streaming: live order tracking + rpc TrackOrder(GetOrderRequest) returns (stream OrderEvent); +} + +// Unary +service ReviewService { + rpc CreateReview(CreateReviewRequest) returns (Review); + rpc ListReviews(ListReviewsRequest) returns (ListReviewsResponse); +} + +// All streaming patterns +service RealtimeService { + // Server streaming: inventory changes + rpc WatchInventory(WatchInventoryRequest) returns (stream InventoryUpdate); + + // Server streaming: push notifications + rpc SubscribeNotifications(SubscribeNotificationsRequest) returns (stream Notification); + + // Bidirectional streaming: customer support chat + rpc CustomerSupportChat(stream ChatMessage) returns (stream ChatMessage); + + // Client streaming: analytics event ingestion + rpc IngestAnalytics(stream AnalyticsEvent) returns (AnalyticsAck); +} + +// Unary utility +service HealthService { + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); +} diff --git a/demo/models/grpc-simple/grpc-simple.proto b/demo/models/grpc-simple/grpc-simple.proto new file mode 100644 index 000000000..4f59f0d55 --- /dev/null +++ b/demo/models/grpc-simple/grpc-simple.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package greeter; + +service GreeterService { + rpc SayHello(HelloRequest) returns (HelloResponse); + rpc SayGoodbye(GoodbyeRequest) returns (GoodbyeResponse); +} + +message HelloRequest { + string name = 1; + int32 age = 2; +} + +message HelloResponse { + string greeting = 1; + bool success = 2; +} + +message GoodbyeRequest { + string name = 1; +} + +message GoodbyeResponse { + string farewell = 1; +} diff --git a/demo/models/oas-301-api/oas-301-api.yaml b/demo/models/oas-301-api/oas-301-api.yaml new file mode 100644 index 000000000..a5366ddcd --- /dev/null +++ b/demo/models/oas-301-api/oas-301-api.yaml @@ -0,0 +1,330 @@ +openapi: "3.0.1" +info: + title: Bookstore API + description: A sample OAS 3.0.1 API for testing api-console parsing + version: "1.0.0" + contact: + name: API Console Team + email: arc@mulesoft.com + +servers: + - url: https://api.bookstore.example.com/v1 + description: Production + - url: https://staging-api.bookstore.example.com/v1 + description: Staging + +paths: + /books: + get: + operationId: listBooks + summary: List all books + description: Returns a paginated list of books + tags: + - Books + parameters: + - name: page + in: query + description: Page number + required: false + schema: + type: integer + default: 1 + minimum: 1 + - name: limit + in: query + description: Items per page + required: false + schema: + type: integer + default: 20 + minimum: 1 + maximum: 100 + - name: genre + in: query + description: Filter by genre + required: false + schema: + type: string + enum: + - fiction + - non-fiction + - science + - history + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: "#/components/schemas/Book" + pagination: + $ref: "#/components/schemas/Pagination" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + operationId: createBook + summary: Create a new book + tags: + - Books + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/BookInput" + responses: + "201": + description: Book created + content: + application/json: + schema: + $ref: "#/components/schemas/Book" + "422": + description: Validation error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + /books/{bookId}: + parameters: + - name: bookId + in: path + required: true + description: The book ID + schema: + type: string + format: uuid + get: + operationId: getBook + summary: Get a book by ID + tags: + - Books + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: "#/components/schemas/Book" + "404": + description: Book not found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + put: + operationId: updateBook + summary: Update a book + tags: + - Books + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/BookInput" + responses: + "200": + description: Book updated + content: + application/json: + schema: + $ref: "#/components/schemas/Book" + delete: + operationId: deleteBook + summary: Delete a book + tags: + - Books + responses: + "204": + description: Book deleted + "404": + description: Book not found + + /books/{bookId}/reviews: + parameters: + - name: bookId + in: path + required: true + schema: + type: string + format: uuid + get: + operationId: listReviews + summary: List reviews for a book + tags: + - Reviews + responses: + "200": + description: List of reviews + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Review" + post: + operationId: createReview + summary: Add a review + tags: + - Reviews + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ReviewInput" + responses: + "201": + description: Review created + content: + application/json: + schema: + $ref: "#/components/schemas/Review" + "401": + description: Unauthorized + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + Book: + type: object + required: + - id + - title + - author + properties: + id: + type: string + format: uuid + title: + type: string + example: "The Great Gatsby" + author: + type: string + example: "F. Scott Fitzgerald" + isbn: + type: string + pattern: "^\\d{13}$" + example: "9780743273565" + genre: + type: string + enum: + - fiction + - non-fiction + - science + - history + publishedDate: + type: string + format: date + price: + type: number + format: float + minimum: 0 + inStock: + type: boolean + default: true + + BookInput: + type: object + required: + - title + - author + properties: + title: + type: string + minLength: 1 + maxLength: 255 + author: + type: string + minLength: 1 + isbn: + type: string + pattern: "^\\d{13}$" + genre: + type: string + enum: + - fiction + - non-fiction + - science + - history + publishedDate: + type: string + format: date + price: + type: number + format: float + minimum: 0 + + Review: + type: object + properties: + id: + type: string + format: uuid + bookId: + type: string + format: uuid + rating: + type: integer + minimum: 1 + maximum: 5 + comment: + type: string + createdAt: + type: string + format: date-time + + ReviewInput: + type: object + required: + - rating + properties: + rating: + type: integer + minimum: 1 + maximum: 5 + comment: + type: string + maxLength: 1000 + + Pagination: + type: object + properties: + page: + type: integer + limit: + type: integer + total: + type: integer + totalPages: + type: integer + + Error: + type: object + properties: + code: + type: string + message: + type: string + details: + type: array + items: + type: string diff --git a/docs/team/README.md b/docs/team/README.md new file mode 100644 index 000000000..49404e584 --- /dev/null +++ b/docs/team/README.md @@ -0,0 +1,43 @@ +# Team Documentation - api-console v6 + +Console-specific runbooks, patterns, and configs for contributing to this open-source project. + +**General guidelines**: See [acm-dot-agents/docs/team-guide.md](https://github.com/mulesoft-labs-emu/acm-dot-agents/blob/main/docs/team-guide.md) for team-wide standards. + +--- + +## What's Here + +### runbooks/ +Console-specific operational procedures: +- **Release process**: api-console v6 release workflow, version bumping +- **Debugging Shadow DOM**: Troubleshooting Web Component issues, custom events +- **AMF model issues**: Parser errors, model generation, JSON-LD troubleshooting +- **Visual regression**: Updating baselines, screenshot comparison +- **Component updates**: Updating workspace dependencies, npm packages + +### patterns/ +Console-specific architectural decisions: +- Web Component communication (custom events vs properties) +- AmfHelperMixin usage patterns +- Shadow DOM styling with CSS custom properties +- Lazy loading strategies for large APIs +- Multi-package workspace conventions + +### configs/ +Local development configs: +- Git GPG setup (MuleSoft repos require @mulesoft.com signature) +- IDE settings for Web Components +- ESLint/Prettier configs +- @web/test-runner settings + +### onboarding/ +New contributor guides specific to console v6 architecture + +--- + +## Quick Reference + +**Workflow**: Draft in `.claude/investigations/` → Promote to `docs/team/runbooks/` when resolved +**Team guide**: [acm-dot-agents/docs/team-guide.md](https://github.com/mulesoft-labs-emu/acm-dot-agents/blob/main/docs/team-guide.md) +**Questions?** Open issue on GitHub or ping @advanced-rest-client diff --git a/docs/team/configs/README.md b/docs/team/configs/README.md new file mode 100644 index 000000000..8f84d8bb8 --- /dev/null +++ b/docs/team/configs/README.md @@ -0,0 +1,98 @@ +# Team Configuration Files + +> Shared configuration files for development tools and team workflows + +--- + +## Purpose + +This folder contains team-wide configuration files that are: +- ✅ **Committed to Git** (shared with all team members) +- ✅ **IDE/tool agnostic** (or include examples for multiple tools) +- ✅ **Stable and tested** (not experimental) + +**Not for**: +- ❌ Personal preferences (use your own local configs) +- ❌ Sensitive data (credentials, tokens, etc.) +- ❌ Auto-generated files (build artifacts, etc.) + +--- + +## Structure + +``` +configs/ +├── README.md # This file +├── .editorconfig # Cross-IDE formatting (indent, EOL, etc.) +├── .eslintrc.example # Example ESLint config for new team members +└── prettier.example.json # Example Prettier config (if team uses it) +``` + +--- + +## How to Use + +### For New Team Members + +1. Review existing config files in this folder +2. Copy example files to your local workspace (if needed) +3. Customize for your personal workflow +4. **Do NOT commit personal customizations back here** + +### For Team Leads + +When adding a new config: +1. Verify it works across different environments (macOS, Linux, Windows) +2. Document what the config does and why it's needed +3. Get team consensus before committing (PR review) +4. Update this README if adding a new file type + +--- + +## Examples + +### ESLint Config + +If the team agrees on ESLint rules, add `.eslintrc.example`: +```json +{ + "extends": ["eslint:recommended"], + "rules": { + "no-console": "warn", + "semi": ["error", "always"] + } +} +``` + +Team members copy to `.eslintrc.json` (which is in `.gitignore`). + +### EditorConfig + +Cross-IDE formatting rules (works in VS Code, IntelliJ, etc.): +```ini +# .editorconfig +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +``` + +This file is committed as `.editorconfig` (no `.example` needed). + +--- + +## Related + +- **`.claude/`**: Personal AI assistant files (NOT committed, see `.gitignore`) +- **`docs/team/patterns/`**: Code patterns and architectural decisions +- **`docs/team/runbooks/`**: Operational procedures and debugging guides + +--- + +**Last Updated**: 2026-03-03 +**Owner**: ACM Team diff --git a/docs/team/configs/git-gpg-setup.md b/docs/team/configs/git-gpg-setup.md new file mode 100644 index 000000000..d95d4e774 --- /dev/null +++ b/docs/team/configs/git-gpg-setup.md @@ -0,0 +1,338 @@ +# Git & GPG Configuration for MuleSoft/Salesforce Repos + +> **Purpose**: Configure Git to sign commits with correct email and GPG key +> **Applies to**: All team members working on MuleSoft and Salesforce repositories +> **Last Updated**: 2026-03-04 + +--- + +## Why This Matters + +Different repository organizations require different Git configurations: + +| Repo Organization | Example Repos | Required Email | GPG Required | +|-------------------|---------------|----------------|--------------| +| `mulesoft/*` | api-console, api-console-lwc | `yourname@mulesoft.com` | ✅ Yes | +| `mulesoft-emu/*` | anypoint-api-console | `yourname@salesforce.com` | ✅ Yes | +| `advanced-rest-client/*` | api-navigation, api-type-document | `yourname@mulesoft.com` | ✅ Yes | +| `anypoint-web-components/*` | anypoint-button, anypoint-input | `yourname@mulesoft.com` | ✅ Yes | + +**Consequences of wrong configuration**: +- ❌ Commits rejected by GitHub (wrong email) +- ❌ GPG verification fails +- ❌ Git history shows incorrect author +- ❌ Can't push to protected branches + +--- + +## Option 1: Manual Configuration (Per Repo) + +### For MuleSoft Repos (`mulesoft/*`, `advanced-rest-client/*`, `anypoint-web-components/*`) + +```bash +cd /path/to/mulesoft/repo + +# Set email +git config user.email "yourname@mulesoft.com" + +# Set GPG signing key (replace with YOUR key ID) +git config user.signingkey YOUR_GPG_KEY_ID + +# Enable signing +git config commit.gpgsign true +``` + +**Find your GPG key ID**: +```bash +gpg --list-secret-keys --keyid-format=long +# Look for something like: sec rsa4096/ABCD1234EFGH5678 +# The key ID is: ABCD1234EFGH5678 +``` + +--- + +### For Salesforce EMU Repos (`mulesoft-emu/*`) + +```bash +cd /path/to/mulesoft-emu/repo + +# Set email +git config user.email "yourname@salesforce.com" + +# Set GPG signing key (may be same or different from MuleSoft key) +git config user.signingkey YOUR_GPG_KEY_ID + +# Enable signing +git config commit.gpgsign true +``` + +--- + +## Option 2: Shell Aliases (Recommended for Frequent Switching) + +If you frequently switch between MuleSoft and Salesforce repos, create aliases: + +### Setup + +Add to your `~/.zshrc` or `~/.bashrc`: + +```bash +# MuleSoft repos configuration +alias mulesoft-git='git config user.email "yourname@mulesoft.com" && git config user.signingkey YOUR_MULESOFT_GPG_KEY && echo "✅ Configured for MuleSoft repos"' + +# Salesforce EMU repos configuration +alias salesforce-git='git config user.email "yourname@salesforce.com" && git config user.signingkey YOUR_SALESFORCE_GPG_KEY && echo "✅ Configured for Salesforce EMU repos"' +``` + +**Replace**: +- `yourname@mulesoft.com` → Your MuleSoft email +- `yourname@salesforce.com` → Your Salesforce email +- `YOUR_MULESOFT_GPG_KEY` → Your GPG key ID (from `gpg --list-keys`) +- `YOUR_SALESFORCE_GPG_KEY` → Same or different GPG key + +**Reload shell**: +```bash +source ~/.zshrc # or source ~/.bashrc +``` + +### Usage + +Before committing in any repo: + +```bash +# In mulesoft/* repos +cd ~/mulesoft/context/products/api-console/v6/api-console +mulesoft-git +git commit -m "fix: something" + +# In mulesoft-emu/* repos +cd ~/mulesoft/context/products/api-console/wrapper +salesforce-git +git commit -m "chore: update dependency" +``` + +--- + +## Option 3: Directory-Based Configuration (Advanced) + +Use `.gitconfig` includes to automatically apply config based on directory: + +### Setup + +Edit `~/.gitconfig`: + +```ini +[includeIf "gitdir:~/mulesoft/"] + path = ~/.gitconfig-mulesoft + +[includeIf "gitdir:~/salesforce/"] + path = ~/.gitconfig-salesforce +``` + +Create `~/.gitconfig-mulesoft`: + +```ini +[user] + email = yourname@mulesoft.com + signingkey = YOUR_MULESOFT_GPG_KEY + +[commit] + gpgsign = true +``` + +Create `~/.gitconfig-salesforce`: + +```ini +[user] + email = yourname@salesforce.com + signingkey = YOUR_SALESFORCE_GPG_KEY + +[commit] + gpgsign = true +``` + +**Benefit**: No manual switching! Git automatically uses correct config based on repo location. + +--- + +## Verification + +### Check Current Configuration + +```bash +# Show current email +git config user.email + +# Show current signing key +git config user.signingkey + +# Show if signing is enabled +git config commit.gpgsign +``` + +### Verify Last Commit Signature + +```bash +git log --show-signature -1 +``` + +**Expected output**: +``` +gpg: Signature made [date] +gpg: Good signature from "Your Name " [ultimate] +commit abc123def456... +Author: Your Name +``` + +**If signature is wrong**: +```bash +# Fix config +mulesoft-git # or salesforce-git + +# Amend last commit with new signature +git commit --amend --no-edit -S + +# Verify again +git log --show-signature -1 +``` + +--- + +## GPG Setup (First Time Only) + +If you don't have a GPG key yet: + +### 1. Generate GPG Key + +```bash +gpg --full-generate-key +``` + +**Prompts**: +- Key type: RSA (default) +- Key size: 4096 +- Expiration: 0 (no expiration, or set to 2 years) +- Real name: Your Name +- Email: `yourname@mulesoft.com` (or `yourname@salesforce.com`) + +### 2. List Keys + +```bash +gpg --list-secret-keys --keyid-format=long +``` + +**Output**: +``` +sec rsa4096/ABCD1234EFGH5678 2024-01-01 [SC] +uid [ultimate] Your Name +``` + +**Your key ID**: `ABCD1234EFGH5678` + +### 3. Export Public Key + +```bash +gpg --armor --export ABCD1234EFGH5678 +``` + +Copy the output (including `-----BEGIN PGP PUBLIC KEY BLOCK-----` and `-----END PGP PUBLIC KEY BLOCK-----`) + +### 4. Add to GitHub + +1. Go to GitHub → Settings → SSH and GPG keys +2. Click "New GPG key" +3. Paste your public key +4. Save + +### 5. Configure Git + +```bash +git config --global user.signingkey ABCD1234EFGH5678 +git config --global commit.gpgsign true +``` + +--- + +## Common Issues + +### Issue: "failed to sign the data" + +**Cause**: GPG agent not running or key not found. + +**Solution**: +```bash +# Test GPG signing +echo "test" | gpg --clearsign + +# If fails, restart GPG agent +gpgconf --kill gpg-agent +gpgconf --launch gpg-agent + +# Try commit again +``` + +--- + +### Issue: Commit shows wrong author email + +**Cause**: Global Git config overrides repo config. + +**Solution**: +```bash +# Check what's configured +git config --list --show-origin | grep user.email + +# If global is wrong, fix with alias +mulesoft-git # or salesforce-git + +# OR set per-repo +git config user.email "yourname@mulesoft.com" +``` + +--- + +### Issue: "no secret key" error + +**Cause**: Git is configured with a key ID that doesn't exist in your GPG keyring. + +**Solution**: +```bash +# List your available keys +gpg --list-secret-keys --keyid-format=long + +# Configure with correct key ID +git config user.signingkey CORRECT_KEY_ID +``` + +--- + +## Quick Reference + +| Action | Command | +|--------|---------| +| Check current email | `git config user.email` | +| Check signing key | `git config user.signingkey` | +| List GPG keys | `gpg --list-secret-keys --keyid-format=long` | +| Verify last commit | `git log --show-signature -1` | +| Amend commit signature | `git commit --amend --no-edit -S` | +| Configure for MuleSoft | `mulesoft-git` (if alias exists) | +| Configure for Salesforce | `salesforce-git` (if alias exists) | + +--- + +## Team Members: Share Your Config + +If you've set up aliases or directory-based config, consider sharing your approach in #api-console-cloud-sync or #acm-team to help others! + +--- + +## Related Documentation + +- **GitHub GPG Setup**: https://docs.github.com/en/authentication/managing-commit-signature-verification +- **GPG Cheat Sheet**: https://github.com/NicoHood/gpg-key +- **.gitconfig Examples**: See `docs/team/configs/gitconfig-examples/` + +--- + +**Last Updated**: 2026-03-04 +**Maintainer**: ACM Team diff --git a/docs/team/onboarding/api-console-v6.md b/docs/team/onboarding/api-console-v6.md new file mode 100644 index 000000000..c9a7c0dd0 --- /dev/null +++ b/docs/team/onboarding/api-console-v6.md @@ -0,0 +1,334 @@ +# API Console v6 - Onboarding + +> **Last Updated**: 2026-03-02 +> **Maintainer**: ACM Team (API Community Manager) +> **Version**: 6.6.x + +--- + +## What is API Console? + +API Console is an interactive documentation tool that automatically generates API documentation from RAML, OAS (OpenAPI), AsyncAPI, and gRPC specifications. It's similar to Postman but embedded directly in web applications. + +**Key Features**: +- **API Navigation**: Tree view of endpoints, methods, types +- **API Documentation**: Detailed docs for each endpoint/method +- **API Request Panel**: "Try it" functionality to test endpoints +- **Multi-spec support**: RAML, OAS 2/3, AsyncAPI, gRPC (read-only) + +**Used by**: +- Anypoint Platform (Exchange, API Designer) +- API Community Manager (ACM) +- APIKit +- Multiple MuleSoft + Salesforce products + +--- + +## Architecture Overview + +### Two Versions + +| Version | Tech Stack | Purpose | Repo | +|---------|-----------|---------|------| +| **v6** | LitElement, Web Components | Open source, used in most products | `mulesoft/api-console` | +| **v7** | Lightning Web Components (LWC) | Salesforce Experience Cloud only | `mulesoft/api-console-lwc` | + +This document focuses on **v6**. + +### Two Usage Modes + +**1. Standalone Application** (`ApiConsoleApp`) +- Full app with routing, layout, navigation drawer +- Entry point: `src/ApiConsoleApp.js` +- Demo: `demo/standalone/index.html` + +**2. Web Component** (`ApiConsole`) +- Embeddable component (no routing/layout) +- Entry point: `src/ApiConsole.js` +- Host app provides layout and navigation +- Demo: `demo/element/index.html` + +### Component Hierarchy + +``` +ApiConsoleApp (extends ApiConsole) +└── ApiConsole (extends AmfHelperMixin(LitElement)) + ├── api-navigation (left drawer) + ├── api-documentation (main content) + ├── api-request-panel (try it panel) + └── Helper components: + ├── xhr-simple-request + ├── oauth1-authorization + └── oauth2-authorization +``` + +--- + +## AMF Model Architecture + +**CRITICAL**: API Console does NOT parse API specs directly. It requires a pre-generated **AMF model**. + +### What is AMF? + +**AMF (AML Modeling Framework)**: MuleSoft's unified model for RAML, OAS, AsyncAPI, and gRPC. +- **Format**: JSON-LD +- **Version**: v6.0.0+ requires AMF v4.0.0+ (AMF model v2) +- **Generator**: `@api-components/api-model-generator` + +### AMF Concepts + +**Declares**: Types, components, schemas +**Endpoints**: API paths +**Operations**: HTTP methods (GET, POST, PUT, DELETE, etc.) + +### Model Flow + +``` +API Spec (RAML/OAS/AsyncAPI/gRPC) + → AMF Parser (amf-client-js) + → AMF Model (JSON-LD) + → api-console `amf` property + → AmfHelperMixin provides querying utilities + → Renders documentation/navigation/request panel +``` + +**More info**: https://a.ml/docs/ + +--- + +## Repository Structure + +### Main Repos + +**1. `mulesoft/api-console`** (this repo) +- Main integrator component +- Version: 6.6.x +- Depends on: Individual components from `advanced-rest-client` org +- Release cycle: Every 3 weeks on Fridays + +**2. `mulesoft/anypoint-api-console`** +- Builder for Anypoint Platform-specific bundle +- Wraps `api-console` with custom configurations +- Location: `builder/package.json` references `api-console` version + +**3. `advanced-rest-client/*` (GitHub org)** +- Individual Web Components used by api-console +- Examples: + - `api-navigation` + - `api-summary` + - `api-type-document` + - `api-documentation` + - `api-request` +- Each is a separate npm package (`@api-components/`) + +### Monorepo Structure (api-console) + +``` +api-console/ +├── src/ +│ ├── ApiConsole.js # Base web component +│ ├── ApiConsoleApp.js # Standalone app +│ └── styles/ # Component styles +├── demo/ +│ ├── apis.json # API definitions for demos +│ ├── models/ # Generated AMF models (gitignored) +│ ├── vendor.js # Non-ES6 dependencies (generated) +│ └── model.js # Script to generate AMF models +├── test/ +│ ├── *.test.js # Unit tests +│ └── visual/ # Visual regression tests +├── docs/team/ # Team documentation +│ ├── onboarding/ # Onboarding docs (this file) +│ ├── runbooks/ # Operational procedures +│ └── patterns/ # Architectural decisions +└── .claude/ # Claude Code working files (gitignored) + ├── skills/ # Automation skills + └── investigations/ # Bug analysis files +``` + +--- + +## Tech Stack + +### Core Technologies + +- **LitElement 2.x**: Base class for Web Components +- **Web Components**: Custom elements with Shadow DOM +- **AMF**: API modeling framework +- **Polymer**: Legacy components (being phased out) +- **CodeMirror**: Code editor (bundled in vendor.js) + +### Testing + +- **@web/test-runner**: Test framework (NOT Jest - Jest has poor Shadow DOM support) +- **Playwright**: Browser automation (chromium + firefox) +- **Visual regression**: `@web/test-runner-visual-regression` + +### Build & Dev + +- **Rollup**: Production bundler +- **web-dev-server**: Development server +- **npm workspaces**: Monorepo (v6 only, not for individual components) + +--- + +## API Specification Support + +| Spec | Version | Support Level | Try It Panel | +|------|---------|---------------|--------------| +| **RAML** | 0.8, 1.0 | ✅ Full | ✅ Yes | +| **OAS** | 2.0, 3.0 | ✅ Full | ✅ Yes | +| **AsyncAPI** | 2.x | ✅ Read-only | ❌ No (not REST) | +| **gRPC** | Proto3 | ✅ Read-only | ❌ No (RPC protocol) | + +**Note**: gRPC and AsyncAPI are auto-detected and hide the "Try it" panel. + +--- + +## Related Teams & Contacts + +| Team | Point of Contact | Responsibility | +|------|------------------|----------------| +| **API Designer** | Leandro Bauret (Dev)
Eduardo Cominguez (Manager) | Consumes api-console in Designer | +| **Exchange** | Nicolas Escalante (Dev)
Mariano Campo (Manager) | API documentation display | +| **AMF** | Nicolas Schejtman (Dev)
Martin Gutierrez (Manager) | AMF parser and model | +| **APIkit** | Chakravarthy Parankusam (Manager) | Runtime API implementation | +| **Mocking Service** | Roberto Ciccone (Dev)
Diego Macias (Manager) | API mocking | +| **ACM Team** | #acm-team (Slack) | Maintains v6 and v7 | + +--- + +## Essential Commands + +### First-time Setup + +```bash +git clone git@github.com:mulesoft/api-console.git +cd api-console +npm install +npm run prepare # Build vendor.js + generate AMF models +``` + +**⚠️ Important**: Always run `npm run prepare` after cloning. It builds non-ES6 dependencies (vendor.js) and generates demo models. + +### Development + +```bash +npm start # Dev server at demo/index.html +npm run start:server # Parsing server with debug +npm run build:models # Generate AMF models from demo/apis.json +``` + +### Testing + +```bash +npm test # All tests (unit + visual regression) +npm run test:watch # Watch mode (chromium only) +npm run test:visual # Visual regression only +npm run test:visual:update # Update visual baselines +``` + +### Building + +```bash +npm run build # Production build to dist/ +npm run build:vendor # Build vendor.js (CodeMirror + crypto) +``` + +--- + +## Learning Resources + +### Documentation + +- **Full docs**: https://docs.api-console.io +- **AMF**: https://a.ml/docs/ +- **AMF GitHub**: https://github.com/aml-org/amf +- **API Components**: https://github.com/advanced-rest-client +- **LitElement**: https://lit.dev/docs/v1/ + +### Specifications + +- **RAML**: https://raml.org/ +- **OAS**: https://swagger.io/specification/ +- **AsyncAPI**: https://www.asyncapi.com/docs/reference/specification + +### Internal Resources + +- **Onboarding meetings**: + - Part 1: APIC basics + - Part 2: Troubleshooting example +- **Figma designs**: Authorization migration +- **Slack**: #api-console-cloud-sync (releases), #api-line (general) + +--- + +## Development Workflow + +### Typical Development Flow + +1. **Clone repo** + run `npm run prepare` +2. **Create feature branch** (NEVER commit to master directly) +3. **Make changes** to components +4. **Test locally**: `npm start` + manual testing +5. **Run tests**: `npm test` (must pass) +6. **Create PR** via GitHub web UI (gh CLI doesn't work with EMU) +7. **Wait for review** + CI checks (Linux + Windows) +8. **Merge** → Auto-publishes to npm (if version bumped) + +### Git & GPG Requirements + +**⚠️ CRITICAL**: This is a `mulesoft/*` repository. Before committing: + +```bash +mulesoft-git # Configure GPG signing with alexperez@mulesoft.com +``` + +**Verify signature**: +```bash +git log --show-signature -1 +``` + +**Must show**: `Good signature from "alexp mule "` + +--- + +## Common Pitfalls + +### DON'T: +- ❌ Commit directly to master/main (always create branch) +- ❌ Forget to run `mulesoft-git` before committing +- ❌ Use Jest for testing (use @web/test-runner) +- ❌ Parse API files directly (use AMF model) +- ❌ Modify AMF model structure (it's an external standard) +- ❌ Import CodeMirror/crypto as ES modules (use vendor.js) +- ❌ Use `gh pr create` (EMU account doesn't work with mulesoft/* repos) + +### DO: +- ✅ Run `npm run prepare` after cloning +- ✅ Run `mulesoft-git` before committing +- ✅ Test in both chromium and firefox (visual differences exist) +- ✅ Use `AmfHelperMixin` utilities for AMF querying +- ✅ Create PR via GitHub web UI +- ✅ Update visual regression baselines when UI changes intentionally + +--- + +## Next Steps + +After reading this onboarding: + +1. **Read**: `docs/team/runbooks/api-console-v6-release.md` - Learn release process +2. **Read**: `docs/team/runbooks/api-console-v6-troubleshooting.md` - Common issues +3. **Read**: `docs/team/patterns/api-console-architecture.md` - Technical decisions +4. **Clone repo** + run through essential commands +5. **Join Slack**: #api-console-cloud-sync, #api-line +6. **Ask questions**: Tag @alexperez or team in Slack + +--- + +## Questions? + +- **Slack**: #api-line (general), #acm-team (internal) +- **GitHub Issues**: https://github.com/mulesoft/api-console/issues +- **Email**: arc@mulesoft.com diff --git a/docs/team/patterns/00-web-component-communication.md b/docs/team/patterns/00-web-component-communication.md new file mode 100644 index 000000000..13bf03280 --- /dev/null +++ b/docs/team/patterns/00-web-component-communication.md @@ -0,0 +1,191 @@ +# Pattern: Web Component Communication + +**Date**: 2026-02-26 +**Author**: ACM Team +**Status**: Accepted +**Applies to**: All Web Components in api-console + +--- + +## Problem + +Web Components in api-console need to communicate with each other: +- Parent → Child: Pass data down +- Child → Parent: Notify of events +- Sibling → Sibling: Share state + +Without clear patterns, components become tightly coupled and hard to test. + +--- + +## Solution + +Use **Properties + Custom Events** pattern: + +``` +┌─────────────────────────────────────┐ +│ Parent Component │ +│ - Sets properties on children │ +│ - Listens to custom events │ +└──────────────┬──────────────────────┘ + │ + │ properties (down) + ▼ +┌─────────────────────────────────────┐ +│ Child Component │ +│ - Receives data via @property │ +│ - Emits custom events (up) │ +└─────────────────────────────────────┘ +``` + +--- + +## Implementation + +### Parent → Child (Properties) + +**Parent sets property**: +```javascript +// parent-component.js +import { LitElement, html } from 'lit-element'; + +class ParentComponent extends LitElement { + render() { + return html` + + + `; + } +} +``` + +**Child receives property**: +```javascript +// api-navigation.js +import { LitElement, html } from 'lit-element'; + +class ApiNavigation extends LitElement { + static get properties() { + return { + amf: { type: Object }, + selected: { type: String } + }; + } + + updated(changedProps) { + if (changedProps.has('amf')) { + this._processAmf(this.amf); + } + } +} +``` + +### Child → Parent (Custom Events) + +**Child dispatches event**: +```javascript +// api-navigation.js +_handleSelection(endpointId) { + this.dispatchEvent(new CustomEvent('api-navigation-selection-changed', { + bubbles: true, + composed: true, + detail: { selected: endpointId } + })); +} +``` + +**Parent listens to event**: +```javascript +// parent-component.js +render() { + return html` + + + `; +} + +_onSelectionChanged(e) { + this.selectedId = e.detail.selected; +} +``` + +### Sibling → Sibling (Shared State) + +**Option 1: State in parent** (preferred for simple cases): +```javascript +// parent manages state, passes to both children +class ParentComponent extends LitElement { + render() { + return html` + + + + + + `; + } +} +``` + +**Option 2: Event bus** (for complex cases): +```javascript +// Avoid unless absolutely necessary - harder to debug +``` + +--- + +## Rules + +### ✅ DO +- Use `.property` syntax for Object/Array properties (not attributes) +- Use `bubbles: true, composed: true` for events that cross shadow DOM +- Prefix event names with component name (`api-navigation-*`) +- Document event details in JSDoc +- Keep event payloads simple (primitives, plain objects) + +### ❌ DON'T +- Don't access child component methods directly (`this.querySelector('api-nav').selectEndpoint()`) +- Don't use global variables for component communication +- Don't mutate objects passed as properties (create new objects instead) +- Don't listen to events on `window` unless truly global + +--- + +## Example from Codebase + +See `api-console/src/ApiConsole.js` for complete parent-child pattern: +- Properties: `amf`, `selected`, `baseUri` +- Events: `api-navigation-selection-changed`, `api-request-send` + +--- + +## Testing + +```javascript +import { fixture, html } from '@open-wc/testing'; + +it('emits selection event when item clicked', async () => { + const el = await fixture(html``); + + setTimeout(() => el._handleSelection('endpoint-1')); + const event = await oneEvent(el, 'api-navigation-selection-changed'); + + expect(event.detail.selected).to.equal('endpoint-1'); +}); +``` + +--- + +## Related +- [Shadow DOM Styling Pattern](./01-shadow-dom-styling.md) +- [AMF Integration Pattern](./02-amf-integration.md) + +--- + +**Last Updated**: 2026-02-26 diff --git a/docs/team/patterns/api-console-architecture.md b/docs/team/patterns/api-console-architecture.md new file mode 100644 index 000000000..0d8f4ba38 --- /dev/null +++ b/docs/team/patterns/api-console-architecture.md @@ -0,0 +1,448 @@ +# API Console v6 - Architecture Patterns + +> **Last Updated**: 2026-03-02 +> **Purpose**: Document key architectural decisions and technical patterns + +--- + +## Architectural Decisions + +### ADR-001: Why AMF Instead of Direct Parsing? + +**Decision**: API Console consumes pre-generated AMF models instead of parsing API specs directly. + +**Context**: +- API specs can be complex (RAML, OAS 2/3, AsyncAPI, gRPC) +- Parsing logic is non-trivial (includes, fragments, inheritance) +- Parsing performance can be slow for large APIs + +**Decision**: +- Use AMF (API Modeling Framework) as unified model +- Require pre-generated JSON-LD models +- Console only renders, doesn't parse + +**Consequences**: + +**Pros**: +- ✅ Single model format for all spec types +- ✅ Faster console load (no parse time) +- ✅ Parsing logic maintained by AMF team +- ✅ Consistent rendering across spec types + +**Cons**: +- ❌ Extra step required (generate AMF model first) +- ❌ Tight coupling to AMF version +- ❌ Cannot handle spec updates without regenerating model + +**Status**: ✅ Active + +--- + +### ADR-002: Monorepo vs Separate Component Repos + +**Decision**: Console integrator (`api-console`) and individual components (`@api-components/*`) are in separate repos. + +**Context**: +- Console uses 18+ components (navigation, docs, request, etc.) +- Components reused across multiple products (Exchange, Designer, ACM) +- Different release cycles for console vs components + +**Decision**: +- Console repo (`mulesoft/api-console`): Integrator only +- Component repos (`advanced-rest-client/*`): Individual Web Components +- Each component is separate npm package + +**Consequences**: + +**Pros**: +- ✅ Components reusable across products +- ✅ Independent versioning and releases +- ✅ Smaller bundle sizes (consumers pick what they need) +- ✅ Easier testing (components isolated) + +**Cons**: +- ❌ Complex dependency management +- ❌ Version conflicts possible +- ❌ Release coordination required +- ❌ More repos to maintain + +**Status**: ✅ Active + +--- + +### ADR-003: LitElement (v6) vs LWC (v7) + +**Decision**: Maintain two parallel versions: v6 (LitElement) and v7 (LWC). + +**Context**: +- v6 used by open-source products and Anypoint Platform +- Salesforce products require LWC (no Shadow DOM piercing allowed) +- ACM embedded in Salesforce Experience Cloud + +**Decision**: +- **v6**: LitElement + Web Components (open source) +- **v7**: Lightning Web Components (Salesforce-specific) +- Manual porting of features between versions + +**Consequences**: + +**Pros**: +- ✅ v6: Full Shadow DOM support, flexible styling +- ✅ v7: Salesforce platform integration (LMS, wire adapters, SLDS) +- ✅ Each optimized for its platform + +**Cons**: +- ❌ Double maintenance burden +- ❌ Feature parity difficult to maintain +- ❌ Manual porting (no automation) +- ❌ Different constraints (v7 has governor limits) + +**Status**: ✅ Active + +**Feature parity tracking**: See `products/api-console/feature-parity/` folder + +--- + +### ADR-004: Shadow DOM Scoping + +**Decision**: Use Shadow DOM for all Web Components in v6. + +**Context**: +- Web Components can use Shadow DOM (scoped styles) or Light DOM (global styles) +- Shadow DOM prevents style leakage but limits customization + +**Decision**: Use Shadow DOM with CSS custom properties for theming. + +**Consequences**: + +**Pros**: +- ✅ Styles scoped to component (no global conflicts) +- ✅ Encapsulation (internals hidden from host) +- ✅ Consistent rendering across different hosts + +**Cons**: +- ❌ Hard to override styles from outside +- ❌ CSS custom properties required for theming +- ❌ DevTools inspection harder +- ❌ Testing requires Shadow DOM support (@web/test-runner, NOT Jest) + +**Status**: ✅ Active + +--- + +### ADR-005: vendor.js for Non-ES6 Dependencies + +**Decision**: Bundle CodeMirror and crypto libraries into `vendor.js`. + +**Context**: +- CodeMirror uses AMD/CommonJS modules (incompatible with ES6) +- Crypto libraries (for OAuth1, Digest auth) also non-ES6 +- Rollup cannot bundle mixed module systems + +**Decision**: +- Pre-bundle non-ES6 deps into `demo/vendor.js` +- Load via `` +- Generate via `npm run build:vendor` (not committed to git) + +**Consequences**: + +**Pros**: +- ✅ Works around module system incompatibility +- ✅ Single bundle for all non-ES6 code +- ✅ Smaller main bundle (ES6 only) + +**Cons**: +- ❌ Extra build step required after clone +- ❌ Not obvious for new developers (causes "missing vendor.js" errors) +- ❌ Pollutes global scope (CodeMirror, CryptoJS) + +**Status**: ✅ Active (until CodeMirror v6 migration) + +--- + +## Component Patterns + +### Pattern: Event-Driven Communication + +**Context**: Components need to communicate (e.g., navigation → documentation). + +**Pattern**: Use custom events, not direct method calls. + +**Example**: + +```javascript +// api-navigation fires event +this.dispatchEvent(new CustomEvent('api-navigation-selection-changed', { + detail: { selected: 'method-id', type: 'method' }, + bubbles: true, + composed: true // Crosses Shadow DOM boundary +})); + +// api-console listens +this.addEventListener('api-navigation-selection-changed', (e) => { + this.selectedShape = e.detail.selected; + this.selectedShapeType = e.detail.type; +}); +``` + +**Why**: +- ✅ Loose coupling (components don't know about each other) +- ✅ Works across Shadow DOM boundaries (`composed: true`) +- ✅ Easy to test (mock events) + +--- + +### Pattern: AmfHelperMixin for AMF Queries + +**Context**: Querying AMF JSON-LD is complex (namespaced properties, nested structure). + +**Pattern**: Use `AmfHelperMixin` utilities, not direct JSON queries. + +**Example**: + +```javascript +// ❌ Bad: Direct JSON query +const name = model['http://www.w3.org/ns/shacl#name'][0]['@value']; + +// ✅ Good: Use AmfHelperMixin +const name = this._getValue(model, this.ns.aml.vocabularies.core.name); +``` + +**Why**: +- ✅ Abstracts namespace complexity +- ✅ Handles array vs single value +- ✅ Forwards-compatible (AMF model changes isolated) + +--- + +### Pattern: Reactive Properties with Custom Setters + +**Context**: Property changes need side effects (e.g., update UI, fetch data). + +**Pattern**: Define custom setter, call `requestUpdate()`. + +**Example**: + +```javascript +static get properties() { + return { + selectedShape: { type: String } + }; +} + +get selectedShape() { + return this._selectedShape; +} + +set selectedShape(value) { + const old = this._selectedShape; + if (old === value) return; // Avoid redundant updates + this._selectedShape = value; + this._handleShapeChange(value); // Side effect + this.requestUpdate('selectedShape', old); // Trigger re-render +} + +_handleShapeChange(shape) { + // Fetch method details, update documentation, etc. +} +``` + +**Why**: +- ✅ LitElement reactive system aware of change +- ✅ Side effects controlled +- ✅ Avoids redundant renders (check `old === value`) + +--- + +## API Detection Patterns + +### Pattern: gRPC Auto-Detection + +**Context**: gRPC APIs shouldn't show "Try it" panel (RPC protocol, not REST). + +**Pattern**: Detect API type in AMF model, hide try-it accordingly. + +**Implementation**: + +```javascript +// ApiConsoleApp.js:206-210, ApiConsole.js:466-469 +if (!this._isWebAPI(this.amf) || this._isGrpcApi(this.amf)) { + this._noTryItValue = true; // Hide try-it panel +} + +_isWebAPI(amf) { + // Check if AMF model has WebAPI shape +} + +_isGrpcApi(amf) { + // Check if protocol is gRPC +} +``` + +**Why**: +- ✅ Automatic (no manual configuration) +- ✅ Works for gRPC, AsyncAPI, GraphQL +- ✅ Prevents user confusion (can't send gRPC requests from browser) + +--- + +## Release Patterns + +### Pattern: Semantic Versioning + +**Policy**: Follow semver strictly. + +- **Patch** (X.X.Y): Bug fixes, component updates +- **Minor** (X.Y.0): New features, backwards-compatible +- **Major** (X.0.0): Breaking changes, AMF version updates + +**Example**: +- `6.6.60` → `6.6.61`: Component updates (patch) +- `6.6.61` → `6.7.0`: New feature (e.g., AsyncAPI support) +- `6.7.0` → `7.0.0`: LWC rewrite (major) + +--- + +### Pattern: Component Version Comments in GUS + +**Policy**: Always comment component+version in GUS tickets. + +**Format**: `Fixed in @api-components/api-navigation@4.3.22` + +**Why**: +- ✅ Traceability (know which version fixed issue) +- ✅ Release notes (auto-generate from comments) +- ✅ Rollback guidance (if regression, revert to previous version) + +--- + +### Pattern: Branch Naming + +**Policy**: +- **Features**: `feat/` or `feat/W-XXXXXXX` +- **Fixes**: `fix/` or `fix/W-XXXXXXX` +- **Releases**: `build/` (e.g., `build/6.6.61`) +- **Chores**: `chore/` + +**Why**: Consistent, easy to understand, supports automation. + +--- + +## Testing Patterns + +### Pattern: @web/test-runner over Jest + +**Decision**: Use `@web/test-runner` with Playwright, NOT Jest. + +**Why**: +- ✅ @web/test-runner: Built for Web Components, real browser, Shadow DOM support +- ❌ Jest: JSDOM (not real browser), poor Shadow DOM support + +**Example**: + +```javascript +// test/api-console.basic.test.js +import { fixture, expect } from '@open-wc/testing'; +import '../src/ApiConsole.js'; + +describe('ApiConsole', () => { + it('renders navigation when navigationOpened', async () => { + const el = await fixture(''); + const nav = el.shadowRoot.querySelector('api-navigation'); + expect(nav).to.exist; + }); +}); +``` + +--- + +### Pattern: Visual Regression Testing + +**Decision**: Use `@web/test-runner-visual-regression` for UI changes. + +**Why**: Catch unintended visual regressions (CSS changes, layout shifts). + +**Example**: + +```javascript +import { visualDiff } from '@web/test-runner-visual-regression'; + +it('matches screenshot', async () => { + const el = await fixture(''); + await visualDiff(el, 'api-console-default'); + // Compares with baseline in test/visual/screenshots/ +}); +``` + +**Threshold**: 1% pixel difference allowed (accounts for font rendering). + +--- + +## Deployment Patterns + +### Pattern: Automatic npm Publication + +**Decision**: GitHub Actions auto-publishes to npm on version bump. + +**Workflow**: +1. PR merged to master with version bump in `package.json` +2. CI detects version change +3. Runs tests (Linux + Windows) +4. If tests pass → `npm publish` +5. Downstream consumers get new version + +**Why**: +- ✅ No manual `npm publish` (reduces errors) +- ✅ Tests always run before publish +- ✅ Audit trail (git commit linked to npm version) + +--- + +## Future Considerations + +### CodeMirror v6 Migration + +**Status**: Planned (no timeline) + +**Why**: CodeMirror 6 is ES6 native (no vendor.js needed). + +**Blocker**: Breaking API changes, effort required for migration. + +--- + +### AMF v5 Support + +**Status**: Monitoring + +**Impact**: May require major version bump (7.0.0). + +**Plan**: Wait for AMF v5 stable release, then evaluate migration path. + +--- + +### TypeScript Migration + +**Status**: Under consideration + +**Pros**: Better IDE support, catch errors early + +**Cons**: Migration effort, build complexity + +--- + +## Questions or Proposals? + +Want to propose a new pattern or change an existing one? + +1. Create ADR document: `docs/team/patterns/adr-NNN-title.md` +2. Follow ADR template (Context, Decision, Consequences) +3. Discuss in #api-line or team meeting +4. Update this document after approval + +--- + +## See Also + +- [Onboarding](../onboarding/api-console-v6.md) - Architecture overview +- [Release Runbook](../runbooks/api-console-v6-release.md) - Release process +- [Troubleshooting](../runbooks/api-console-v6-troubleshooting.md) - Common issues diff --git a/docs/team/patterns/branch-naming-conventions.md b/docs/team/patterns/branch-naming-conventions.md new file mode 100644 index 000000000..de949140c --- /dev/null +++ b/docs/team/patterns/branch-naming-conventions.md @@ -0,0 +1,465 @@ +# Branch Naming Conventions for API Console v6 + +> **Last Updated**: 2026-03-03 +> **Owner**: ACM Team +> **Purpose**: Standardize branch naming across api-console ecosystem + +--- + +## Overview + +The API Console v6 ecosystem consists of: +1. **Individual components** (e.g., api-example-generator, api-type-document, api-navigation) +2. **api-console** (main package that bundles components) +3. **anypoint-api-console** (wrapper for Salesforce) + +Different branch naming patterns are used depending on the type of change and repository. + +--- + +## Commit Message Conventions (Enforced by commitlint) + +### Overview + +**This repository uses commitlint** with `@commitlint/config-conventional` to enforce standardized commit messages. + +**Configuration**: `commitlint.config.js` + +**What commitlint validates**: +- ✅ Commit message **format** (type, scope, subject) +- ❌ **NOT** branch names (branch names are flexible) + +### Conventional Commits Format + +``` +(): + +[optional body] + +[optional footer] +``` + +**Example**: +``` +fix(api-navigation): resolve deep allOf property collection + +Added recursive traversal for nested allOf chains. + +Related: W-21368901 +``` + +### Valid Commit Types + +| Type | Use When | Example | +|------|----------|---------| +| `feat` | New feature | `feat(api-request): add OAuth2 PKCE support` | +| `fix` | Bug fix | `fix(api-documentation): resolve markdown rendering issue` | +| `docs` | Documentation only | `docs: update README with new examples` | +| `style` | Code formatting (no logic change) | `style: fix indentation in ApiConsole.js` | +| `refactor` | Code refactor (no bug fix or feature) | `refactor: extract AMF helper into separate file` | +| `test` | Test changes | `test: add regression test for deep allOf` | +| `chore` | Maintenance tasks | `chore: bump version to 6.6.62` | +| `perf` | Performance improvement | `perf: optimize AMF model traversal` | +| `ci` | CI/CD changes | `ci: update GitHub Actions workflow` | +| `build` | Build system changes | `build: update rollup config` | +| `revert` | Revert previous commit | `revert: revert "feat: add feature X"` | + +### Scope (Optional but Recommended) + +Scope indicates what part of the codebase is affected: + +**Examples**: +- `fix(api-navigation):` - Navigation component +- `feat(api-request):` - Request panel +- `docs(README):` - README file +- `chore(deps):` - Dependencies + +**When to omit scope**: +- Changes affect entire codebase +- Documentation updates at root level +- Version bumps + +### Subject Line Rules + +✅ **DO**: +- Use imperative mood ("add" not "added" or "adds") +- Start with lowercase +- No period at the end +- Keep under 72 characters + +❌ **DON'T**: +- Start with uppercase +- End with period +- Use past tense +- Be vague ("fix stuff", "update things") + +### Examples: Good vs Bad + +#### ✅ Good Commits + +```bash +fix(api-navigation): resolve deep allOf property collection +feat(api-request): add OAuth2 PKCE support +docs: add branch naming conventions pattern +chore: bump version to 6.6.62 +test: add regression test for deep allOf schemas +refactor(api-console): extract AMF helper utilities +``` + +#### ❌ Bad Commits (will fail commitlint) + +```bash +Fixed bug # Missing type/scope, past tense +Update code. # Vague, ends with period +FEAT: Add feature # Uppercase type, uppercase subject +fix stuff # Too vague +Added new feature to navigation # Past tense +``` + +### Body and Footer (Optional) + +**Body**: Detailed explanation of WHAT changed and WHY (not HOW - code shows that) + +**Footer**: Reference tickets, breaking changes, etc. + +**Example**: +``` +fix(api-example-generator): add recursive property collection for deep allOf + +Single-pass iteration through allOf shapes didn't recursively expand +nested shacl:and arrays beyond 3 levels. This caused properties in +4+ level allOf chains to be missing from generated examples. + +Added _collectPropertiesRecursive() method with: +- Depth limiting (max 10 levels) +- Circular reference detection +- Backward compatibility + +Related: W-21368901 +Closes: #123 +``` + +### Validation + +**commitlint runs automatically**: +- On `git commit` (via husky pre-commit hook, if configured) +- In CI/CD pipeline + +**Test commit message locally**: +```bash +echo "fix(api-console): resolve issue" | npx commitlint +``` + +**If validation fails**: +```bash +⧗ input: update code +✖ subject may not be empty [subject-empty] +✖ type may not be empty [type-empty] +✖ found 2 problems, 0 warnings +``` + +Fix the commit message: +```bash +git commit --amend -m "fix(api-console): resolve navigation issue" +``` + +--- + +## Branch Naming Patterns + +### 1. `fix/W-XXXXX-description` - Component Bug Fixes + +**Use when**: Fixing a bug in an individual component repository + +**Applies to**: +- `@api-components/api-example-generator` +- `@api-components/api-type-document` +- `@api-components/api-navigation` +- `@api-components/api-summary` +- `@api-components/api-documentation` +- `@api-components/api-request` +- All other `@api-components/*` packages + +**Format**: `fix/W-XXXXXXXX-short-description` + +**Examples**: +```bash +fix/W-21368901-deep-allof +fix/W-12345678-grpc-schema-parsing +fix/W-87654321-nullable-union-types +``` + +**Workflow**: +1. Create `fix/W-XXXXX-description` branch +2. Implement fix + tests +3. **DO NOT** run `npm version patch` in the branch +4. Commit changes with conventional commit message +5. Push branch +6. Create PR +7. **After merge**: GitHub Actions auto-publishes new version (e.g., 4.4.36) + +**Why no version bump in branch**: Allows multiple fixes to be in progress simultaneously without version conflicts. GitHub Actions handles version bumping after merge. + +--- + +### 2. `build/X.X.X` - API Console Releases + +**Use when**: Creating a new api-console release that bundles multiple component updates + +**Applies to**: +- `mulesoft/api-console` (main repo) + +**Format**: `build/X.X.X` where X.X.X is the **next** patch version + +**Examples**: +```bash +build/6.6.62 +build/6.6.63 +build/6.7.0 # Minor version bump +``` + +**Workflow**: +1. Component fixes are already published (e.g., api-example-generator@4.4.36, api-type-document@4.2.42) +2. Create `build/X.X.X` branch (calculate next version from package.json) +3. Run `npm update @api-components/component-name` for each updated component +4. Run `npm version patch` (bumps version in package.json) +5. Commit all changes (package.json, package-lock.json) +6. Push branch +7. Create PR with title: `Release vX.X.X` +8. **After merge**: GitHub Actions publishes api-console@X.X.X to npm + +**Why `build/` not `fix/`**: +- A release typically includes **multiple** component updates (3-5 components) +- Each component may have different GUS work items +- `build/` signals "this is a bundled release", not a single fix +- Prevents confusion when multiple releases are prepared in parallel + +**Version calculation**: +- Read current version from `package.json` +- Increment patch: `6.6.61` → `6.6.62` +- Use incremented version in branch name + +--- + +### 3. `X.X.X` - Wrapper Releases (No Prefix) + +**Use when**: Updating anypoint-api-console wrapper with new api-console version + +**Applies to**: +- `mulesoft-emu/anypoint-api-console` (wrapper repo) + +**Format**: `X.X.X` (direct number, **no prefix**) + +**Examples**: +```bash +6.6.88 +6.6.89 +6.7.0 +``` + +**Workflow**: +1. Wait for api-console@X.X.X to be published to npm (~5-10 min after merge) +2. Create branch with wrapper version number (independent from api-console version) +3. Update `builder/package.json` with new api-console dependency +4. Delete `builder/package-lock.json` and `builder/node_modules` (mandatory) +5. Run `npm install` in `builder/` +6. Commit changes (NO version bump in root package.json) +7. Push branch +8. Create PR with title: `@W-XXXXXXXX: Release X.X.X` +9. After merge: Manual or automated deployment + +**Why no prefix**: +- Historical convention in this repo +- Wrapper versions are independent from api-console versions +- Example: api-console 6.6.62 → wrapper 6.6.88 + +--- + +## Comparison Table + +| Scenario | Branch Pattern | Repo | Version Bump in Branch? | Commit Message Format | Example | +|----------|----------------|------|-------------------------|-----------------------|---------| +| Fix bug in component | `fix/W-XXXXX-desc` | `@api-components/*` | ❌ No | ✅ Conventional Commits | `fix/W-21368901-deep-allof` | +| Release api-console | `build/X.X.X` | `mulesoft/api-console` | ✅ Yes (`npm version patch`) | ✅ Conventional Commits | `build/6.6.62` | +| Update wrapper | `X.X.X` | `mulesoft-emu/anypoint-api-console` | ❌ No | ✅ Conventional Commits | `6.6.88` | + +**Note**: Commit messages are validated by commitlint in ALL repos, regardless of branch naming pattern. + +--- + +## Why This Pattern? + +### Problem: Version Conflicts +If we used `fix/` branches in api-console and ran `npm version patch` in each: +- Developer A: `fix/bug-1` → bumps to 6.6.62 +- Developer B: `fix/bug-2` → also bumps to 6.6.62 +- **Conflict**: Both branches claim the same version + +### Solution: Separate Concerns +- **Components**: `fix/` branches focus on code changes, version bump happens after merge +- **api-console**: `build/` branches bundle multiple components, explicit version in branch name prevents conflicts +- **Wrapper**: Direct version number, independent versioning + +### Note on commitlint + +**commitlint validates commit messages, NOT branch names.** + +- ✅ Branch names: `fix/W-12345-bug`, `build/6.6.62`, `feat/my-feature` - **ALL valid** +- ✅ Commit messages: **MUST** follow Conventional Commits format (enforced) + +**Why this matters**: +- Branch names are flexible and team-specific +- Commit messages are standardized across projects (tooling compatibility) +- Git history benefits from consistent commit message format +- Branch names are temporary (deleted after merge), commit messages are permanent + +--- + +## Related GUS Work Items + +### Components +- Each fix has its own GUS work item +- Format: `W-XXXXXXXX` (no prefix in branch name) +- Example: `fix/W-21368901-deep-allof` → W-21368901 + +### api-console +- Release may reference multiple GUS work items (from bundled components) +- Commit message lists all related work items +- PR body includes all component updates with their GUS tickets + +### Wrapper +- Typically has one "APIC Release" work item (reused across releases) +- Example: W-21411326 (Type: User Story, 1 story point) +- PR title always prefixed with `@W-XXXXXXXX:` + +--- + +## Examples from Recent Work + +### Scenario: Fix deeply nested allOf bug (W-21368901) + +**Step 1: Fix in api-example-generator** +```bash +cd ~/mulesoft/context/products/api-console/v6/api-example-generator +git checkout -b fix/W-21368901-deep-allof +# Implement fix + tests +git add src/ test/ +git commit -m "fix(W-21368901): add recursive property collection for deep allOf" +# NO npm version patch here +git push -u origin fix/W-21368901-deep-allof +# Create PR → Merge → GitHub Actions publishes 4.4.36 +``` + +**Step 2: Fix in api-type-document** +```bash +cd ~/mulesoft/context/products/api-console/v6/api-type-document +git checkout -b fix/W-21368901-deep-allof +# Implement parallel fix +git commit -m "fix(W-21368901): add recursive property collection" +# NO npm version patch here +git push -u origin fix/W-21368901-deep-allof +# Create PR → Merge → GitHub Actions publishes 4.2.42 +``` + +**Step 3: Release api-console** +```bash +cd ~/mulesoft/context/products/api-console/v6/api-console +git checkout -b build/6.6.62 +npm update @api-components/api-example-generator @api-components/api-type-document +npm version patch # Bumps to 6.6.62 +git add package.json package-lock.json +git commit -m "chore: bump version to 6.6.62 + +Updated components: +- @api-components/api-example-generator: 4.4.35 → 4.4.36 +- @api-components/api-type-document: 4.2.41 → 4.2.42 + +Related: W-21368901" +git push -u origin build/6.6.62 +# Create PR → Merge → GitHub Actions publishes 6.6.62 +``` + +**Step 4: Update wrapper** +```bash +cd ~/mulesoft/context/products/api-console/wrapper +git checkout -b 6.6.88 +# Edit builder/package.json: "api-console": "6.6.62" +cd builder +rm package-lock.json && rm -rf node_modules && npm install +cd .. +git add builder/package.json builder/package-lock.json +git commit -m "chore: update api-console to 6.6.62 + +Includes component updates: +- @api-components/api-example-generator: 4.4.36 +- @api-components/api-type-document: 4.2.42 + +Related: W-21368901" +git push -u origin 6.6.88 +gh pr create --title "@W-21411326: Release 6.6.88" --body "..." +``` + +--- + +## Validation Checklist + +Before creating branch: +- [ ] Identified correct pattern (`fix/`, `build/`, or direct number) +- [ ] For `build/`: Calculated next version from current package.json +- [ ] For wrapper: Determined independent wrapper version +- [ ] Have GUS work item numbers ready for commit messages + +Before pushing: +- [ ] Branch name follows convention +- [ ] Version bump only in `build/` branches (not `fix/`) +- [ ] Commit message references GUS work items +- [ ] GPG signature correct (mulesoft-git or salesforce-git) + +--- + +## Common Mistakes + +### ❌ Wrong: Using `fix/` in api-console for releases +```bash +# DON'T DO THIS +git checkout -b fix/W-21368901-deep-allof # Wrong for api-console +npm version patch # Creates version conflict risk +``` + +### ✅ Correct: Using `build/` in api-console +```bash +# DO THIS +git checkout -b build/6.6.62 # Clear version intent +npm version patch # Safe, version is in branch name +``` + +### ❌ Wrong: Running `npm version patch` in component `fix/` branch +```bash +cd api-example-generator +git checkout -b fix/W-12345-bug +# ... make changes ... +npm version patch # DON'T DO THIS - let CI handle it +``` + +### ✅ Correct: Let CI handle component versioning +```bash +cd api-example-generator +git checkout -b fix/W-12345-bug +# ... make changes ... +git commit -m "fix(W-12345): description" +# Merge PR → CI auto-publishes with version bump +``` + +--- + +## Questions? + +Contact: +- **API Console**: ACM Team (#api-console-cloud-sync) +- **Pattern clarification**: Alex Pérez +- **Documentation updates**: Submit PR to this file + +--- + +**Last Updated**: 2026-03-03 +**Version**: 1.0 diff --git a/docs/team/runbooks/00-debugging-common-issues.md b/docs/team/runbooks/00-debugging-common-issues.md new file mode 100644 index 000000000..02b71572e --- /dev/null +++ b/docs/team/runbooks/00-debugging-common-issues.md @@ -0,0 +1,278 @@ +# Runbook: Debugging Common Issues + +**Project**: api-console (Open Source) +**Last Updated**: 2026-02-26 + +--- + +## Quick Links + +- **Demo**: `npm start` → http://localhost:8080 +- **Tests**: `npm test` +- **Repo**: https://github.com/mulesoft/api-console +- **Issues**: https://github.com/mulesoft/api-console/issues + +--- + +## Common Issues + +### Issue 1: Component Not Rendering + +**Symptoms**: Component shows nothing, or only skeleton + +**Diagnosis**: +1. Check browser console for errors +2. Check if `amf` property is set +3. Check if component is registered (`customElements.get('api-console')`) +4. Inspect Shadow DOM in DevTools + +**Common Causes**: +- AMF not loaded or invalid +- Async rendering not complete +- CSS not loaded (check for `