@explorer02/cfm-survey-sdk 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/cli/index.js +141 -33
  2. package/dist/cli/index.mjs +141 -33
  3. package/dist/index.js +1 -1
  4. package/dist/index.mjs +1 -1
  5. package/package.json +3 -1
  6. package/postinstall.js +9 -5
  7. package/templates/AGENT.md +60 -19
  8. package/templates/deploy-wizard-to-s3.sh +52 -0
  9. package/templates/docs/00-integration/agent-execution-flow.md +293 -0
  10. package/templates/docs/00-integration/agent-operating-contract.md +268 -0
  11. package/templates/docs/00-integration/apply-ui-config.md +390 -0
  12. package/templates/docs/00-integration/aws-deploy.md +117 -3
  13. package/templates/docs/00-integration/canonical-survey-fixtures.md +94 -0
  14. package/templates/docs/00-integration/client-integration-guide.md +9 -7
  15. package/templates/docs/00-integration/client-lib-folder.md +115 -0
  16. package/templates/docs/00-integration/component-checklist.md +90 -62
  17. package/templates/docs/00-integration/constraints.md +14 -5
  18. package/templates/docs/00-integration/custom-field-logic-and-navigation.md +56 -0
  19. package/templates/docs/00-integration/mockup-ui-extraction.md +113 -0
  20. package/templates/docs/00-integration/placeholders-and-custom-fields-wiring.md +192 -0
  21. package/templates/docs/00-integration/placeholders-and-tokens.md +2 -1
  22. package/templates/docs/00-integration/progress.md +4 -2
  23. package/templates/docs/00-integration/setup.md +12 -0
  24. package/templates/docs/00-integration/ui-customization-wizard.md +123 -0
  25. package/templates/docs/00-integration/useSurveySDK.md +35 -1
  26. package/templates/docs/00-integration/wizard-api.md +126 -0
  27. package/templates/docs/00-integration/wizard-config-handoff.md +292 -0
  28. package/templates/docs/00-integration/wizard-preview-build-guide.md +405 -0
  29. package/templates/docs/00-integration/wizard-question-type-styling.md +197 -0
  30. package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
  31. package/templates/docs/01-components/01-survey-page.md +18 -8
  32. package/templates/docs/01-components/02-question.md +2 -2
  33. package/templates/docs/01-components/03-rating-scale.md +12 -18
  34. package/templates/docs/01-components/05-csat-matrix-scale.md +18 -26
  35. package/templates/docs/01-components/06-likert-matrix-scale.md +19 -39
  36. package/templates/docs/01-components/07-slider-matrix-scale.md +48 -33
  37. package/templates/docs/01-components/09-custom-slider-track.md +15 -25
  38. package/templates/docs/01-components/10-header-footer.md +23 -4
  39. package/templates/docs/01-components/11-progress-bar.md +14 -6
  40. package/templates/docs/01-components/19-survey-sticky-chrome.md +79 -0
  41. package/templates/docs/01-components/README.md +2 -2
  42. package/templates/docs/02-reference/question-types/10-slider-matrix.md +38 -26
  43. package/templates/docs/02-reference/routing-table.md +1 -0
  44. package/templates/docs/02-reference/value-derivation.md +1 -1
  45. package/templates/docs/03-ui-specs/00-question-shell.md +10 -0
  46. package/templates/docs/03-ui-specs/01-rating.md +18 -0
  47. package/templates/docs/03-ui-specs/02-radio.md +16 -1
  48. package/templates/docs/03-ui-specs/03-text.md +12 -1
  49. package/templates/docs/03-ui-specs/04-csat.md +84 -50
  50. package/templates/docs/03-ui-specs/06-slider.md +3 -1
  51. package/templates/docs/03-ui-specs/07-matrix-cfm.md +71 -48
  52. package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +48 -18
  53. package/templates/docs/03-ui-specs/09-slider-matrix.md +59 -32
  54. package/templates/docs/03-ui-specs/10-file-upload.md +11 -0
  55. package/templates/docs/03-ui-specs/11-text-and-media.md +4 -0
  56. package/templates/docs/03-ui-specs/12-survey-chrome.md +54 -5
  57. package/templates/docs/03-ui-specs/13-heatmap.md +12 -1
  58. package/templates/docs/03-ui-specs/14-rank-order.md +11 -0
  59. package/templates/docs/03-ui-specs/README.md +4 -2
  60. package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +1 -1
  61. package/templates/docs/MANIFEST.json +180 -7
  62. package/templates/docs/index.md +114 -117
  63. package/templates/docs/templates/CsatMatrixScale.tsx +637 -0
  64. package/templates/docs/templates/FileUploadScale.tsx +262 -0
  65. package/templates/docs/templates/HeatmapScale.tsx +114 -0
  66. package/templates/docs/templates/LikertMatrixScale.tsx +414 -0
  67. package/templates/docs/templates/Question.tsx +3 -0
  68. package/templates/docs/templates/RatingScale.tsx +129 -0
  69. package/templates/docs/templates/SliderMatrixScale.tsx +248 -0
  70. package/templates/docs/templates/SurveyStickyChrome.tsx +24 -0
  71. package/templates/docs/templates/customFieldValues.ts +36 -0
  72. package/templates/docs/templates/deploy-to-aws.sh +74 -0
  73. package/templates/docs/templates/implementation_plan.md +64 -10
  74. package/templates/docs/templates/labelStyles.ts +33 -0
  75. package/templates/docs/templates/selectionStyles.ts +100 -0
  76. package/templates/docs/templates/surveyUiIcons.tsx +11 -0
  77. package/templates/docs/templates/surveyUiScaleUtils.ts +51 -0
  78. package/templates/docs/templates/verify-agent-build.sh +119 -0
  79. package/templates/preview-harness/preview-bridge.inline.js +201 -0
  80. package/templates/preview-harness/previewPages.js +108 -0
  81. package/templates/preview-harness/previewPages.ts +298 -0
  82. package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +67 -0
  83. package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +122 -0
  84. package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +75 -0
  85. package/templates/preview-harness/vite-app/src/fixtures/questions.ts +311 -0
  86. package/templates/preview-harness/vite-app/src/globals.css +16 -0
  87. package/templates/preview-harness/vite-app/src/mount.tsx +9 -0
  88. package/templates/preview-harness/vite-app/src/preview-live-overrides.css +101 -0
  89. package/templates/preview-harness/vite-app/stubs/next-dynamic.tsx +25 -0
  90. package/templates/preview-harness/vite-app/stubs/next-image.tsx +29 -0
  91. package/templates/previewBridge.ts +153 -0
  92. package/templates/survey-theme.css +295 -0
  93. package/templates/survey-ui-config.schema.json +213 -0
  94. package/templates/wizard-dist/assets/PreviewMock-AoZdAEPZ.js +1 -0
  95. package/templates/wizard-dist/assets/TypePanel-39FnbtvG.js +1 -0
  96. package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
  97. package/templates/wizard-dist/assets/index-CWKdsJOp.js +34 -0
  98. package/templates/wizard-dist/assets/vendor-BwkXDkd3.js +17 -0
  99. package/templates/wizard-dist/index.html +20 -0
  100. package/templates/wizard.html +13 -1129
@@ -0,0 +1,268 @@
1
+ # Agent Operating Contract — Anti-Hallucination Guide
2
+
3
+ > **Read with** [`agent-execution-flow.md`](agent-execution-flow.md) and [`index.md`](../index.md).
4
+ > This doc tells the **client-side coding agent** exactly how to use SDK docs — and what is **forbidden** to invent.
5
+
6
+ **Prime directive:** If a behavior, API, file path, CSS variable, answer shape, or CLI command is **not** written in these docs (or copied from `docs/templates/`), **do not implement it from memory**.
7
+
8
+ ---
9
+
10
+ ## 1. Authoritative source hierarchy
11
+
12
+ Use sources **only** in this order. Lower items never override higher ones.
13
+
14
+ | Priority | Source | Use for |
15
+ |----------|--------|---------|
16
+ | **1** | [`MANIFEST.json`](../MANIFEST.json) | Phase order, `typeLiterals`, per-type `blueprint` / `reference` / `uiSpec` paths |
17
+ | **2** | [`agent-execution-flow.md`](agent-execution-flow.md) | Pipeline, client questions, phase gates |
18
+ | **3** | This file | Anti-hallucination rules, doc routing, verification |
19
+ | **4** | `00-integration/*` | Wiring, constraints, wizard, deploy |
20
+ | **5** | `01-components/*` + `03-ui-specs/*` | UI anatomy per type |
21
+ | **6** | `02-reference/*` | Data shapes, exports, value derivation |
22
+ | **7** | `docs/templates/*` | Copy-paste starting code (`Question.tsx`, scales, libs) |
23
+
24
+ ### Forbidden sources (never use to implement)
25
+
26
+ | Forbidden | Why |
27
+ |-----------|-----|
28
+ | `packages/sdk/src/**` or `node_modules/.../src/**` | Internal SDK — not a public contract |
29
+ | `apps/client/**` | Monorepo snapshot — may be stale; not agent deliverable |
30
+ | Legacy `survey-config.json` | Replaced by `survey-ui-config.json` + wizard |
31
+ | Training memory / other survey libs | Wrong answer shapes, wrong hooks, wrong types |
32
+ | Guessing from component names alone | Types and helpers are defined in docs only |
33
+
34
+ **If two docs conflict:** `MANIFEST.json` + `agent-execution-flow.md` win. Open an issue in the monorepo — do not pick a guess.
35
+
36
+ ---
37
+
38
+ ## 2. Read-before-write protocol (mandatory)
39
+
40
+ **Never write or edit React/TS/CSS until the listed docs for the current phase are read.**
41
+
42
+ ### Phase gate table
43
+
44
+ | Phase | Read these files **before any code** | Extract and record |
45
+ |-------|--------------------------------------|--------------------|
46
+ | **0** | `agent-operating-contract.md`, `agent-execution-flow.md`, `mockup-ui-extraction.md`, `index.md`, `MANIFEST.json` | Framework, `typeLiterals`; **UI-only** mockup notes |
47
+ | **1** | `setup.md` (framework section) | Install list, AWS export flags if prompt mentions AWS |
48
+ | **2** | `useSurveySDK.md` | `instanceId` wiring location — then **ask client for JWT** |
49
+ | **3** | `client-integration-guide.md`, `question-type-sdk-matrix.md`, logic + lifecycle docs per MANIFEST phase 3 | `onAction` shapes, `state.answers`, visibility helpers |
50
+ | **4** | `component-checklist.md`, `implementation_plan.md` template, `mockup-ui-extraction.md`, `placeholders-and-custom-fields-wiring.md`, `00-question-shell.md`, `12-survey-chrome.md`, **per-type** MANIFEST routes | §3b from **fetch**; §3d placeholders + custom fields |
51
+ | **5** | `constraints.md`, `wizard-preview-build-guide.md`, `wizard-question-type-styling.md`, **each** `03-ui-specs/{type}.md` in inventory | Tokens, `data-cfm-*`, selection pattern |
52
+ | **6** | `constraints.md`, `component-checklist.md` Step 3–4 | Run `verify-agent-build.sh` — fix failures |
53
+ | **6b** | `ui-customization-wizard.md`, `wizard-api.md` | CLI env vars — only if client said **yes** |
54
+ | **6c** | `apply-ui-config.md`, `wizard-question-type-styling.md` | UI tokens only |
55
+ | **7** | `aws-deploy.md` or deploy section in `setup.md` | Deploy target from prompt / config |
56
+
57
+ ### Per-question-type gate (Phase 4–5)
58
+
59
+ For **each** `question.type` in the fetched survey, read **all three** MANIFEST paths before touching that component:
60
+
61
+ ```
62
+ questionTypes.{TYPE}.blueprint → 01-components/*
63
+ questionTypes.{TYPE}.reference → 02-reference/question-types/*
64
+ questionTypes.{TYPE}.uiSpec → 03-ui-specs/*
65
+ ```
66
+
67
+ **Blocking rule:** If you have not read the ui-spec for a type, you may not implement that type.
68
+
69
+ ---
70
+
71
+ ## 3. Doc routing — task → exact files
72
+
73
+ Use this table when deciding what to read. **Do not substitute similar-sounding docs.**
74
+
75
+ | Task | Read (in order) | Do not guess |
76
+ |------|-----------------|--------------|
77
+ | Wire `useSurveySDK` | `useSurveySDK.md`, `client-integration-guide.md` | Hook return field names |
78
+ | Dispatch questions | `templates/Question.tsx`, `question-type-sdk-matrix.md`, `routing-table.md` | `subType`, stub fallbacks |
79
+ | NPS scale | `03-ui-specs/01-rating.md`, `templates/RatingScale.tsx`, `value-derivation.md` | `optionValue`, `accentColor` on options |
80
+ | MCQ | `03-ui-specs/02-radio.md`, `question-type-sdk-matrix.md#mcq` | `isMultiSelect` — use `selectionMode` |
81
+ | Matrix CFM | `03-ui-specs/07-matrix-cfm.md`, `templates/LikertMatrixScale.tsx`, `canonical-survey-fixtures.md` | Bare radio grid without row labels |
82
+ | Matrix CSAT/Rating | `03-ui-specs/04-csat.md`, `08-matrix-csat-rating.md`, `templates/CsatMatrixScale.tsx` | Separate RatingMatrixScale file |
83
+ | Slider matrix | `03-ui-specs/09-slider-matrix.md`, `templates/SliderMatrixScale.tsx` | Orphan slider without header row |
84
+ | File upload | `03-ui-specs/10-file-upload.md`, `file-upload-aws.md` | Raw `File[]` in submit payload |
85
+ | Heatmap | `03-ui-specs/13-heatmap.md`, `templates/heatmapCoords.ts` | Region overlays on respondent UI |
86
+ | Rank order | `03-ui-specs/14-rank-order.md`, `templates/RankOrderScale.tsx` | Client-side re-shuffle |
87
+ | Custom fields | `custom-field-logic-and-navigation.md`, `placeholders-and-custom-fields-wiring.md`, `templates/customFieldValues.ts` | Skip wiring hook + Question prop |
88
+ | Mockup / prompt image | `mockup-ui-extraction.md` | UI chrome only — not question types or logic |
89
+ | Placeholders + CRM tokens | `placeholders-and-custom-fields-wiring.md`, `placeholders-and-tokens.md` | Keys from fetched `{{TOKEN}}` text |
90
+ | Wizard chrome | `wizard-preview-build-guide.md`, `03-ui-specs/12-survey-chrome.md` | External logo URLs |
91
+ | Wizard per-type colors | `wizard-question-type-styling.md` | Hardcoded Telekom hex for wizard tokens |
92
+ | Selection colors | `wizard-question-type-styling.md`, `templates/selectionStyles.ts` | Single color for ring + fill — use annulus pattern |
93
+ | Matrix column labels | `wizard-question-type-styling.md`, `templates/labelStyles.ts` | Hint labels on CFM column headers |
94
+ | Logo seed | `constraints.md` §4, `wizard-api.md`, `parse-client-header` behavior in wizard docs | Random `public/logo_*` scan |
95
+ | Wizard session (wait) | `wizard-config-handoff.md`, `ui-customization-wizard.md`, `wizard-troubleshooting.md` |
96
+ | Apply all wizard paths | `apply-ui-config.md` | Changing `Question.tsx` dispatch |
97
+ | Deploy AWS | `aws-deploy.md`, `setup.md#nextjs-aws-static-export` | `assetPrefix: "/"` for static export |
98
+
99
+ ---
100
+
101
+ ## 4. Hallucination blocklist — never invent these
102
+
103
+ | ❌ Hallucination | ✅ Doc-backed truth |
104
+ |-----------------|---------------------|
105
+ | `question.subType` routing | Flat `question.type` — 11 literals in `MANIFEST.json` `typeLiterals` |
106
+ | `state.values` for answers | `state.answers` — `MANIFEST.json` `hookContract.answersField` |
107
+ | `isMultiSelect` on MCQ | `selectionMode: 'single' \| 'multiple'` |
108
+ | Default branch: "Not implemented" | Copy `templates/Question.tsx` — all types explicit |
109
+ | Import `@repo/sdk/src/...` | Package root only — `hookContract.forbiddenImports` |
110
+ | Implement from `apps/client` | Copy `docs/templates/*` |
111
+ | `npx cfm-sdk customize-ui` when client is on **same machine** as agent | Use **`npx cfm-sdk customize`** (default) |
112
+ | `npx cfm-sdk customize` when client is on **another device** | Use `customize-ui` + EC2 link |
113
+ | Infer question types / logic / language from mockup image | Fetch survey (JWT) only — see `mockup-ui-extraction.md` |
114
+ | Placeholder keys from mockup examples | Scan fetched question text for `{{TOKEN}}` |
115
+ | `_c_…` ids or CRM values from mockup | Scan fetch + CRM spec — `placeholders-and-custom-fields-wiring.md` |
116
+ | `survey-config.json` | `survey-ui-config.json` + schema in `templates/` |
117
+ | NPS `option.accentColor` | Derive from value — `value-derivation.md` |
118
+ | Matrix value = column label text | `matrixColumnStoredValue(col)` → column **`id`** |
119
+ | FILE_UPLOAD answer = `File[]` | `UploadedFileAnswer[]` after presigned upload |
120
+ | CFM column headers = hint labels | `matrixColumnLabelStyle()` — label **items** only |
121
+ | Focus ring = cell fill (same element) | Ring = border + dot; cell selected = annulus between |
122
+ | Wizard optional → skip `survey-theme.css` | Wizard-ready build is **mandatory** Phase 5 |
123
+ | Logo from any `public/logo_*` | `Header.tsx` `data-cfm-logo` / `data-cfm-logo-text` contract |
124
+ | `global.logo.url` as Header `src` | `./{fileName}` from `public/` built into `out/` — see `aws-deploy.md` § Logos |
125
+ | Wizard logo “in memory” on CloudFront | Re-apply `fileName`, rebuild, redeploy — preview `data:` ≠ deploy bundle |
126
+ | `getVisible*` without 4th arg when CRM logic exists | Pass `customFieldValues` — `hookContract.visibilityHelpers` |
127
+ | New question types or SDK actions | Only documented `onAction` types in `useSurveySDK.md` |
128
+ | Placeholder unstable inline object | Stable ref + `useMemo` on hook options |
129
+ | Slider matrix without tick header | `canonical-survey-fixtures.md` + ui-spec |
130
+ | RATING_MATRIX as new component | Reuse `CsatMatrixScale.tsx` |
131
+ | Killed CLI during wizard poll | Keep running until `Configuration ready`; see `wizard-config-handoff.md` |
132
+ | Applied before client submitted | Wait for CLI exit 0; use `.final.json` not seed |
133
+ | Skipped diff paths | Read entire `survey-ui-config.diff.md`; apply every path |
134
+
135
+ ---
136
+
137
+ ## 5. Copy-first code generation
138
+
139
+ **Default action = copy template, then extend.** Not rewrite from ui-spec prose.
140
+
141
+ | Always copy first | Destination |
142
+ |-------------------|-------------|
143
+ | `templates/Question.tsx` | `src/components/Question.tsx` |
144
+ | `templates/survey-theme.css` | `src/styles/survey-theme.css` |
145
+ | `templates/selectionStyles.ts` | `src/lib/surveyUi/selectionStyles.ts` |
146
+ | `templates/labelStyles.ts` | `src/lib/surveyUi/labelStyles.ts` |
147
+ | `templates/previewBridge.ts` | `src/lib/previewBridge.ts` |
148
+ | Per-inventory scale templates | `src/components/` |
149
+
150
+ **After copy, only change:**
151
+
152
+ - Branding tokens (`var(--cfm-*)`) per client prompt
153
+ - Imports paths for project alias
154
+ - Cosmetic styling per `wizard-question-type-styling.md`
155
+
156
+ **Never change in copied dispatcher:**
157
+
158
+ - `onAction` payload shapes
159
+ - `question.type` switch cases / missing branches
160
+ - Visibility helper call signatures
161
+
162
+ ---
163
+
164
+ ## 6. Phase completion evidence
165
+
166
+ Do **not** tell the client a phase is done without evidence.
167
+
168
+ | Phase | Required evidence |
169
+ |-------|-------------------|
170
+ | **4** | `implementation_plan.md` exists; §3b lists every fetched `question.type` |
171
+ | **5** | All inventory components exist; draft `survey-ui-config.json` present |
172
+ | **6** | `bash templates/verify-agent-build.sh` exit 0; `npm run build` exit 0; dev server loads |
173
+ | **6b** | Client explicitly said yes; `survey-ui-config.json` updated by CLI |
174
+ | **6c** | Tokens synced per `apply-ui-config.md`; verify script re-run |
175
+ | **7** | Deploy only after INPUT 4 yes |
176
+
177
+ ### Verification commands (run, do not assume)
178
+
179
+ ```bash
180
+ # From project root — paths may vary; see component-checklist.md
181
+ bash templates/verify-agent-build.sh
182
+ npm run build
183
+ grep -r "not yet implemented" src/ components/ app/ # must be empty
184
+ grep -r "subType" src/components/Question.tsx # must be empty
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 7. When uncertain — stop and read
190
+
191
+ | Situation | Action | Do not |
192
+ |-----------|--------|--------|
193
+ | Field not in ui-spec config table | Check `02-reference/config-field-index.md` | Add imaginary prop |
194
+ | Matrix labels missing in API | Read `canonical-survey-fixtures.md` | Omit label row |
195
+ | Unknown `question.type` in survey | Re-fetch; check `typeLiterals` | Add `default` stub |
196
+ | Wizard token name unclear | Read `wizard-question-type-styling.md` + `survey-theme.css` | Invent `--cfm-*` name |
197
+ | CLI fails | Read error + `constraints.md` troubleshooting | Retry random flags |
198
+ | Custom field id `_c_…` | Read `custom-field-logic-and-navigation.md` | Ignore in visibility |
199
+ | AWS vs Vercel deploy | Prompt keywords + `survey-ui-config.json` `deploy.target` | Assume Vercel |
200
+
201
+ **Uncertainty rule:** Open the MANIFEST-routed doc for that topic. If still absent, ask the client — do not implement.
202
+
203
+ ---
204
+
205
+ ## 8. Client communication rules
206
+
207
+ ### Exact questions (only these four)
208
+
209
+ 1. *(Prompt — usually provided at start)*
210
+ 2. *"Please provide your survey instance ID (JWT token)."* — Phase 2 only
211
+ 3. *"Your survey is running locally. Would you like to customize the UI through the web wizard?"* — Phase 6 only
212
+ 4. *"Your survey is built and verified. Ready to deploy to production?"* — Phase 7 only
213
+
214
+ **Do not ask:** architecture opinions, stub approval, wizard before build, or "should I read the docs."
215
+
216
+ ### Status updates to client
217
+
218
+ When reporting progress, cite **phase number** and **doc section** completed, e.g.:
219
+
220
+ - "Phase 4 complete — inventory: NPS_SCALE, MCQ, CFM_MATRIX per `implementation_plan.md` §3b"
221
+ - "Phase 5 — wired `--cfm-matrix-selected` / `--cfm-input-focus-ring` per `wizard-question-type-styling.md`"
222
+
223
+ Do not claim "integrated SDK" without naming hook doc and verify result.
224
+
225
+ ---
226
+
227
+ ## 9. Wizard-ready build checklist (Phase 5 — non-optional)
228
+
229
+ Even when the client will skip the wizard, verify each item:
230
+
231
+ - [ ] `src/styles/survey-theme.css` copied from template
232
+ - [ ] `selectionStyles.ts` + `labelStyles.ts` in `src/lib/surveyUi/`
233
+ - [ ] `./survey-ui-config.json` draft at project root
234
+ - [ ] `data-cfm-logo` or `data-cfm-logo-text`, `data-cfm-btn-next`, `data-cfm-btn-back`, `data-cfm-survey-title` in chrome
235
+ - [ ] Scale components use `var(--cfm-*)` for wizard-controlled tokens
236
+ - [ ] Selection pattern: focus ring = border + dot; cell selected = annulus
237
+ - [ ] `previewBridge.ts` + layout init for local `customize`
238
+
239
+ ---
240
+
241
+ ## 10. Quick self-audit before handoff
242
+
243
+ Answer **yes** to all before telling the client the survey is ready:
244
+
245
+ 1. Did I read `agent-operating-contract.md` and `agent-execution-flow.md` at session start?
246
+ 2. Did I read ui-specs for **every** type in the fetched survey?
247
+ 3. Did I copy `Question.tsx` from templates (not write a new dispatcher)?
248
+ 4. Are all 11 `typeLiterals` handled with no stub branch?
249
+ 5. Did `verify-agent-build.sh` pass?
250
+ 6. Did I ask wizard question only after Phase 6 verify?
251
+ 7. Did I avoid `apps/client` and SDK `/src/` imports?
252
+ 8. Are matrix row + column labels visible per `canonical-survey-fixtures.md`?
253
+ 9. Is FILE_UPLOAD using presigned flow if present?
254
+ 10. Is `customFieldValues` wired in hook **and** Question when `_c_…` ids exist?
255
+
256
+ **Any "no" → go back to the routed doc in §3; do not hand off.**
257
+
258
+ ---
259
+
260
+ ## Related docs
261
+
262
+ | Doc | Role |
263
+ |-----|------|
264
+ | [`agent-execution-flow.md`](agent-execution-flow.md) | Phase order and client inputs |
265
+ | [`component-checklist.md`](component-checklist.md) | File inventory and copy table |
266
+ | [`constraints.md`](constraints.md) | Hard limits (logo, imports, stubs) |
267
+ | [`question-type-sdk-matrix.md`](question-type-sdk-matrix.md) | Answer shapes + visibility per type |
268
+ | [`index.md`](../index.md) | Master index |
@@ -0,0 +1,390 @@
1
+ # Apply UI Config (`survey-ui-config.json`)
2
+
3
+ > **Phase 6c** — after wizard handoff. Read [`wizard-config-handoff.md`](wizard-config-handoff.md) first (wait protocol + review artifacts).
4
+ > **Build-time contract:** [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md).
5
+ > **Per-type tokens:** [`wizard-question-type-styling.md`](wizard-question-type-styling.md).
6
+
7
+ ## Which file to apply from
8
+
9
+ | Wizard mode | Apply source | When |
10
+ |-------------|--------------|------|
11
+ | **`customize` (default)** | `survey-ui-config.json` | After `✅ UI configuration saved` |
12
+ | `customize-ui` review | `survey-ui-config.final.json` | After CLI prints `Configuration ready` |
13
+ | `customize-ui --apply` | `survey-ui-config.json` | Immediately after CLI exits |
14
+
15
+ **Default:** apply directly from `survey-ui-config.json` after `npx cfm-sdk customize`.
16
+
17
+ **EC2 review mode:** apply from `.final.json`; run `confirm-ui-config` after codebase apply.
18
+
19
+ ---
20
+
21
+ ## Scope (UI-only)
22
+
23
+ **May change:** CSS vars, chrome components, nav labels, logo path, placeholders, debug flag, cosmetic scale tokens.
24
+
25
+ **Must NOT change:** `Question.tsx` dispatch, `onAction` payloads, answer shapes, visibility helpers, matrix routing, file upload presigned flow.
26
+
27
+ ---
28
+
29
+ ## Apply workflow (ordered — do not skip steps)
30
+
31
+ ### 1. Capture and audit
32
+
33
+ ```bash
34
+ # AWS review mode — mandatory read
35
+ cat survey-ui-config.diff.md
36
+ ```
37
+
38
+ - Count entries: `changed + added + removed` from CLI output or diff JSON
39
+ - Open `survey-ui-config.final.json` (or `survey-ui-config.json` for local)
40
+
41
+ ### 2. Validate
42
+
43
+ - JSON parses without error
44
+ - Validate against `templates/survey-ui-config.schema.json`
45
+ - `surveyTypes` matches fetched survey inventory
46
+
47
+ ### 3. Sync CSS (full regen — not diff-only)
48
+
49
+ **Regenerate entire `src/styles/survey-theme.css`** from final config so derived tokens stay consistent.
50
+
51
+ Use the mapping tables below: every config field → `--cfm-*` var. Reference implementation: wizard `configToCssVars()` (same var names as `templates/survey-theme.css`).
52
+
53
+ Minimum global vars from `global.colorScheme` + `global.theme`:
54
+
55
+ ```css
56
+ :root {
57
+ --cfm-primary: /* global.colorScheme.primary */;
58
+ --cfm-accent: /* global.colorScheme.accent */;
59
+ --cfm-matrix-selected: /* global.theme.cellSelectedColor */;
60
+ --cfm-input-focus-ring: /* global.theme.focusRingColor */;
61
+ --cfm-mcq-selected-accent: var(--cfm-matrix-selected);
62
+ /* … all vars in templates/survey-theme.css */
63
+ }
64
+ ```
65
+
66
+ Import in `globals.css`: `@import './styles/survey-theme.css';`
67
+
68
+ ### 4. Apply content patches (`data-cfm-*`)
69
+
70
+ | Config path | DOM target | Attribute / content |
71
+ |-------------|------------|---------------------|
72
+ | `global.surveyTitle` | Intro / title slot | `data-cfm-survey-title` text |
73
+ | `global.companyName` | Header | `data-cfm-company` text |
74
+ | `global.thankYouMessage` | End page | `data-cfm-thank-you` text |
75
+ | `global.browserTabTitle` | `layout.tsx` / metadata | `document.title` |
76
+ | `global.buttons.next` | SurveyPage | `data-cfm-btn-next` text |
77
+ | `global.buttons.back` | SurveyPage | `data-cfm-btn-back` text |
78
+ | `global.buttons.submit` | SurveyPage submit label | button text |
79
+ | `global.logo.fileName` | Header | `data-cfm-logo` src=`./${fileName}` for AWS static export (`/${fileName}` for local dev only) |
80
+ | `global.logo.url` | Download source only | EC2: CloudFront `/assets/` URL → `confirm-ui-config` copies to `public/`. **Never** use as `img src` or `data:` preview URL |
81
+ | `global.footer.copyrightText` | Footer | `data-cfm-copyright` |
82
+ | `global.footer.links[]` | Footer | `data-cfm-footer-links` (render links) |
83
+ | `questionTypes.MCQ.optionStyle` | `:root` or survey wrapper | `data-cfm-mcq-style` |
84
+ | `questionTypes.NPS_SCALE.buttonStyle` | `:root` | `data-cfm-nps-button-style` |
85
+ | `questionTypes.FILE_UPLOAD.dropzoneStyle` | `:root` | `data-cfm-dropzone-style` |
86
+
87
+ ### 5. Apply layout toggles (chrome only)
88
+
89
+ | `global.layout.*` | Apply in |
90
+ |-------------------|----------|
91
+ | `showHeader` | `SurveyPage` — conditional `<Header />` |
92
+ | `showFooter` | Conditional `<Footer />` |
93
+ | `showProgressBar` | `SurveyStickyChrome` / `ProgressBar` |
94
+ | `showLanguageSwitcher` | `LanguageSelector` |
95
+ | `showNextButton` / `showBackButton` | Nav button visibility |
96
+ | `showQuestionNumbers` | Question title prefix |
97
+ | `showRequiredAsterisk` | Required `*` in shell |
98
+ | `width` | Container `max-w-*` via `--cfm-max-width` |
99
+ | `borderStyle` | `--cfm-border-radius` |
100
+ | `fontStyle` | `--cfm-font-family` |
101
+
102
+ | `global.header.*` | CSS vars on `:root` (see § Header) |
103
+ | `global.footer.*` | CSS vars + footer structure |
104
+
105
+ ### 6. Apply hook options
106
+
107
+ | Config path | Wire in |
108
+ |-------------|---------|
109
+ | `placeholders.*` | `useSurveySDK({ options: { placeholders } })` — stable ref |
110
+ | `customFields` | `src/lib/customFieldValues.ts` + hook + `Question` prop |
111
+ | `debug.enabled` | `debug: true` in hook options |
112
+
113
+ ### 7. Per-type tokens (inventory only)
114
+
115
+ For each type in `surveyTypes[]`, apply `questionTypes.{TYPE}` per § Question types below.
116
+
117
+ ### 8. Logo file (required for AWS deploy)
118
+
119
+ Wizard preview keeps the image in **browser memory** (`data:` URL). CloudFront only serves files that were **built into `out/`** and uploaded in Phase 7.
120
+
121
+ | Wizard mode | Where binary lands | Agent action before deploy |
122
+ |-------------|-------------------|----------------------------|
123
+ | **`customize` (local)** | `public/{fileName}` via `POST /api/upload-logo` | Set `data-cfm-logo src="./{fileName}"` in `Header.tsx` |
124
+ | **`customize-ui` (EC2)** | S3 `sites/{surveyId}/assets/{fileName}` + `global.logo.url` in `.final.json` | Run `confirm-ui-config` → copies to `public/`; then set Header `src="./{fileName}"` |
125
+
126
+ **Rules:**
127
+
128
+ 1. **Authoritative path:** `global.logo.fileName` — not `global.logo.url` for `img src`.
129
+ 2. **`global.logo.url` after EC2 wizard:** public CloudFront URL under `/assets/` — use only to **download** into `public/` (`confirm-ui-config` or `downloadWizardLogoToPublic`). Do **not** use as `img src` in the survey (wrong S3 prefix vs deploy bundle).
130
+ 3. **`global.logo.url` after local wizard:** must be `null` (CLI strips `data:` on save). If you still see `data:image/…` in JSON, re-save from wizard or clear `url` manually.
131
+ 4. **AWS static export:** `src="./{fileName}"` (leading `./`). Absolute `/file.png` breaks under `/sites/{surveyId}/{deployId}/`.
132
+ 5. Prefer plain `<img data-cfm-logo>` over `next/image` for logo files — simpler relative paths in `out/`.
133
+
134
+ **Verify before Phase 7:**
135
+
136
+ ```bash
137
+ LOGO=$(python3 -c "import json; c=json.load(open('survey-ui-config.json')); print((c.get('global') or {}).get('logo', {}).get('fileName') or '')")
138
+ test -n "$LOGO" && test -f "public/$LOGO" || echo "WARN: no logo file"
139
+ yarn build
140
+ test -f "out/$LOGO" && echo "Logo in static output — safe to deploy"
141
+ ```
142
+
143
+ Full deploy pipeline: [`aws-deploy.md`](aws-deploy.md) § Logos & local assets.
144
+
145
+ ### 9. Promote active config (AWS review only)
146
+
147
+ ```bash
148
+ npx cfm-sdk confirm-ui-config
149
+ ```
150
+
151
+ Run **after** codebase apply succeeds.
152
+
153
+ ### 10. Verify nothing missed
154
+
155
+ ```bash
156
+ bash templates/verify-agent-build.sh
157
+ npm run build
158
+ ```
159
+
160
+ **Diff cross-check:** For each path in `survey-ui-config.diff.json` → `changed` + `added` + `removed`, confirm a corresponding update exists (CSS var, DOM attr, or layout branch). If a path has no mapping in this doc, search `wizard-question-type-styling.md` and `templates/survey-theme.css`.
161
+
162
+ ---
163
+
164
+ ## Complete config path → apply target
165
+
166
+ ### `global.colorScheme`
167
+
168
+ | Path | CSS variable |
169
+ |------|----------------|
170
+ | `primary` | `--cfm-primary` |
171
+ | `secondary` | `--cfm-secondary` |
172
+ | `accent` | `--cfm-accent` |
173
+ | `background` | `--cfm-background` (fallback; `theme.pageBackground` wins) |
174
+ | `text` | `--cfm-text` |
175
+ | `buttonText` | `--cfm-button-text` |
176
+
177
+ ### `global.theme` (Question card + chrome)
178
+
179
+ | Path | CSS variable / effect |
180
+ |------|----------------------|
181
+ | `pageBackground` | `--cfm-background` |
182
+ | `cardBackground` | `--cfm-card-bg` |
183
+ | `cardBorderColor` | `--cfm-card-border-color` |
184
+ | `cardPadding` | `--cfm-card-padding` |
185
+ | `cardShadowEnabled` | `--cfm-card-shadow` |
186
+ | `cellSelectedColor` | `--cfm-matrix-selected`, `--cfm-mcq-selected-accent`, `--cfm-csat-ring-color` |
187
+ | `focusRingColor` | `--cfm-input-focus-ring` |
188
+ | `selectedBackground` | `--cfm-selected-bg`, `--cfm-mcq-selected-bg` |
189
+ | `zebraRowColor` | `--cfm-zebra-row` |
190
+ | `rowBandColor` | `--cfm-row-band` |
191
+ | `validationBorder` | `--cfm-validation-border` |
192
+ | `validationBackground` | `--cfm-validation-bg` |
193
+ | `tooltipBackground` | `--cfm-tooltip-bg` |
194
+ | `progressTrackHeight` | `--cfm-progress-height` |
195
+ | `progressTrackColor` | `--cfm-progress-track` |
196
+ | `progressFillColor` | `--cfm-progress-fill` |
197
+ | `stickyChromePaddingTop` | `--cfm-sticky-pt` |
198
+ | `stickyChromePaddingBottom` | `--cfm-sticky-pb` |
199
+ | `languageSelectorBackground` | `--cfm-language-bg` |
200
+ | `languageSelectorTextColor` | `--cfm-language-text` |
201
+ | `languageSelectorBorderColor` | `--cfm-language-border` |
202
+
203
+ ### `global.header`
204
+
205
+ | Path | CSS variable |
206
+ |------|----------------|
207
+ | `height` | `--cfm-header-height` |
208
+ | `logoBoxWidth` | `--cfm-header-logo-width` |
209
+ | `logoBoxHeight` | `--cfm-header-logo-height` |
210
+ | `logoPadding` | `--cfm-header-logo-padding` |
211
+ | `logoPlacement` | `--cfm-header-logo-col`, `--cfm-header-logo-justify` |
212
+ | `showCompanyName` | `--cfm-header-show-company` |
213
+ | `companyNamePlacement` | `--cfm-header-company-col`, `--cfm-header-company-justify` |
214
+ | `companyNameFontSize` | `--cfm-header-company-size` |
215
+ | `companyNameFontWeight` | `--cfm-header-company-weight` |
216
+ | `companyNameColor` | `--cfm-header-company-color` |
217
+ | `backgroundColor` | `--cfm-header-bg` |
218
+ | `shadowEnabled` | `--cfm-header-shadow` |
219
+ | `borderBottomColor` | `--cfm-header-border` |
220
+ | `contentPaddingX` | `--cfm-header-padding-x` |
221
+
222
+ ### `global.footer`
223
+
224
+ | Path | CSS variable / DOM |
225
+ |------|-------------------|
226
+ | `backgroundColor` | `--cfm-footer-bg` |
227
+ | `textColor` | `--cfm-footer-text` |
228
+ | `linkColor` | `--cfm-footer-link` |
229
+ | `linkHoverColor` | `--cfm-footer-link-hover` |
230
+ | `showLogo` | layout flag + footer logo slot |
231
+ | `logoWidth` / `logoHeight` | `--cfm-footer-logo-width`, `--cfm-footer-logo-height` |
232
+ | `logoPlacement` | `--cfm-footer-logo-col`, grid vars |
233
+ | `copyrightText` | `data-cfm-copyright` |
234
+ | `layout` | `--cfm-footer-layout`, `--cfm-footer-inner-display` |
235
+ | `paddingY` / `paddingX` | `--cfm-footer-padding-y`, `--cfm-footer-padding-x` |
236
+ | `links[]` | `data-cfm-footer-links` |
237
+
238
+ ### `global.typography` + `global.motion`
239
+
240
+ | Path | CSS variable |
241
+ |------|----------------|
242
+ | `typography.fontFamily` | fallback for `--cfm-font-family` |
243
+ | `typography.headingWeight` | `--cfm-heading-weight` |
244
+ | `motion.durationMs` | `--cfm-motion-duration` |
245
+
246
+ ### `questionTypes.MCQ`
247
+
248
+ | Path | Apply |
249
+ |------|-------|
250
+ | `optionStyle` / `cardStyle` | `data-cfm-mcq-style` |
251
+ | `optionGap` | `--cfm-mcq-option-gap` |
252
+ | `borderRadius` | `--cfm-mcq-border-radius` |
253
+ | `optionPadding` / `cardPadding` | `--cfm-mcq-card-padding` |
254
+ | `hoverBorderColor` | `--cfm-mcq-hover-border` |
255
+ | Selection colors | from `global.theme` cellSelected + focusRing |
256
+
257
+ ### `questionTypes.TEXTFIELD`
258
+
259
+ | Path | CSS variable |
260
+ |------|----------------|
261
+ | `inputRadius` | `--cfm-input-radius` |
262
+ | `borderColor` | `--cfm-input-border` |
263
+ | `inputPadding` | `--cfm-input-padding` |
264
+ | `inputHeight` | `--cfm-input-height` |
265
+ | `placeholderColor` | `--cfm-input-placeholder` |
266
+ | `defaultPlaceholder` | placeholder text in preview / optional default |
267
+
268
+ ### `questionTypes.NPS_SCALE`
269
+
270
+ | Path | CSS variable / DOM |
271
+ |------|-------------------|
272
+ | `buttonStyle` | `data-cfm-nps-button-style` |
273
+ | `selectedFill` | `--cfm-nps-selected-fill` |
274
+ | `trackBarColor` | `--cfm-nps-track-bar` |
275
+ | `trackHighlightColor` | `--cfm-nps-track-highlight` |
276
+ | `cellSize` / `cellGap` | `--cfm-nps-cell-size`, `--cfm-nps-cell-gap` |
277
+ | `hintMinText` / `hintMaxText` | NPS anchor row text |
278
+ | `hintLabelColor` / `hintLabelBgColor` | `--cfm-hint-label-color`, `--cfm-hint-label-bg` |
279
+ | `numberLabelMode` | `--cfm-number-label-mode` |
280
+ | `monochromeNumberColor` | `--cfm-number-mono-color` |
281
+ | `individualNumberColors[n]` | `--cfm-number-color-{n}` |
282
+
283
+ ### `questionTypes.CFM_MATRIX`
284
+
285
+ | Path | CSS variable |
286
+ |------|----------------|
287
+ | `rowLabelWidth` | `--cfm-matrix-row-width` |
288
+ | `bipolarColumnWidthPercent` | `--cfm-matrix-bipolar-width` |
289
+ | `cellPadding` | `--cfm-matrix-cell-padding` |
290
+ | `columnLabelColor` / `columnLabelBgColor` | `--cfm-matrix-column-label-color`, `--cfm-matrix-column-label-bg` |
291
+
292
+ ### `questionTypes.CSAT_MATRIX` / `RATING_MATRIX`
293
+
294
+ | Path | CSS variable |
295
+ |------|----------------|
296
+ | `emojiSize` | `--cfm-csat-emoji-size` |
297
+ | `unselectedOpacity` | `--cfm-csat-unselected-opacity` |
298
+ | `cellSize` | `--cfm-csat-cell-size` |
299
+ | `tooltipBg` | `--cfm-csat-tooltip-bg` |
300
+ | `rowLabelWidth` | `--cfm-matrix-row-width` |
301
+ | `columnLabelColor` / `columnLabelBgColor` | `--cfm-csat-column-label-*` |
302
+ | Number label fields | same as NPS `--cfm-number-*` |
303
+
304
+ ### `questionTypes.SLIDER_MATRIX`
305
+
306
+ | Path | CSS variable |
307
+ |------|----------------|
308
+ | `trackColor` / `thumbColor` | slider track vars in theme |
309
+ | `tickLabelColor` / `tickLabelBgColor` | `--cfm-slider-tick-label-color`, `--cfm-slider-tick-label-bg` |
310
+ | Row band | `--cfm-row-band` from global theme |
311
+
312
+ ### `questionTypes.FILE_UPLOAD`
313
+
314
+ | Path | Apply |
315
+ |------|-------|
316
+ | `dropzoneStyle` | `data-cfm-dropzone-style` |
317
+ | `borderColor` | `--cfm-upload-border-color` |
318
+
319
+ ### `questionTypes.HEATMAP`
320
+
321
+ | Path | CSS variable |
322
+ |------|----------------|
323
+ | `pinColor` | `--cfm-heatmap-pin` |
324
+ | `pinSize` | `--cfm-heatmap-pin-size` |
325
+ | `pinBorderColor` | `--cfm-heatmap-pin-border` |
326
+
327
+ ### `questionTypes.RANK_ORDER`
328
+
329
+ | Path | CSS variable |
330
+ |------|----------------|
331
+ | `drag.itemBg` / `dropdown.itemBg` | `--cfm-rank-item-bg` |
332
+ | `drag.rankBadgeColor` / `dropdown.rankBadgeColor` | `--cfm-rank-badge` |
333
+ | `drag.itemPadding` / `itemGap` | `--cfm-rank-item-padding`, `--cfm-rank-item-gap` |
334
+ | `drag.dragHandleColor` | `--cfm-rank-handle` |
335
+ | `dropdown.selectBorderColor` | `--cfm-rank-select-border` |
336
+
337
+ ### `deploy`
338
+
339
+ | Path | Phase 7 |
340
+ |------|---------|
341
+ | `deploy.target` | `aws` → `aws-deploy.md`; `vercel` → `npx cfm-sdk deploy` |
342
+ | `deploy.autoDeploy` | informational — agent still asks INPUT 4 |
343
+
344
+ ---
345
+
346
+ ## Diff-driven apply (zero omissions)
347
+
348
+ When `survey-ui-config.diff.json` exists:
349
+
350
+ 1. Load `diff.changed`, `diff.added`, `diff.removed`
351
+ 2. For each entry, look up `entry.path` in the tables above
352
+ 3. Apply the **After** value (or remove DOM/CSS for `removed`)
353
+ 4. Track progress: `appliedCount === changed.length + added.length + removed.length`
354
+
355
+ **Categories easy to miss** (always check diff for these):
356
+
357
+ - `global.footer.links` (array — full replace)
358
+ - `global.header.showCompanyName` + placement pairs
359
+ - `questionTypes.*.individualNumberColors` (array)
360
+ - `placeholders.*` (every key)
361
+ - `customFields.*` (every `_c_` key)
362
+ - `global.theme.cellSelectedColor` + `focusRingColor` (drive all scale selections)
363
+ - `global.logo.fileName` (image swap)
364
+ - `global.logo.url` (download reference — ensure file in `public/`)
365
+
366
+ ---
367
+
368
+ ## Selection styling (verify after apply)
369
+
370
+ ```tsx
371
+ import { scaleRadioRingStyle, scaleRadioDotStyle } from '@/lib/surveyUi/selectionStyles';
372
+ ```
373
+
374
+ Ensure components use `selectionStyles.ts` — config only changes CSS vars, not component structure.
375
+
376
+ ---
377
+
378
+ ## Re-run policy
379
+
380
+ Do not re-run the wizard unless the client explicitly requests another session. Each run overwrites config artifacts.
381
+
382
+ ---
383
+
384
+ ## Related
385
+
386
+ | Doc | Role |
387
+ |-----|------|
388
+ | [`wizard-config-handoff.md`](wizard-config-handoff.md) | Wait + capture + confirm order |
389
+ | [`wizard-question-type-styling.md`](wizard-question-type-styling.md) | Visual selection patterns |
390
+ | [`agent-operating-contract.md`](agent-operating-contract.md) | Do not change dispatch logic |