@explorer02/cfm-survey-sdk 0.2.4 → 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 (31) hide show
  1. package/dist/cli/index.js +34 -33
  2. package/dist/cli/index.mjs +35 -34
  3. package/package.json +1 -6
  4. package/postinstall.js +2 -1
  5. package/templates/AGENT.md +3 -3
  6. package/templates/docs/00-integration/agent-execution-flow.md +39 -27
  7. package/templates/docs/00-integration/agent-operating-contract.md +13 -5
  8. package/templates/docs/00-integration/apply-ui-config.md +35 -10
  9. package/templates/docs/00-integration/aws-deploy.md +117 -3
  10. package/templates/docs/00-integration/component-checklist.md +4 -2
  11. package/templates/docs/00-integration/constraints.md +3 -2
  12. package/templates/docs/00-integration/custom-field-logic-and-navigation.md +1 -1
  13. package/templates/docs/00-integration/mockup-ui-extraction.md +113 -0
  14. package/templates/docs/00-integration/placeholders-and-custom-fields-wiring.md +192 -0
  15. package/templates/docs/00-integration/placeholders-and-tokens.md +2 -1
  16. package/templates/docs/00-integration/ui-customization-wizard.md +83 -104
  17. package/templates/docs/00-integration/wizard-api.md +74 -82
  18. package/templates/docs/00-integration/wizard-config-handoff.md +55 -9
  19. package/templates/docs/00-integration/wizard-preview-build-guide.md +12 -7
  20. package/templates/docs/00-integration/wizard-question-type-styling.md +4 -2
  21. package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
  22. package/templates/docs/01-components/10-header-footer.md +3 -3
  23. package/templates/docs/MANIFEST.json +30 -13
  24. package/templates/docs/index.md +7 -9
  25. package/templates/docs/templates/deploy-to-aws.sh +74 -0
  26. package/templates/docs/templates/implementation_plan.md +19 -12
  27. package/templates/wizard-dist/assets/{PreviewMock-DgHfrVeb.js → PreviewMock-AoZdAEPZ.js} +1 -1
  28. package/templates/wizard-dist/assets/{TypePanel-CFVC3Ptn.js → TypePanel-39FnbtvG.js} +1 -1
  29. package/templates/wizard-dist/assets/index-CWKdsJOp.js +34 -0
  30. package/templates/wizard-dist/index.html +1 -1
  31. package/templates/wizard-dist/assets/index-DYK3X1e5.js +0 -34
@@ -43,11 +43,11 @@ Use sources **only** in this order. Lower items never override higher ones.
43
43
 
44
44
  | Phase | Read these files **before any code** | Extract and record |
45
45
  |-------|--------------------------------------|--------------------|
46
- | **0** | `agent-operating-contract.md`, `agent-execution-flow.md`, `index.md`, `MANIFEST.json` | Framework, `typeLiterals`, branding notes |
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
47
  | **1** | `setup.md` (framework section) | Install list, AWS export flags if prompt mentions AWS |
48
48
  | **2** | `useSurveySDK.md` | `instanceId` wiring location — then **ask client for JWT** |
49
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, `00-question-shell.md`, `12-survey-chrome.md`, **per-type** MANIFEST routes | Inventory table in `implementation_plan.md` §3b |
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
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
52
  | **6** | `constraints.md`, `component-checklist.md` Step 3–4 | Run `verify-agent-build.sh` — fix failures |
53
53
  | **6b** | `ui-customization-wizard.md`, `wizard-api.md` | CLI env vars — only if client said **yes** |
@@ -84,13 +84,15 @@ Use this table when deciding what to read. **Do not substitute similar-sounding
84
84
  | File upload | `03-ui-specs/10-file-upload.md`, `file-upload-aws.md` | Raw `File[]` in submit payload |
85
85
  | Heatmap | `03-ui-specs/13-heatmap.md`, `templates/heatmapCoords.ts` | Region overlays on respondent UI |
86
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`, `templates/customFieldValues.ts` | Skip wiring hook + Question prop |
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 |
88
90
  | Wizard chrome | `wizard-preview-build-guide.md`, `03-ui-specs/12-survey-chrome.md` | External logo URLs |
89
91
  | Wizard per-type colors | `wizard-question-type-styling.md` | Hardcoded Telekom hex for wizard tokens |
90
92
  | Selection colors | `wizard-question-type-styling.md`, `templates/selectionStyles.ts` | Single color for ring + fill — use annulus pattern |
91
93
  | Matrix column labels | `wizard-question-type-styling.md`, `templates/labelStyles.ts` | Hint labels on CFM column headers |
92
94
  | Logo seed | `constraints.md` §4, `wizard-api.md`, `parse-client-header` behavior in wizard docs | Random `public/logo_*` scan |
93
- | Wizard session (wait) | `wizard-config-handoff.md`, `ui-customization-wizard.md` |
95
+ | Wizard session (wait) | `wizard-config-handoff.md`, `ui-customization-wizard.md`, `wizard-troubleshooting.md` |
94
96
  | Apply all wizard paths | `apply-ui-config.md` | Changing `Question.tsx` dispatch |
95
97
  | Deploy AWS | `aws-deploy.md`, `setup.md#nextjs-aws-static-export` | `assetPrefix: "/"` for static export |
96
98
 
@@ -106,7 +108,11 @@ Use this table when deciding what to read. **Do not substitute similar-sounding
106
108
  | Default branch: "Not implemented" | Copy `templates/Question.tsx` — all types explicit |
107
109
  | Import `@repo/sdk/src/...` | Package root only — `hookContract.forbiddenImports` |
108
110
  | Implement from `apps/client` | Copy `docs/templates/*` |
109
- | `npx cfm-sdk customize` before build | Build + verify first; AWS = `customize-ui` |
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` |
110
116
  | `survey-config.json` | `survey-ui-config.json` + schema in `templates/` |
111
117
  | NPS `option.accentColor` | Derive from value — `value-derivation.md` |
112
118
  | Matrix value = column label text | `matrixColumnStoredValue(col)` → column **`id`** |
@@ -115,6 +121,8 @@ Use this table when deciding what to read. **Do not substitute similar-sounding
115
121
  | Focus ring = cell fill (same element) | Ring = border + dot; cell selected = annulus between |
116
122
  | Wizard optional → skip `survey-theme.css` | Wizard-ready build is **mandatory** Phase 5 |
117
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 |
118
126
  | `getVisible*` without 4th arg when CRM logic exists | Pass `customFieldValues` — `hookContract.visibilityHelpers` |
119
127
  | New question types or SDK actions | Only documented `onAction` types in `useSurveySDK.md` |
120
128
  | Placeholder unstable inline object | Stable ref + `useMemo` on hook options |
@@ -8,11 +8,13 @@
8
8
 
9
9
  | Wizard mode | Apply source | When |
10
10
  |-------------|--------------|------|
11
- | AWS review (default) | `survey-ui-config.final.json` | After CLI prints `Configuration ready` |
12
- | AWS `--apply` | `survey-ui-config.json` | Immediately after CLI exits |
13
- | Local `customize` | `survey-ui-config.json` | After `UI configuration saved` |
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
14
 
15
- **AWS review mode:** `survey-ui-config.json` remains **seed** until `npx cfm-sdk confirm-ui-config` — always apply codebase from **`.final.json`**.
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.
16
18
 
17
19
  ---
18
20
 
@@ -74,8 +76,8 @@ Import in `globals.css`: `@import './styles/survey-theme.css';`
74
76
  | `global.buttons.next` | SurveyPage | `data-cfm-btn-next` text |
75
77
  | `global.buttons.back` | SurveyPage | `data-cfm-btn-back` text |
76
78
  | `global.buttons.submit` | SurveyPage submit label | button text |
77
- | `global.logo.fileName` | Header | `data-cfm-logo` src=`/${fileName}` (or `./${fileName}` for static AWS export); remove `data-cfm-logo-text` when image |
78
- | `global.logo.url` | Agent reference only | Public CloudFront URL after wizard download to `public/`; do **not** use as `img src` in the survey |
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 |
79
81
  | `global.footer.copyrightText` | Footer | `data-cfm-copyright` |
80
82
  | `global.footer.links[]` | Footer | `data-cfm-footer-links` (render links) |
81
83
  | `questionTypes.MCQ.optionStyle` | `:root` or survey wrapper | `data-cfm-mcq-style` |
@@ -112,10 +114,33 @@ Import in `globals.css`: `@import './styles/survey-theme.css';`
112
114
 
113
115
  For each type in `surveyTypes[]`, apply `questionTypes.{TYPE}` per § Question types below.
114
116
 
115
- ### 8. Logo file
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
+ ```
116
142
 
117
- - Local / `confirm-ui-config`: file in `public/{fileName}`
118
- - If missing after confirm: re-run with `CFM_INSTANCE_ID` + `CFM_DEPLOY_API_BASE`
143
+ Full deploy pipeline: [`aws-deploy.md`](aws-deploy.md) § Logos & local assets.
119
144
 
120
145
  ### 9. Promote active config (AWS review only)
121
146
 
@@ -352,7 +377,7 @@ Ensure components use `selectionStyles.ts` — config only changes CSS vars, not
352
377
 
353
378
  ## Re-run policy
354
379
 
355
- Do not re-run `customize-ui` unless the client explicitly requests another customization session. Each run overwrites review artifacts.
380
+ Do not re-run the wizard unless the client explicitly requests another session. Each run overwrites config artifacts.
356
381
 
357
382
  ---
358
383
 
@@ -110,13 +110,104 @@ Set `OUT_DIR` to `dist/`. Ensure asset paths in built HTML are **relative** (no
110
110
 
111
111
  | Rule | Detail |
112
112
  |------|--------|
113
- | Public logos | Use relative paths (`logo.svg`), not `/logo.svg` |
113
+ | Public logos | Use **relative** paths (`./logo.svg` for AWS static export), not `/logo.svg` or `https://…` |
114
+ | Wizard logos | Must exist in `public/` **and** `out/` before deploy — see § Logos & local assets below |
114
115
  | Rank-order images | Prefer `option.imageUrl` over `option.previewImageUrl` — preview `*_p.*` URLs often return 403 |
115
116
  | Footer hash links | Use plain `<a href="#">`, not `next/link` — avoids RSC prefetch on static export |
116
117
  | No AWS keys in code | JWT only in `Authorization: Bearer` header at deploy time |
117
118
 
118
119
  ---
119
120
 
121
+ ## Logos & local assets (wizard → S3 → CloudFront)
122
+
123
+ ### Why logos break on CloudFront
124
+
125
+ The wizard **preview** shows logos from **browser memory** (`data:` URLs / base64). That works on `localhost:4200` only. CloudFront serves files from the **deploy bundle** at:
126
+
127
+ ```
128
+ https://<cloudfront>/sites/{surveyId}/{deployId}/<filename>
129
+ ```
130
+
131
+ It does **not** read wizard preview memory, and it does **not** automatically include logos stored under the separate wizard asset path (`sites/{surveyId}/assets/{fileName}`). Those S3 assets are for wizard handoff / re-download — the agent must copy the file into `public/` and ship it inside `out/` on every deploy.
132
+
133
+ ```mermaid
134
+ flowchart LR
135
+ subgraph wizard [Wizard session]
136
+ Upload[Client uploads logo]
137
+ Mem[Preview: base64 in memory]
138
+ Disk[public/logo_*.jpg local OR S3 assets/ EC2]
139
+ end
140
+ subgraph agent [Agent Phase 6c]
141
+ Apply[Header data-cfm-logo src=./fileName]
142
+ Build[yarn build copies public to out/]
143
+ end
144
+ subgraph deploy [Phase 7 AWS]
145
+ S3[sites/surveyId/deployId/logo_*.jpg]
146
+ CF[CloudFront serves same prefix as index.html]
147
+ end
148
+ Upload --> Mem
149
+ Upload --> Disk
150
+ Disk --> Apply
151
+ Apply --> Build
152
+ Build --> S3
153
+ S3 --> CF
154
+ ```
155
+
156
+ ### Two storage locations (do not confuse)
157
+
158
+ | Location | When written | Served on live survey? |
159
+ |----------|--------------|------------------------|
160
+ | `public/{fileName}` on dev machine | `customize` upload-logo API, or `confirm-ui-config` download | **Only after** `build` copies into `out/` and deploy uploads |
161
+ | `sites/{surveyId}/assets/{fileName}` on S3 | EC2 wizard **Review & Build** complete | **No** — not in deploy prefix; use only as download source for `confirm-ui-config` |
162
+
163
+ ### Correct agent flow (mandatory when wizard uploaded a logo)
164
+
165
+ **After Phase 6c apply, before Phase 7 deploy:**
166
+
167
+ 1. Read `global.logo.fileName` from `survey-ui-config.json` (local) or `.final.json` (EC2).
168
+ 2. Ensure the binary exists in `public/{fileName}`:
169
+ - **Local `customize`:** file written by `POST /api/upload-logo` when client uploaded in wizard.
170
+ - **EC2 `customize-ui`:** run `npx cfm-sdk confirm-ui-config` — downloads from `global.logo.url` (CloudFront assets URL) to `public/`.
171
+ 3. Update `Header.tsx`:
172
+
173
+ ```tsx
174
+ <img data-cfm-logo src="./logo_1783069846059_download2.jpg" alt="Brand" />
175
+ ```
176
+
177
+ Use `./{fileName}` for AWS static export (`assetPrefix: './'`). **Never** set `src` to:
178
+ - `global.logo.url` when it is a `data:` URL (preview memory)
179
+ - `https://…/sites/.../assets/...` (wrong path — outside deploy folder)
180
+ - `/logo.png` (absolute — breaks under nested CloudFront prefix)
181
+
182
+ 4. Rebuild and verify file is in static output:
183
+
184
+ ```bash
185
+ yarn build
186
+ LOGO=$(python3 -c "import json; print(json.load(open('survey-ui-config.json'))['global']['logo']['fileName'])")
187
+ test -f "public/$LOGO" && test -f "out/$LOGO" && echo "Logo ready for deploy"
188
+ ```
189
+
190
+ 5. Deploy — `deploy-to-aws.sh` uploads **every file under `out/`**, including the logo.
191
+
192
+ 6. Post-deploy verify (same deploy prefix as `index.html`):
193
+
194
+ ```bash
195
+ # If index.html is .../66593925-.../index.html, logo must be:
196
+ # .../66593925-.../logo_*.jpg → HTTP 200
197
+ ```
198
+
199
+ ### Pre-deploy checklist (logo)
200
+
201
+ - [ ] `global.logo.fileName` set in active config
202
+ - [ ] `public/{fileName}` exists on disk
203
+ - [ ] `Header.tsx` `data-cfm-logo` `src="./{fileName}"` (or `./your-seed-logo.svg` if no wizard upload)
204
+ - [ ] `out/{fileName}` exists after `yarn build`
205
+ - [ ] No `data:` or `https://` logo `src` in Header/Footer
206
+
207
+ See also: [`apply-ui-config.md`](apply-ui-config.md) § Logo file, [`wizard-config-handoff.md`](wizard-config-handoff.md) § Logo capture.
208
+
209
+ ---
210
+
120
211
  ## Deploy Procedure (agent executes in order)
121
212
 
122
213
  ### Step 0 — Build
@@ -253,7 +344,26 @@ bash templates/deploy-to-aws.sh
253
344
 
254
345
  ---
255
346
 
256
- ## Repeat Deploys
347
+ ## EC2 operator setup (one-time)
348
+
349
+ On `43.204.26.213`, `/home/ec2-user/deploy-api/.env` must use **real** CloudFront values (not `.env.example` placeholders):
350
+
351
+ ```bash
352
+ HOSTING_BUCKET=sprinklr-cfm-survey-sites-prod-unnat
353
+ CLOUDFRONT_DISTRIBUTION_ID=EY6QXOHVFMVZ2
354
+ CLOUDFRONT_BASE_URL=https://d81qbkjijbkjd.cloudfront.net
355
+ ```
356
+
357
+ Verify after `pm2 restart sprinklr-api`:
358
+
359
+ ```bash
360
+ curl -s http://43.204.26.213:3000/health/cloudfront | python3 -m json.tool
361
+ # expect "ok": true
362
+ ```
363
+
364
+ Placeholder IDs like `E1234567890ABC` cause `STORAGE_UNAVAILABLE` on `/deploy/complete` even when S3 uploads succeed.
365
+
366
+ ---
257
367
 
258
368
  Each deploy creates a **new** `deployId` folder under `sites/{surveyId}/`. Old deploys remain in S3.
259
369
 
@@ -269,9 +379,13 @@ After UI changes: rebuild → re-run Steps 1–3 (same `CFM_INSTANCE_ID` if same
269
379
  | 403 on `index.html.txt?_rsc` | Missing RSC payload file | Add `cp out/index.txt out/index.html.txt` to build script |
270
380
  | 403 on `*_p.png` / `*_p.jpg` images | Preview URL used | Use `option.imageUrl \|\| option.previewImageUrl` in RankOrderScale |
271
381
  | 401 `TOKEN_EXPIRED` | JWT expired | Ask client for new instanceId |
272
- | 503 `DEPLOY_UNAVAILABLE` | EC2 CloudFront/S3 env wrong | Report to operator |
382
+ | 503 `STORAGE_UNAVAILABLE` on `/deploy/complete` | EC2 `.env` has placeholder `CLOUDFRONT_*` values | Fix `.env` with real distribution ID + domain; `pm2 restart` |
383
+ | 503 `DEPLOY_UNAVAILABLE` | EC2 hosting env misconfigured — report to operator |
273
384
  | Some PUTs 403 | Presigned URLs expired (default 5 min) | Restart from Step 1; complete within window |
274
385
  | Blank page, HTML 200 | JS/CSS not uploaded or wrong paths | Re-check Channel 2 logs |
386
+ | Broken logo on live site, HTML 200 | Logo only in wizard preview memory or wrong `src` | Apply `global.logo.fileName` to `data-cfm-logo` as `./fileName`; verify `out/{fileName}` before deploy |
387
+ | Logo 404 under deploy URL | File not in `out/` or absolute `/logo.png` path | Rebuild after copying to `public/`; use `./fileName` not `/fileName` |
388
+ | Used `global.logo.url` as img src | Often `data:` base64 or `/assets/` path outside deploy | Use local `./fileName` only — see § Logos & local assets |
275
389
  | Survey API errors in browser | Deploy JWT ≠ SurveyPage JWT | Align `SURVEY_INSTANCE_ID` |
276
390
 
277
391
  ---
@@ -92,7 +92,8 @@ Store matrix values as column **`id`** — `matrixColumnStoredValue(col)` from S
92
92
  ## Step 3: Verify Before Build
93
93
 
94
94
  - [ ] Every type in survey inventory has matching component file(s)
95
- - [ ] **`src/lib/customFieldValues.ts`** when survey logic references `_c_…` ids
95
+ - [ ] **`src/lib/customFieldValues.ts`** when survey logic references `_c_…` ids — keys from **fetch**, wire hook + Question ([`placeholders-and-custom-fields-wiring.md`](00-integration/placeholders-and-custom-fields-wiring.md))
96
+ - [ ] **`SURVEY_PLACEHOLDERS`** keys discovered from fetched `{{TOKEN}}` text — not mockup
96
97
  - [ ] `CUSTOM_FIELD_VALUES` wired in `SurveyPage` hook options **and** `Question` prop
97
98
  - [ ] Matrix row + column/anchor labels visible (see canonical fixtures)
98
99
  - [ ] Slider has header + track (see canonical fixtures)
@@ -115,6 +116,7 @@ Read: [`agent-execution-flow.md`](agent-execution-flow.md), [`wizard-preview-bui
115
116
  - [ ] `previewBridge.ts` + `PreviewBridgeInit` in root layout
116
117
  - [ ] Header/Footer/ProgressBar/SurveyPage use `var(--cfm-*)` — no hardcoded brand hex for wizard-controlled tokens
117
118
  - [ ] `data-cfm-logo` / `data-cfm-logo-text`, `data-cfm-company`, `data-cfm-survey-title`, `data-cfm-btn-next`, `data-cfm-btn-back`, `data-cfm-thank-you` on chrome
118
- - [ ] Per-type scale vars per `wizard-question-type-styling.md` for types in survey inventory
119
+ - [ ] **Layout toggles:** `data-cfm-progress`, `[data-cfm-question-number]`, `[data-cfm-required]`, `.cfm-footer` see `wizard-troubleshooting.md` §3
120
+ - [ ] Per-type scale vars per `wizard-question-type-styling.md` for **all 11 types** (wizard exports all; survey inventory may be smaller)
119
121
  - [ ] Selection pattern: focus ring = outer border + inner dot; cell selected = annulus fill
120
122
  - [ ] `npx cfm-sdk export-previews` succeeds from project root (when previews needed for AWS wizard)
@@ -34,11 +34,12 @@ Choose **one** pattern in `Header.tsx` — see [`wizard-preview-build-guide.md`]
34
34
  | Mode | Rules |
35
35
  |------|--------|
36
36
  | **Text / CSS-only** | Build logo with HTML + CSS; use `<span data-cfm-logo-text>`. No `public/` logo file required. |
37
- | **Local image** | Put asset in `public/`; reference with `<img data-cfm-logo src="/your-logo.svg" />`. **Never** use external URLs (`https://…`) in the built survey. |
37
+ | **Local image** | Put asset in `public/`; reference with `<img data-cfm-logo src="/your-logo.svg" />` for local dev. For **AWS static export**, use `src="./your-logo.svg"` (relative — required under `/sites/{surveyId}/{deployId}/`). **Never** use external URLs (`https://…`) or wizard `data:` URLs in the built survey. |
38
38
 
39
39
  - Do **not** drop unrelated `public/logo_*` files during agent build — CLI seeds from `Header.tsx`, not newest `logo_*`.
40
40
  - After wizard upload, `survey-ui-config.json` `global.logo.fileName` is authoritative on re-open.
41
- - After wizard complete, poll/final JSON includes `global.logo.url` (public CloudFront URL) for agent handoff; the agent still copies the file to `public/` and uses a local `src` in `Header.tsx`.
41
+ - Wizard preview shows logo from **browser memory**; CloudFront serves only files in the **deploy bundle** (`out/` S3 `sites/{surveyId}/{deployId}/`). See [`aws-deploy.md`](aws-deploy.md) § Logos & local assets.
42
+ - After EC2 wizard complete, poll/final JSON includes `global.logo.url` (CloudFront `/assets/` URL) — agent downloads to `public/` via `confirm-ui-config`; still use `./{fileName}` in `Header.tsx`, not the assets URL.
42
43
 
43
44
  ## 5. Client Components
44
45
 
@@ -18,7 +18,7 @@ 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).
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
22
 
23
23
  ---
24
24
 
@@ -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