@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
@@ -18,6 +18,61 @@ Survey logic rules may reference **custom fields** instead of survey questions:
18
18
 
19
19
  Inspect fetched survey data: any `skipLogics`, `displayLogic`, or `answerLogic` with `entityType: 'CUSTOM_FIELD'` requires client-supplied values.
20
20
 
21
+ Copy portable template: [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts`. See [`client-lib-folder.md`](client-lib-folder.md) and **[`placeholders-and-custom-fields-wiring.md`](placeholders-and-custom-fields-wiring.md)** for precise key discovery and two-point wiring.
22
+
23
+ ---
24
+
25
+ ## Agent implementation recipe
26
+
27
+ 1. **After fetch** — scan `survey.pages` (and `endPages` logic) for `conditionEntity.entityType === 'CUSTOM_FIELD'`. Collect every `conditionEntity.id` (`_c_…`).
28
+ 2. **Record** each id in `implementation_plan.md` §3d with `fieldType`, logic kind (skip/display/answer/end), and expected CRM value shape.
29
+ 3. **Copy** [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts`. Populate from CRM/transaction API — **not** inline in `SurveyPage`.
30
+ 4. **Wire hook** — import map and pass in stable `useMemo` options:
31
+
32
+ ```typescript
33
+ import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
34
+
35
+ const surveyOptions = useMemo(
36
+ () => ({
37
+ instanceId,
38
+ placeholders: SURVEY_PLACEHOLDERS,
39
+ customFieldValues: CUSTOM_FIELD_VALUES,
40
+ }),
41
+ [instanceId, selectedLanguage]
42
+ );
43
+ ```
44
+
45
+ 5. **Wire Question** — pass the **same** map as `customFieldValues` prop (template `Question.tsx` already forwards it to `getVisible*ForAnswers`).
46
+ 6. **Verify** — trigger a custom-field skip rule on Next; no per-question client evaluator code needed.
47
+
48
+ **Blocking gate:** if any `_c_…` id exists in fetched survey → `src/lib/customFieldValues.ts` must exist before Phase 5 BUILD.
49
+
50
+ ### Fixture example (integration-test survey)
51
+
52
+ Page 2 `SLIDER_MATRIX` has a skip rule:
53
+
54
+ ```json
55
+ {
56
+ "conditionEntity": {
57
+ "id": "_c_67199096d294be011a2b4773",
58
+ "entityType": "CUSTOM_FIELD",
59
+ "fieldType": "TEXT"
60
+ },
61
+ "field": "CASE_SENSITIVE_TEXT",
62
+ "values": ["abc"]
63
+ }
64
+ ```
65
+
66
+ Client map:
67
+
68
+ ```typescript
69
+ export const CUSTOM_FIELD_VALUES: CustomFieldValueMap = {
70
+ '_c_67199096d294be011a2b4773': 'abc',
71
+ };
72
+ ```
73
+
74
+ When this value matches, SDK skip logic runs on Next — values must be in **hook options**, not typed by the respondent.
75
+
21
76
  ---
22
77
 
23
78
  ## Client value map
@@ -172,3 +227,4 @@ When a question has several `skipLogics[]` entries (including custom-field rules
172
227
  - [`display-logic-and-navigation.md`](display-logic-and-navigation.md) — question-level gating
173
228
  - [`answer-logic-and-navigation.md`](answer-logic-and-navigation.md) — option/row/column gating + visibility helpers
174
229
  - [`client-integration-guide.md`](client-integration-guide.md) — full wiring map
230
+ - [`client-lib-folder.md`](client-lib-folder.md) — lib folder layout + portable templates
@@ -0,0 +1,113 @@
1
+ # Mockup & Client Prompt — UI-Only Extraction
2
+
3
+ > **Read in Phase 0–4** before fetch and before filling `implementation_plan.md`.
4
+ > Pipeline: [`agent-operating-contract.md`](agent-operating-contract.md) · [`agent-execution-flow.md`](agent-execution-flow.md)
5
+
6
+ Client mockup images and prompts are **visual references** for chrome and styling. They are **not** the survey definition. Logic, language, question inventory, and CRM data come **only** from the fetched survey (JWT) and host-app context.
7
+
8
+ ---
9
+
10
+ ## Prime rule
11
+
12
+ | Source | Authoritative for |
13
+ |--------|-----------------|
14
+ | **Mockup image / prompt** | UI look-and-feel only (see table below) |
15
+ | **Fetched survey (JWT)** | Question types, text, logic, languages, placeholders in question copy, custom-field ids |
16
+ | **Host / CRM / transaction** | `customFieldValues` runtime values |
17
+ | **Client (explicit)** | JWT, wizard yes/no, deploy yes/no |
18
+
19
+ **Never invent survey behavior from a mockup.** A single NPS screenshot does not mean the survey has only NPS, one language, or specific skip rules.
20
+
21
+ ---
22
+
23
+ ## Extract from mockup (UI only)
24
+
25
+ Use mockup / prompt for **chrome and tokens** — record in `implementation_plan.md` §0 and draft `survey-theme.css` / `survey-ui-config.json`:
26
+
27
+ | Extract | Examples | Where it goes |
28
+ |---------|----------|---------------|
29
+ | **Brand colors** | Primary pink, footer dark gray, page background | `--cfm-primary`, `--cfm-footer-bg`, `global.colorScheme` |
30
+ | **Logo style** | Image vs text/CSS logo, placement | `Header.tsx` pattern (`data-cfm-logo` or `data-cfm-logo-text`) |
31
+ | **Header layout** | Logo left, company name, sticky bar | `global.header.*`, header CSS vars |
32
+ | **Footer layout** | Logo, links row, copyright | `global.footer.*`, `data-cfm-footer-links` |
33
+ | **Chrome copy (display text)** | Survey title, company name, button labels, thank-you line, footer link labels | `global.surveyTitle`, `global.companyName`, `global.buttons`, `global.footer.links` — **wording only** |
34
+ | **Progress bar presence** | Visible track under header | `global.layout.showProgressBar` default |
35
+ | **Typography / corners** | Rounded cards, font family | `global.layout.borderStyle`, `global.layout.fontStyle` |
36
+ | **Question card feel** | Card background, border, shadow | `global.theme.*` |
37
+ | **Scale visual style (reference)** | NPS traffic-light, star vs numbered — as **styling hint** | Per-type tokens in `questionTypes.*` after you know types from fetch |
38
+
39
+ Chrome text from mockup (e.g. "Telekom Umfrage", "Impressum") is **UI copy** — safe to seed branding. It does **not** replace question text from the API.
40
+
41
+ ---
42
+
43
+ ## Do NOT extract from mockup (survey myths)
44
+
45
+ | Do not infer | Why | Correct source |
46
+ |--------------|-----|----------------|
47
+ | **Question types** in survey | Image shows one screen (e.g. NPS) | Unique `question.type` from **fetched** `survey.pages` |
48
+ | **Question count / order** | Mockup is one page | Fetched survey structure |
49
+ | **Question text / labels** | May be sample or translated | `question.questionText`, `options`, matrix rows from fetch |
50
+ | **Language** (`de` vs `en`) | UI locale in screenshot ≠ survey language | `survey.language`, `supportedLanguages` from fetch; `useSurveySDK({ language })` |
51
+ | **Skip / display / answer logic** | Not visible in static image | `skipLogics`, `displayLogic`, `answerLogic` on fetched pages |
52
+ | **Custom field ids or values** | CRM data not in mockup | Scan fetch for `_c_…` ids — [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) |
53
+ | **Placeholder keys** (`{{FIRST_NAME}}`) | Tokens in mockup may be examples | Scan **fetched** question text for `{{…}}` tokens |
54
+ | **Validation rules** | Not shown in design | SDK + fetched `validation` |
55
+ | **End pages / intro copy** | Unless clearly labeled as chrome | `survey.pages` / `endPages` from fetch |
56
+ | **`surveyTypes` for wizard** | Mockup ≠ wizard inventory | All **11** types for wizard; fetched types for dispatch only |
57
+
58
+ **Blocking rule:** `implementation_plan.md` §3b inventory table is filled from **fetch**, not from mockup filename or image content.
59
+
60
+ ---
61
+
62
+ ## Agent workflow
63
+
64
+ ### Phase 0 — Mockup pass (UI notebook only)
65
+
66
+ 1. Note colors, header/footer structure, logo mode, button style, card chrome.
67
+ 2. Write **Branding source** in `implementation_plan.md` §0 — describe UI only.
68
+ 3. Do **not** write question-type rows or logic rows yet.
69
+
70
+ ### Phase 2–4 — Fetch pass (survey truth)
71
+
72
+ 1. Ask client for JWT; fetch survey.
73
+ 2. List unique `question.type` values → §3b (from API).
74
+ 3. Scan logic → §3d custom fields, §3e logic inventory (from API).
75
+ 4. Scan question text for `{{TOKEN}}` → placeholder keys (from API).
76
+ 5. Override mockup only where client **explicitly** contradicts fetch in written prompt (rare — prefer fetch for survey content).
77
+
78
+ ### Phase 5 — Merge
79
+
80
+ | From mockup | From fetch |
81
+ |-------------|------------|
82
+ | CSS vars, chrome layout, default button labels | `Question.tsx` branches, scale fixtures, logic wiring |
83
+ | `data-cfm-*` hooks | `getVisible*ForAnswers`, `customFieldValues` |
84
+
85
+ ---
86
+
87
+ ## Common myths (avoid)
88
+
89
+ | Myth | Reality |
90
+ |------|---------|
91
+ | "Mockup shows NPS → build only NPS" | Build all types in **fetch**; wizard still shows all 11 for customization |
92
+ | "German text in image → hardcode `language: 'de'`" | Set language from survey + selector; mockup language is not authoritative |
93
+ | "Footer says Datenschutz → survey has privacy logic" | Footer link is chrome — wire `global.footer.links`; no extra SDK logic |
94
+ | "Question 6 in image → survey has 6 questions" | Numbering is path-scoped; count pages from fetch |
95
+ | "Red asterisk in mockup → question.required on that id" | Required flags come from fetched questions |
96
+
97
+ ---
98
+
99
+ ## Wizard note
100
+
101
+ Mockup drives **seed** colors and chrome text in `survey-ui-config.json`. Wizard **Question Types** step still lists all 11 literals — see [`wizard-troubleshooting.md`](wizard-troubleshooting.md) §4.
102
+
103
+ ---
104
+
105
+ ## Related docs
106
+
107
+ | Doc | Role |
108
+ |-----|------|
109
+ | [`placeholders-and-tokens.md`](placeholders-and-tokens.md) | Placeholder keys from fetch |
110
+ | [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) | `_c_…` ids from fetch |
111
+ | [`logic-fields-catalog.md`](logic-fields-catalog.md) | Logic fields (do not invent) |
112
+ | [`canonical-survey-fixtures.md`](canonical-survey-fixtures.md) | Matrix/slider shapes from fetch |
113
+ | [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) | Tokenize UI for live preview |
@@ -0,0 +1,192 @@
1
+ # Placeholders & Custom Fields — Precise SDK Wiring
2
+
3
+ > **Read in Phase 4–5** after survey fetch. Companion: [`placeholders-and-tokens.md`](placeholders-and-tokens.md), [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md), [`mockup-ui-extraction.md`](mockup-ui-extraction.md).
4
+
5
+ Agents must pass **exact keys** from the fetched survey and CRM context into `useSurveySDK` — not guesses from mockup text.
6
+
7
+ ---
8
+
9
+ ## Two different maps (do not conflate)
10
+
11
+ | Map | Key format | Purpose | Value source |
12
+ |-----|------------|---------|----------------|
13
+ | **`placeholders`** | `FIRST_NAME`, `COMPANY` (no braces) | Replace `{{FIRST_NAME}}` in question copy at map time | CRM / marketing context or wizard `placeholders.*` |
14
+ | **`customFieldValues`** | `_c_…` ids from logic rules | Skip, display, answer, end, progress evaluation | CRM / transaction API — **not** respondent UI |
15
+
16
+ Mockup images do **not** define either map. Discover keys from **fetched survey JSON**.
17
+
18
+ ---
19
+
20
+ ## Step 1 — Discover placeholder keys (after fetch)
21
+
22
+ Scan all `questionText`, `questionDescription`, display variant bodies, intro/end copy for tokens:
23
+
24
+ ```
25
+ {{FIRST_NAME}}
26
+ {{COMPANY}}
27
+ {{SURVEY_QUESTION-:-<questionId>}}
28
+ ```
29
+
30
+ **CRM placeholders** — add to `SURVEY_PLACEHOLDERS`:
31
+
32
+ ```typescript
33
+ // src/lib/placeholders.ts (or module scope in SurveyPage.tsx)
34
+ export const SURVEY_PLACEHOLDERS = {
35
+ FIRST_NAME: 'Alex', // key = token name without {{ }}
36
+ COMPANY: 'Acme Corp',
37
+ } as const;
38
+ ```
39
+
40
+ Rules:
41
+
42
+ - Key must match token name **exactly** (case-sensitive per survey).
43
+ - Values are **display strings** for CRM/marketing — not survey answers.
44
+ - Omit keys not present in fetched text (do not copy example lists from docs blindly).
45
+ - **Answer tokens** `{{SURVEY_QUESTION-:-id}}` are **not** in `placeholders` — resolved at render via `resolveSurveyQuestionPlaceholders`.
46
+
47
+ Record discovered keys in `implementation_plan.md`:
48
+
49
+ ```markdown
50
+ ## Placeholder inventory (from fetch)
51
+ | Token | Key in SURVEY_PLACEHOLDERS | Example value | Found in question ids |
52
+ | {{FIRST_NAME}} | FIRST_NAME | … | q1, q3 |
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Step 2 — Wire placeholders (stable ref + hook)
58
+
59
+ ```typescript
60
+ import { useMemo } from 'react';
61
+ import { useSurveySDK } from '@explorer02/cfm-survey-sdk';
62
+ import { SURVEY_PLACEHOLDERS } from '@/lib/placeholders';
63
+ import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
64
+
65
+ const surveyOptions = useMemo(
66
+ () => ({
67
+ instanceId: SURVEY_INSTANCE_ID,
68
+ language: selectedLanguage,
69
+ placeholders: SURVEY_PLACEHOLDERS,
70
+ customFieldValues: CUSTOM_FIELD_VALUES,
71
+ }),
72
+ [selectedLanguage],
73
+ );
74
+
75
+ const { state, onAction, surveyQueryResults } = useSurveySDK({ options: surveyOptions });
76
+ ```
77
+
78
+ **Failure modes:**
79
+
80
+ | Mistake | Symptom |
81
+ |---------|---------|
82
+ | Inline `placeholders={{ ... }}` in component | Infinite re-fetch |
83
+ | Key missing from map | Literal `{{FIRST_NAME}}` in UI |
84
+ | Mockup name instead of token key | Wrong or missing substitution |
85
+
86
+ ---
87
+
88
+ ## Step 3 — Discover custom field ids (after fetch)
89
+
90
+ Scan `survey.pages[].skipLogics`, `displayLogic`, `answerLogic`, and `endPages` for:
91
+
92
+ ```json
93
+ "conditionEntity": { "entityType": "CUSTOM_FIELD", "id": "_c_67199096d294be011a2b4773", "fieldType": "TEXT" }
94
+ ```
95
+
96
+ Collect **every** `_c_…` id. Fill `implementation_plan.md` §3d.
97
+
98
+ Copy template → `src/lib/customFieldValues.ts`:
99
+
100
+ ```typescript
101
+ import type { CustomFieldValueMap } from '@explorer02/cfm-survey-sdk';
102
+
103
+ export const CUSTOM_FIELD_VALUES: CustomFieldValueMap = {
104
+ '_c_67199096d294be011a2b4773': 'abc', // TEXT — exact id from fetch
105
+ // '_c_…': 2, // NUMBER
106
+ // '_c_…': 'picklist-option-uuid', // PICKLIST
107
+ };
108
+ ```
109
+
110
+ ### Value shape by `fieldType` (must match SDK evaluator)
111
+
112
+ | fieldType | Pass |
113
+ |-----------|------|
114
+ | `TEXT`, `TEXT_MULTI`, `TEXTAREA` | `string` |
115
+ | `NUMBER` | `number` or numeric `string` |
116
+ | `PICKLIST` | option **id** string |
117
+ | `PICKLIST_MULTISELECT` | `string[]` of option ids |
118
+ | `DATETIME` | epoch ms (`number` or numeric string) |
119
+
120
+ Missing keys → treated as empty for logic. Wrong shape → rule may never match.
121
+
122
+ **Values come from CRM/transaction** — ask client or integration spec when not in prompt. Do **not** invent ids or values from mockup.
123
+
124
+ ---
125
+
126
+ ## Step 4 — Wire custom fields (two places — same map)
127
+
128
+ ### A. Hook
129
+
130
+ ```typescript
131
+ customFieldValues: CUSTOM_FIELD_VALUES, // inside useMemo surveyOptions
132
+ ```
133
+
134
+ ### B. Question + visibility helpers
135
+
136
+ ```tsx
137
+ <Question
138
+ customFieldValues={CUSTOM_FIELD_VALUES}
139
+ allAnswers={state.answers}
140
+ allQuestions={allQuestions}
141
+ ...
142
+ />
143
+ ```
144
+
145
+ Inside `Question.tsx` (from template):
146
+
147
+ ```typescript
148
+ getVisibleMcqOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues);
149
+ getVisibleMatrixItemsForAnswers(question, allAnswers, allQuestions, customFieldValues);
150
+ getVisibleRankOrderOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues);
151
+ ```
152
+
153
+ **Fourth argument must be the same map** as hook options whenever logic references `CUSTOM_FIELD`.
154
+
155
+ ---
156
+
157
+ ## Step 5 — Wizard overrides (Phase 6c)
158
+
159
+ When client uses wizard, `survey-ui-config.json` may include:
160
+
161
+ | Config path | Code update |
162
+ |-------------|-------------|
163
+ | `placeholders.firstName` etc. | Merge into `SURVEY_PLACEHOLDERS` (wizard keys → SDK token keys per [`apply-ui-config.md`](apply-ui-config.md)) |
164
+ | `customFields._c_…` | Merge into `CUSTOM_FIELD_VALUES` |
165
+
166
+ Wizard **Testing & Tokens** step edits config only — you still wire stable refs in code after `confirm-ui-config`.
167
+
168
+ ---
169
+
170
+ ## Verification checklist
171
+
172
+ - [ ] Placeholder keys discovered by **scanning fetched survey text**, not mockup
173
+ - [ ] `SURVEY_PLACEHOLDERS` at module scope; keys match `{{TOKEN}}` names
174
+ - [ ] Every `_c_…` id in logic appears in `CUSTOM_FIELD_VALUES`
175
+ - [ ] Value shapes match `fieldType` from fetch
176
+ - [ ] `useMemo` wraps hook `options`
177
+ - [ ] `customFieldValues` passed to hook **and** `Question`
178
+ - [ ] `getVisible*ForAnswers` receives 4th arg when CRM logic exists
179
+ - [ ] `resolveSurveyQuestionPlaceholders` used for answer tokens in question shell
180
+ - [ ] No placeholder or custom-field keys invented from mockup image
181
+
182
+ ---
183
+
184
+ ## Related
185
+
186
+ | Doc | Role |
187
+ |-----|------|
188
+ | [`mockup-ui-extraction.md`](mockup-ui-extraction.md) | UI-only vs fetch |
189
+ | [`placeholders-and-tokens.md`](placeholders-and-tokens.md) | Token resolution stages |
190
+ | [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) | Logic evaluation contract |
191
+ | [`client-lib-folder.md`](client-lib-folder.md) | File layout |
192
+ | [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) | Copy template |
@@ -1,6 +1,7 @@
1
1
  # Placeholders and Tokens
2
2
 
3
- > Covers `sdkFeatures.placeholderResolution` — how CRM and dynamic answer tokens resolve in question text.
3
+ > Covers `sdkFeatures.placeholderResolution` — how CRM and dynamic answer tokens resolve in question text.
4
+ > **Agent wiring (discover keys from fetch):** [`placeholders-and-custom-fields-wiring.md`](placeholders-and-custom-fields-wiring.md)
4
5
 
5
6
  ---
6
7
 
@@ -52,10 +52,12 @@ Survey: 4 questions on active path (Q1–Q4 sequential).
52
52
 
53
53
  ## UI wiring
54
54
 
55
+ On the **content** phase, render progress inside sticky chrome so it stays visible when scrolling to the last question on a page:
56
+
55
57
  ```tsx
56
- <ProgressBar progressPercentage={state.progressPercentage} />
58
+ <SurveyStickyChrome progressPercentage={state.progressPercentage} />
57
59
  ```
58
60
 
59
- See [`01-components/11-progress-bar.md`](../01-components/11-progress-bar.md) and [`03-ui-specs/12-survey-chrome.md`](../03-ui-specs/12-survey-chrome.md).
61
+ See [`01-components/19-survey-sticky-chrome.md`](../01-components/19-survey-sticky-chrome.md), [`01-components/11-progress-bar.md`](../01-components/11-progress-bar.md), and [`03-ui-specs/12-survey-chrome.md`](../03-ui-specs/12-survey-chrome.md).
60
62
 
61
63
  See also: [`skip-logic-and-navigation.md`](skip-logic-and-navigation.md).
@@ -132,6 +132,18 @@ else → ask client which React setup to use
132
132
 
133
133
  For **existing apps**, read `package.json` and project structure — do not scaffold from scratch unless the client asks.
134
134
 
135
+ ### Recommended `src/lib/` scaffold
136
+
137
+ ```
138
+ src/lib/
139
+ ├── customFieldValues.ts ← templates/customFieldValues.ts (when CUSTOM_FIELD logic)
140
+ ├── surveyUiScaleUtils.ts ← templates/surveyUiScaleUtils.ts
141
+ ├── surveyUiIcons.tsx ← templates/surveyUiIcons.tsx (optional co-locate)
142
+ └── heatmapCoords.ts ← templates/heatmapCoords.ts (HEATMAP only)
143
+ ```
144
+
145
+ See [`client-lib-folder.md`](client-lib-folder.md).
146
+
135
147
  ---
136
148
 
137
149
  ## Survey-type conditional dependencies
@@ -0,0 +1,123 @@
1
+ # UI Customization Wizard
2
+
3
+ > Optional **run** after Phase 6 verify. **Wizard-ready build** is mandatory in Phase 5 — see [`agent-execution-flow.md`](agent-execution-flow.md).
4
+
5
+ ## Default: local wizard (`customize`)
6
+
7
+ When the client says **yes** to customization in agent chat, **always run:**
8
+
9
+ ```bash
10
+ npx cfm-sdk customize
11
+ ```
12
+
13
+ This is the **recommended default** because it:
14
+
15
+ - Serves wizard + component previews from **one local server** (`localhost:4200`)
16
+ - Auto-exports all **11** question-type previews from agent components
17
+ - Writes `survey-ui-config.json` **directly** on save — no S3, no session polling
18
+ - Cleans up automatically when the CLI exits (no orphan S3 garbage)
19
+ - Updates live previews via the same iframe + preview bridge as production
20
+
21
+ **Agent script after client says yes:**
22
+
23
+ > *"I'll open the customization wizard in your browser. Complete all steps and click **Review & Build** when done — I'll apply your changes automatically."*
24
+
25
+ The CLI **blocks** until the client saves. Wait for:
26
+
27
+ ```
28
+ ✅ UI configuration saved to survey-ui-config.json
29
+ ```
30
+
31
+ Then apply per [`apply-ui-config.md`](apply-ui-config.md).
32
+
33
+ ### Who can use it
34
+
35
+ | User | Can use `customize`? |
36
+ |------|---------------------|
37
+ | Client on **same machine** as agent (Cursor chat on dev laptop) | **Yes — default** |
38
+ | Client on **another device** | **No** — use EC2 fallback below |
39
+
40
+ `localhost:4200` is only reachable on the machine running the CLI.
41
+
42
+ ---
43
+
44
+ ## EC2 fallback (`customize-ui`) — remote clients only
45
+
46
+ Use **only** when the client must customize from another PC/tablet/network:
47
+
48
+ ```bash
49
+ export CFM_INSTANCE_ID="..." CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
50
+ npx cfm-sdk customize-ui
51
+ ```
52
+
53
+ - Uploads previews to EC2 disk (local-server model on remote host)
54
+ - Prints EC2 wizard link — agent sends link to client
55
+ - CLI **polls** until client submits → writes `.final.json` + `.diff.md`
56
+ - Requires deploy-api on EC2 + `CFM_INSTANCE_ID`
57
+
58
+ See [`wizard-api.md`](wizard-api.md) and [`wizard-config-handoff.md`](wizard-config-handoff.md).
59
+
60
+ **Do not** use `customize-ui` when client and agent share the same machine — `customize` is simpler and more reliable.
61
+
62
+ ---
63
+
64
+ ## When to ask (INPUT 3)
65
+
66
+ After Phase 6 verify + dev server:
67
+
68
+ > *"Your survey is running locally. Would you like to customize the UI through the web wizard?"*
69
+
70
+ - **Yes** → `npx cfm-sdk customize` (default)
71
+ - **Yes, but I'm on a different device** → `npx cfm-sdk customize-ui`
72
+ - **No** → Phase 7 deploy ask
73
+
74
+ ---
75
+
76
+ ## How local wizard works
77
+
78
+ ```mermaid
79
+ sequenceDiagram
80
+ participant Agent as Agent CLI
81
+ participant Srv as localhost:4200
82
+ participant Wizard as Wizard SPA
83
+ participant Prev as out/previews/
84
+
85
+ Agent->>Agent: export-previews (all 11 types)
86
+ Agent->>Srv: customize serves wizard + previews
87
+ Wizard->>Srv: GET /api/inventory
88
+ Wizard->>Prev: iframe /previews/MCQ_single/...
89
+ Wizard->>Srv: POST /api/save-config
90
+ Srv->>Agent: survey-ui-config.json written, CLI exits
91
+ ```
92
+
93
+ | Route | Purpose |
94
+ |-------|---------|
95
+ | `/api/inventory` | Preview manifest + seed config |
96
+ | `/previews/{key}/index.html` | Component-wise live preview |
97
+ | `/api/save-config` | Client submit → JSON on disk |
98
+ | `/api/upload-logo` | Logo → `public/` |
99
+
100
+ ---
101
+
102
+ ## Seed config
103
+
104
+ | Priority | Source |
105
+ |----------|--------|
106
+ | 1 | `./survey-ui-config.json` (draft) |
107
+ | 2 | `src/styles/survey-theme.css` |
108
+ | 3 | `implementation_plan.md` |
109
+ | 4 | `Header.tsx` logo contract |
110
+ | 5 | SDK defaults |
111
+
112
+ ---
113
+
114
+ ## Agent checklist
115
+
116
+ - [ ] Phase 5: wizard-preview artifacts wired
117
+ - [ ] Client opted in (INPUT 3)
118
+ - [ ] Ran **`npx cfm-sdk customize`** (default) and waited for CLI exit 0
119
+ - [ ] Read `survey-ui-config.json` (or `.diff.md` if used EC2 fallback)
120
+ - [ ] Phase 6c: applied per [`apply-ui-config.md`](apply-ui-config.md)
121
+ - [ ] Re-ran verify + build
122
+
123
+ See [`wizard-troubleshooting.md`](wizard-troubleshooting.md) if previews show mock UI.
@@ -88,7 +88,41 @@ Missing ids in the map are treated as empty for logic evaluation.
88
88
 
89
89
  When the survey uses custom-field logic, also pass the same map into `Question.tsx` visibility helpers — see [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md).
90
90
 
91
- ## Return Shape
91
+ ---
92
+
93
+ ## Custom field values (required when survey uses CRM logic)
94
+
95
+ Custom field values are **not** survey UI inputs — they come from CRM/transaction context (host app API, JWT claims, etc.) and enable SDK evaluation of rules where `entityType: 'CUSTOM_FIELD'`.
96
+
97
+ | Situation | Action |
98
+ |-----------|--------|
99
+ | No `_c_…` ids in fetched survey logic | `customFieldValues: {}` or omit — empty map is fine |
100
+ | Any skip/display/answer/end rule references `CUSTOM_FIELD` | **Required** — copy [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts` |
101
+
102
+ ### Import and wire (two places)
103
+
104
+ ```typescript
105
+ import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
106
+
107
+ // 1. Hook options (skip, display, progress, validation, end-page logic)
108
+ const surveyOptions = useMemo(
109
+ () => ({
110
+ instanceId,
111
+ placeholders: SURVEY_PLACEHOLDERS,
112
+ customFieldValues: CUSTOM_FIELD_VALUES,
113
+ }),
114
+ [instanceId, selectedLanguage]
115
+ );
116
+
117
+ // 2. Question prop (answer-logic UI — same map)
118
+ <Question customFieldValues={CUSTOM_FIELD_VALUES} ... />
119
+ ```
120
+
121
+ **Both wiring points are mandatory** when custom-field logic exists. Hook-only wiring breaks answer-logic UI; Question-only wiring breaks skip/display/progress.
122
+
123
+ Discovery steps: [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) · lib layout: [`client-lib-folder.md`](client-lib-folder.md).
124
+
125
+ ---
92
126
 
93
127
  | Namespace | Field | Type | Purpose |
94
128
  |-----------|-------|------|---------|