|
| 1 | +# AGENTS.md — GPS Design Systems React Monorepo |
| 2 | + |
| 3 | +This file tells AI coding agents how to work in this repository. Read it before making any changes. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Repo structure |
| 8 | + |
| 9 | +``` |
| 10 | +packages/ |
| 11 | + react-bridge/ ← Platform infrastructure (design-system-agnostic) |
| 12 | + src/ |
| 13 | + gateway/ GatewayProvider, useGatewayQuery/Mutation, MockGateway, |
| 14 | + LwcCallbackGateway, GraphQLGateway, types |
| 15 | + config/ AppConfigProvider, useConfig, useFeatureFlag |
| 16 | + wizard/ createWizardStore (Zustand), useWizardStep (RHF + Zod) |
| 17 | + pubsub/ usePlatformEvent (Platform Events / CDC) |
| 18 | + utils/ stripProxy |
| 19 | + main/default/lwc/ LWC host components: sfGpsDsReactMount, lwcReactConfigLoader, |
| 20 | + lwcConfigUtils, lwcEmpBridge |
| 21 | +
|
| 22 | + react-uswds/ ← USWDS design system package (@sfgps-ds/react-uswds) |
| 23 | + src/ |
| 24 | + components/ 59 React components (USWDS 3.x) |
| 25 | + context/ SfGpsDsUsGovContext / Provider / useAssets |
| 26 | + hooks/ useUniqueId, useAssets, useAccStyleTokens, useI18n |
| 27 | + utils/ safeHtml, sanitizeHref, formUtils |
| 28 | + i18n/ react-i18next integration |
| 29 | + locales/ en.json and other locale bundles |
| 30 | + main/default/ |
| 31 | + classes/ Apex controllers: AppConfigController, CaseController, |
| 32 | + ContactController, ApexFrontdoorService |
| 33 | + networks/ Experience Cloud network metadata |
| 34 | +
|
| 35 | + gov-components/ ← Government-specific components (@gov-ido/gov-components) |
| 36 | + src/ |
| 37 | + components/ 83 gov-specific React components |
| 38 | +
|
| 39 | +docs/ All documentation — platform guides and design-system guides |
| 40 | +e2e/ Playwright tests against local Vite fixture (no org required) |
| 41 | +showcase/ UIBundle showcase app for Salesforce React Experience Cloud |
| 42 | +apps/component-lab/ Local dev fixture — 135 component pages |
| 43 | +examples/ Reference app implementations for PS teams |
| 44 | +scripts/ Utility scripts |
| 45 | +``` |
| 46 | + |
| 47 | +**Package boundary rule:** `react-bridge` has zero imports from `react-uswds` or `gov-components`. It is platform infrastructure only. If code requires a design-system import, it belongs in that design-system package, not here. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## Commands |
| 52 | + |
| 53 | +### Install |
| 54 | +```bash |
| 55 | +npm ci # install from lockfile |
| 56 | +``` |
| 57 | + |
| 58 | +### Build |
| 59 | +```bash |
| 60 | +npm run build # build all packages (tsup for react-uswds) |
| 61 | +npm run build --workspace=packages/react-uswds |
| 62 | +``` |
| 63 | + |
| 64 | +### Test |
| 65 | +```bash |
| 66 | +npm run test --workspaces --if-present # all packages |
| 67 | +npm run test --workspace=packages/react-uswds # USWDS unit tests |
| 68 | +npm run test --workspace=packages/react-bridge # bridge unit tests |
| 69 | +npm run test --workspace=packages/gov-components # gov-components unit tests |
| 70 | +npm run test:coverage --workspace=packages/react-uswds # with coverage thresholds |
| 71 | +``` |
| 72 | + |
| 73 | +### Lint & format |
| 74 | +```bash |
| 75 | +npm run lint # ESLint across all packages |
| 76 | +npm run format:check # Prettier dry-run |
| 77 | +npm run format # Prettier write |
| 78 | +``` |
| 79 | + |
| 80 | +### E2E (local fixture — no org required) |
| 81 | +```bash |
| 82 | +npm run e2e # run against local Vite fixture |
| 83 | +npm run e2e:ui # Playwright interactive UI |
| 84 | +npm run dev # start local Vite dev server (port 4173) |
| 85 | +``` |
| 86 | + |
| 87 | +### Deploy to Salesforce |
| 88 | +```bash |
| 89 | +sf project deploy start --source-dir showcase/main/default/uiBundles --target-org BUILD |
| 90 | +sf org open --target-org BUILD |
| 91 | +``` |
| 92 | + |
| 93 | +--- |
| 94 | + |
| 95 | +## Key architectural constraints |
| 96 | + |
| 97 | +### React component rules |
| 98 | +- React components never import `@salesforce/` modules — those are resolved at LWC compile time and are unavailable in React context. |
| 99 | +- All form components are controlled inputs: the parent owns the value and passes it via props. |
| 100 | +- Use `useId()` for stable, SSR-safe unique IDs. It is deterministic, Concurrent-Mode-safe, and collision-free. |
| 101 | + |
| 102 | +### Security rules |
| 103 | +- Never call `DOMPurify(window)` at module evaluation time. Initialize lazily on first use. |
| 104 | +- Never use `document.activeElement` for focus management in components. Pass trigger elements explicitly. |
| 105 | +- Never use `relatedTarget.closest(...)` in blur handlers. Use a boolean ref flag instead. |
| 106 | +- Use `queueMicrotask`, not `setTimeout`, for post-render focus moves. |
| 107 | + |
| 108 | +### Import rules |
| 109 | +- Import `@salesforce/agentforce-conversation-client` only from `src/agentforce.ts`, never from `src/index.ts` |
| 110 | +- Never import `@salesforce/apex/*`, `@salesforce/label/*`, `@salesforce/schema/*`, `@salesforce/user/*`, `@salesforce/client/*`, `@salesforce/featureFlag/*`, `@salesforce/customPermission/*`, `@salesforce/resourceUrl/*`, or `@salesforce/messageChannel/*` in any React source file — these are LWC compile-time virtual modules and cannot be resolved by npm or any bundler. ESLint rule SB-1 enforces this as a build error. |
| 111 | +- Never import `@sfgps-ds/react-uswds` or `@gov-ido/gov-components` from any file in `packages/react-bridge/`. ESLint rule PB-1 enforces this. |
| 112 | +- Never use `JSON.parse(JSON.stringify(` in `packages/react-bridge/`. Use `stripProxy()` instead. ESLint rule SER-2 enforces this. |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +## What to do / what not to do |
| 117 | + |
| 118 | +### Do |
| 119 | +- Add new USWDS React components under `packages/react-uswds/src/components/<ComponentName>/` |
| 120 | +- Export new public components from `packages/react-uswds/src/index.ts` |
| 121 | +- Export Agentforce-specific components from `packages/react-uswds/src/agentforce.ts` (not the main barrel) |
| 122 | +- Add platform-agnostic infrastructure (gateways, stores, hooks) to `packages/react-bridge/src/` |
| 123 | +- Add gov-specific components under `packages/gov-components/src/components/<ComponentName>/` |
| 124 | +- Write Vitest tests alongside source in `src/**/__tests__/` |
| 125 | +- Write E2E tests in `e2e/tests/` |
| 126 | + |
| 127 | +### Do not |
| 128 | +- Import `@salesforce/agentforce-conversation-client` from the main barrel (`index.ts`) — it belongs in `agentforce.ts` only |
| 129 | +- Import `@salesforce/` LWC virtual modules (`@salesforce/apex/*`, `@salesforce/label/*`, etc.) in any React file — LWC compile-time modules; use the gateway abstraction instead (ESLint SB-1) |
| 130 | +- Import `@sfgps-ds/react-uswds` or `@gov-ido/gov-components` from `packages/react-bridge/` — bridge is design-system-agnostic (ESLint PB-1) |
| 131 | +- Use `JSON.parse(JSON.stringify(` for LWC→React data crossing — use `stripProxy()` instead (ESLint SER-2) |
| 132 | +- Call `DOMPurify(window)` at module evaluation time |
| 133 | +- Use `document.activeElement` for focus management in React components |
| 134 | +- Add `dompurify` back to `dependencies` in `react-uswds` — it is a `peerDependency` and externalized from the tsup bundle |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## Known pre-existing issues |
| 139 | +- `safeHtml.test.ts` — all tests pass. If test `[SEC-1D]` regresses, the fix is the `afterSanitizeAttributes` hook in `getPurifier()` inside `src/utils/safeHtml.ts`. |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## Testing philosophy |
| 144 | +- Unit tests live in `src/**/__tests__/` and must run in Node/jsdom without a Salesforce org. |
| 145 | +- E2E tests in `e2e/` run against a local Vite fixture. They do not require a Salesforce org. |
| 146 | +- Coverage thresholds are enforced at 80% for `react-uswds`. Do not lower them. |
0 commit comments