@explorer02/cfm-survey-sdk 0.2.4 → 0.2.6

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 (43) hide show
  1. package/dist/cli/index.js +45 -44
  2. package/dist/cli/index.mjs +43 -42
  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 +46 -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 +8 -4
  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-chrome-contract.md +210 -0
  19. package/templates/docs/00-integration/wizard-config-handoff.md +57 -9
  20. package/templates/docs/00-integration/wizard-preview-build-guide.md +30 -11
  21. package/templates/docs/00-integration/wizard-question-type-styling.md +4 -2
  22. package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
  23. package/templates/docs/01-components/10-header-footer.md +3 -3
  24. package/templates/docs/01-components/19-survey-sticky-chrome.md +16 -55
  25. package/templates/docs/MANIFEST.json +34 -13
  26. package/templates/docs/index.md +9 -11
  27. package/templates/docs/templates/Footer.tsx +72 -0
  28. package/templates/docs/templates/Header.tsx +84 -0
  29. package/templates/docs/templates/LanguageSelector.tsx +40 -0
  30. package/templates/docs/templates/PreviewBridgeInit.tsx +13 -0
  31. package/templates/docs/templates/ProgressBar.tsx +33 -0
  32. package/templates/docs/templates/Question.tsx +50 -7
  33. package/templates/docs/templates/SurveyStickyChrome.tsx +19 -5
  34. package/templates/docs/templates/deploy-to-aws.sh +74 -0
  35. package/templates/docs/templates/implementation_plan.md +19 -12
  36. package/templates/docs/templates/verify-agent-build.sh +25 -1
  37. package/templates/preview-harness/preview-bridge.inline.js +1 -1
  38. package/templates/previewBridge.ts +131 -38
  39. package/templates/wizard-dist/assets/{PreviewMock-DgHfrVeb.js → PreviewMock-7peNZK-z.js} +1 -1
  40. package/templates/wizard-dist/assets/{TypePanel-CFVC3Ptn.js → TypePanel-BxHnE3cm.js} +1 -1
  41. package/templates/wizard-dist/assets/index-DtZhNwPS.js +34 -0
  42. package/templates/wizard-dist/index.html +1 -1
  43. package/templates/wizard-dist/assets/index-DYK3X1e5.js +0 -34
@@ -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
 
@@ -1,144 +1,123 @@
1
1
  # UI Customization Wizard
2
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
- > **Wait + apply protocol:** [`wizard-config-handoff.md`](wizard-config-handoff.md).
3
+ > Optional **run** after Phase 6 verify. **Wizard-ready build** is mandatory in Phase 5 — see [`agent-execution-flow.md`](agent-execution-flow.md).
5
4
 
6
- **Before the client opts in:** agents must already have wired [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) artifacts so AWS wizard previews update live (`--cfm-*` CSS vars + `data-cfm-*` content hooks).
5
+ ## Default: local wizard (`customize`)
7
6
 
8
- ## When to Use
9
-
10
- After **Phase 6** (verify + `npm run dev`), ask the client:
11
-
12
- > *"Your survey is running locally. Would you like to customize the UI through the web wizard?"*
13
-
14
- - **Yes** → Phase 6b: run `npx cfm-sdk customize-ui` (AWS) or `customize` (local)
15
- - **No** → proceed to Phase 7 deploy
16
-
17
- ## AWS flow (production) — agent waits for client
7
+ When the client says **yes** to customization in agent chat, **always run:**
18
8
 
19
9
  ```bash
20
- export CFM_INSTANCE_ID="..." CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
21
- npx cfm-sdk customize-ui
10
+ npx cfm-sdk customize
22
11
  ```
23
12
 
24
- **Default = review mode.** The CLI:
13
+ This is the **recommended default** because it:
25
14
 
26
- 1. Resolves seed config from project (`survey-ui-config.json` `survey-theme.css` `Header.tsx` → defaults)
27
- 2. Exports component preview pages (`export-previews`) one HTML per preview key (`header`, `footer`, `MCQ_single`, …)
28
- 3. Uploads preview HTML to S3 via EC2 API (`POST /wizard/session/start` → presigned PUTs → `upload/complete`)
29
- 4. Prints the **deployed wizard link** and opens it for the agent **agent must copy this link to the client**
30
- 5. **Polls until client submits** (`GET /wizard/config/:surveyId` `status: ready`)
31
- 6. Writes review artifacts — **does not auto-apply to codebase**
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 local `out/previews/` when client quits without saving (`POST /api/wizard-quit`) or when CLI exits (Ctrl+C)
19
+ - Updates live previews via the same iframe + preview bridge as production
32
20
 
33
- ### Client wizard link (after S3 upload)
21
+ **Agent script after client says yes:**
34
22
 
35
- Once previews are on S3, the CLI prints:
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:
36
26
 
37
27
  ```
38
- Previews uploaded
39
- 🔗 Client wizard link — share with the client:
40
- http://43.204.26.213:3000/wizard-app/index.html?session=<uuid>&secret=<hex>
28
+ UI configuration saved to survey-ui-config.json
41
29
  ```
42
30
 
43
- | Who | Uses |
44
- |-----|------|
45
- | **Client** | Opens the **deployed EC2 wizard link** only — customizes branding, colors, question-type tokens; previews update live from S3-backed component pages |
46
- | **Agent** | Keeps `customize-ui` running (polls API); does **not** ask client to use localhost |
31
+ Then apply per [`apply-ui-config.md`](apply-ui-config.md).
47
32
 
48
- **URL shape:** `{CFM_DEPLOY_API_BASE}/wizard-app/index.html?session={sessionId}&secret={sessionSecret}`
33
+ ### Who can use it
49
34
 
50
- Default production API: `http://43.204.26.213:3000` (see `MANIFEST.json` `apiBaseDefault`).
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 |
51
39
 
52
- **Agent script (after CLI prints the link):**
40
+ `localhost:4200` is only reachable on the machine running the CLI.
53
41
 
54
- > *"I've uploaded your survey component previews. Open this link to customize the UI: [paste wizard URL]. When you're done, click **Review & Build** on the last step. I'll wait here until your changes are saved."*
42
+ ---
55
43
 
56
- **On success, CLI prints:**
57
- ```
58
- Configuration ready
59
- Final: survey-ui-config.final.json
60
- Diff: survey-ui-config.diff.md
61
- Apply when ready: npx cfm-sdk confirm-ui-config
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
62
51
  ```
63
52
 
64
- **Agent must:**
65
- - [ ] Keep terminal open until CLI exits 0
66
- - [ ] **Copy the deployed wizard link from CLI output and send it to the client** (after previews upload to S3)
67
- - [ ] Tell client: *"Please complete the wizard and click Review & Build."*
68
- - [ ] Read `survey-ui-config.diff.md` before Phase 6c
69
- - [ ] Apply codebase per [`apply-ui-config.md`](apply-ui-config.md) from **`.final.json`**
70
- - [ ] Run `npx cfm-sdk confirm-ui-config` after codebase apply
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`
71
57
 
72
- See [`wizard-config-handoff.md`](wizard-config-handoff.md) for full handoff checklist.
58
+ See [`wizard-api.md`](wizard-api.md) and [`wizard-config-handoff.md`](wizard-config-handoff.md).
73
59
 
74
- ### Legacy immediate write
60
+ **Do not** use `customize-ui` when client and agent share the same machine — `customize` is simpler and more reliable.
75
61
 
76
- ```bash
77
- npx cfm-sdk customize-ui --apply
78
- ```
62
+ ---
79
63
 
80
- Writes `survey-ui-config.json` + logo immediately (no diff review). Phase 6c apply still required.
64
+ ## When to ask (INPUT 3)
81
65
 
82
- ### Detached session
66
+ After Phase 6 verify + dev server:
83
67
 
84
- ```bash
85
- npx cfm-sdk customize-ui --no-wait
86
- # Later, when client done:
87
- export CFM_WIZARD_SESSION_ID="..."
88
- npx cfm-sdk fetch-ui-config
89
- ```
68
+ > *"Your survey is running locally. Would you like to customize the UI through the web wizard?"*
90
69
 
91
- ## Local flow (development)
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
92
73
 
93
- ```bash
94
- npx cfm-sdk customize
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
95
91
  ```
96
92
 
97
- Opens browser at `http://localhost:4200`. **Blocks** until client saves → writes `survey-ui-config.json` directly. Then Phase 6c apply from that file (no `confirm-ui-config`).
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
+ ---
98
101
 
99
102
  ## Seed config
100
103
 
101
104
  | Priority | Source |
102
105
  |----------|--------|
103
106
  | 1 | `./survey-ui-config.json` (draft) |
104
- | 2 | `src/styles/survey-theme.css` (`--cfm-*` vars) |
105
- | 3 | `implementation_plan.md` branding hints |
106
- | 4 | `Header.tsx` — `data-cfm-logo` / `data-cfm-logo-text` |
107
+ | 2 | `src/styles/survey-theme.css` |
108
+ | 3 | `implementation_plan.md` |
109
+ | 4 | `Header.tsx` logo contract |
107
110
  | 5 | SDK defaults |
108
111
 
109
- Debug: `npx cfm-sdk resolve-ui-config --write`
110
-
111
- ## Wizard Steps
112
-
113
- | Step | Controls |
114
- |------|----------|
115
- | Identity | Survey title, company name, tab title, thank-you message |
116
- | Logo | Upload S3 (AWS) or `public/` (local) |
117
- | Header / Footer | Logo box, company, links, copyright, colors |
118
- | Theme & Colors | Presets, palette, question card (cell selected + focus ring) |
119
- | Layout & Chrome | Header/footer toggles, nav, width, font |
120
- | Question Types | Per-type tokens + format preview tabs |
121
- | Testing & Tokens | Placeholders, custom fields, debug |
122
- | Deploy | AWS or Vercel target |
123
- | Review & Build | **Client submits** — triggers CLI poll success |
124
-
125
- ## Output artifacts
126
-
127
- | File | When |
128
- |------|------|
129
- | `survey-ui-config.final.json` | AWS — client's submitted config (apply source) |
130
- | `survey-ui-config.diff.md` | AWS — every changed path (audit before apply) |
131
- | `survey-ui-config.json` | Active config (seed until `confirm-ui-config`; or final for local/`--apply`) |
132
-
133
- Apply tokens per [`apply-ui-config.md`](apply-ui-config.md).
134
-
135
- ## Agent Checklist
136
-
137
- - [ ] Phase 5: components wired per [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md)
138
- - [ ] Client opted in after localhost preview (INPUT 3)
139
- - [ ] Ran `customize-ui` or `customize` and **waited** for CLI exit 0
140
- - [ ] Read `survey-ui-config.diff.md` (AWS review mode)
141
- - [ ] Phase 6c: applied **all** diff paths per [`apply-ui-config.md`](apply-ui-config.md)
142
- - [ ] AWS: ran `confirm-ui-config` after codebase apply
143
- - [ ] Re-ran verify script + build
144
- - [ ] Did not modify SDK integration (`onAction`, dispatch logic)
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.
@@ -1,134 +1,126 @@
1
- # Wizard API (`/wizard/*`)
1
+ # Wizard API — EC2 fallback (`customize-ui` only)
2
2
 
3
- > EC2 middle API routes for AWS-hosted UI customization. Consumed by `npx cfm-sdk customize-ui` and the survey-wizard SPA.
3
+ > **Default wizard is `npx cfm-sdk customize` on localhost** no EC2 API needed.
4
+ > This doc applies **only** when the client customizes from another device.
4
5
 
5
- Base URL: `CFM_DEPLOY_API_BASE` — production default: `http://43.204.26.213:3000`
6
+ Base URL: `CFM_DEPLOY_API_BASE` — default: `http://43.204.26.213:3000`
6
7
 
7
- ## Client wizard link (deployed)
8
+ ## Architecture
8
9
 
9
- After `customize-ui` uploads component previews to S3, the CLI prints a **deployed wizard URL** for the client:
10
-
11
- ```
12
- {CFM_DEPLOY_API_BASE}/wizard-app/index.html?session={sessionId}&secret={sessionSecret}
10
+ ```mermaid
11
+ flowchart LR
12
+ CLI[customize-ui CLI] -->|PUT preview files| Disk[EC2 disk data/wizard-sessions/]
13
+ Client[Client browser] --> SPA[wizard-app SPA]
14
+ SPA -->|GET /api/inventory| API[deploy-api]
15
+ SPA -->|iframe /previews/...| Disk
16
+ SPA -->|POST /api/save-config| API
17
+ API -->|final config + logo| S3[S3 hosting bucket]
18
+ CLI -->|poll GET /wizard/config| API
13
19
  ```
14
20
 
15
- Example:
21
+ | During session | Storage |
22
+ |----------------|---------|
23
+ | Preview HTML | EC2 disk (`WIZARD_DATA_DIR/{sessionId}/previews/`) |
24
+ | Seed config | EC2 disk (`seed-config.json`) |
25
+ | Temp logo | EC2 disk (`assets/`) |
26
+ | **On submit** | Final JSON + permanent logo → S3 |
27
+
28
+ Previews are **not** loaded from S3 during customization — avoids "Storage service unavailable" on preview iframes.
29
+
30
+ ## Client wizard link
16
31
 
17
32
  ```
18
- http://43.204.26.213:3000/wizard-app/index.html?session=abc-123&secret=fe7698d0...
33
+ {CFM_DEPLOY_API_BASE}/wizard-app/index.html?session={sessionId}&secret={sessionSecret}
19
34
  ```
20
35
 
21
- | Piece | Role |
36
+ | Route | Role |
22
37
  |-------|------|
23
- | `/wizard-app/` | Wizard SPA on EC2 (customization forms + preview panel) |
24
- | `session` + `secret` | Tie the client to the S3 preview session |
25
- | S3 `previews/` | Component-wise HTML (`header`, `footer`, `MCQ_single`, …) — loaded via EC2 proxy |
26
-
27
- **Agent:** copy link from CLI → send to client. **Client:** opens link only (no localhost). **Agent:** keeps CLI polling until submit.
28
-
29
- `wizardUrl` in `POST /wizard/session/start` response is this full URL (built by `getWizardPublicUrl` in deploy-api).
30
-
31
- ## Auth
32
-
33
- | Caller | Header |
34
- |--------|--------|
35
- | CLI | `Authorization: Bearer {CFM_INSTANCE_ID}` |
36
- | Wizard SPA | `X-Wizard-Session: {secret}` + `X-Wizard-Session-Id: {sessionId}` |
37
-
38
- ## Endpoints
38
+ | `/wizard-app/` | Wizard SPA |
39
+ | `/api/inventory` | Session metadata + `previewManifest` (local-server API) |
40
+ | `/previews/{sessionId}/{key}/index.html` | Component preview iframes |
41
+ | `/api/save-config` | Client submit (same as local `customize`) |
39
42
 
40
- ### `POST /wizard/session/start`
41
-
42
- Starts session; returns presigned PUT URLs for preview HTML files.
43
-
44
- **Body:** `{ "files": [...], "surveyTypes": ["MCQ", "NPS_SCALE"], "initialConfig": { ... } }`
43
+ ## Local-server routes (`/api/*`, `/previews/*`)
45
44
 
46
- `initialConfig` is optional. When present, the CLI sends the agent's resolved UI config (from draft `survey-ui-config.json`, parsed `survey-theme.css`, `Header.tsx` logo contract, or defaults). The API normalizes, validates, stores on the session, and persists to `sites/{surveyId}/wizard-sessions/{sessionId}/seed-config.json` for restart durability.
45
+ Same contract as `packages/sdk/src/cli/customize.ts`:
47
46
 
48
- **Response:** `{ sessionId, sessionSecret, wizardUrl, uploads[] }`
47
+ ### `GET /api/inventory?session=&secret=`
49
48
 
50
- ### `POST /wizard/previews/upload/complete`
49
+ Returns `{ surveyTypes, instanceId, previewUrl, previewManifest, initialConfig, localServer: true }`.
51
50
 
52
- **Body:** `{ "sessionId": "uuid" }`
51
+ ### `GET /api/preview-url`
53
52
 
54
- Activates session; builds same-origin `previewManifest` (API proxy URLs — session previews are private in S3).
53
+ Health check for preview availability indicator.
55
54
 
56
- ### `GET /wizard/preview/:sessionId/:component/index.html?secret=...`
55
+ ### `POST /api/upload-logo?session=&secret=`
57
56
 
58
- Serves preview HTML from S3 for wizard iframes. Auth via `secret` query param (iframes cannot send session headers).
57
+ Body: `{ filename, base64 }` stores logo on EC2 disk for session.
59
58
 
60
- ### `GET /wizard/session/:sessionId`
59
+ ### `POST /api/save-config?session=&secret=`
61
60
 
62
- Wizard boot returns `surveyTypes`, `previewManifest`, `sessionExpiresAt`, and `initialConfig` when the session was seeded.
61
+ Body: full `survey-ui-config.json`. Persists final config + logo to S3, cleans session disk.
63
62
 
64
- **Response:** `{ surveyTypes, instanceId, previewManifest, sessionExpiresAt, initialConfig? }`
63
+ ## Session management (`/wizard/*`)
65
64
 
66
- The wizard SPA calls `loadConfig(initialConfig)` on boot so the client edits on top of the agent build.
65
+ ### `POST /wizard/session/start`
67
66
 
68
- ### `POST /wizard/logo`
67
+ **Auth:** `Authorization: Bearer {JWT}`
69
68
 
70
- **Body:** `{ "filename": "logo.png", "base64": "data:image/png;base64,..." }`
69
+ **Body:** `{ files, surveyTypes, initialConfig }`
71
70
 
72
- Max 512KB. Stores in session S3 prefix.
71
+ **Response:** `{ sessionId, sessionSecret, wizardUrl, uploads[], localServer: true }`
73
72
 
74
- ### `POST /wizard/complete`
73
+ `uploads[].uploadUrl` `PUT /wizard/session/:sessionId/preview-file?path=previews/...` (EC2 disk, not S3 presign).
75
74
 
76
- **Body:** full `survey-ui-config.json` object.
75
+ ### `PUT /wizard/session/:sessionId/preview-file?path=...`
77
76
 
78
- On success:
77
+ **Auth:** `X-Wizard-Session` + `X-Wizard-Session-Id`
79
78
 
80
- 1. Copies uploaded logo to **permanent** S3 key: `sites/{surveyId}/assets/{fileName}`
81
- 2. Saves final config to `sites/{surveyId}/wizard/config.json` (with `logoKey` + `logoUrl` metadata)
82
- 3. **Deletes** entire wizard session folder `sites/{surveyId}/wizard-sessions/{sessionId}/` (previews, seed-config, temp logo)
83
- 4. Returns public logo URL: `{ logoUrl, logoKey, logoFileName }`
79
+ Raw file body written to session disk.
84
80
 
85
- Public logo URL format: `{CLOUDFRONT_BASE_URL}/sites/{surveyId}/assets/{fileName}` — readable by anyone with the link (via CloudFront, bucket stays private).
81
+ ### `POST /wizard/previews/upload/complete`
86
82
 
87
- ### `GET /wizard/config/:surveyId`
83
+ **Auth:** JWT. Verifies all files on disk; activates session; builds manifest with `/previews/{sessionId}/…` URLs.
88
84
 
89
- CLI poll. Query `?sessionId=` to scope to current session.
85
+ ### `POST /wizard/session/quit`
90
86
 
91
- **Pending:** `{ "status": "pending" }`
92
- **Ready:** `{ "status": "ready", "config": { ... }, "logoUrl": "...", "logoKey": "...", "sessionId": "..." }`
87
+ Deletes session disk folder + in-memory session. CLI poll returns `status: abandoned`.
93
88
 
94
- `config.global.logo.url` is populated with the public CloudFront URL when a logo was uploaded.
89
+ ### `GET /wizard/config/:surveyId?sessionId=`
95
90
 
96
- ### `GET /wizard/logo/:surveyId/:fileName`
91
+ CLI poll after client submit.
97
92
 
98
- Returns `{ "downloadUrl": "presigned-get" }` for CLI to save logo to agent `public/` (fallback when CloudFront is not reachable from agent network).
93
+ - **pending** waiting
94
+ - **abandoned** — client quit
95
+ - **ready** — `{ config, logoUrl, … }`
99
96
 
100
97
  ## Env (deploy-api)
101
98
 
102
99
  ```bash
103
- WIZARD_DEV_URL=http://localhost:5173 # dev only
104
- WIZARD_PATH=/sites/_wizard # prod CloudFront path
105
- WIZARD_SESSION_TTL_MS=7200000 # 2h expired sessions trigger S3 GC
100
+ WIZARD_DATA_DIR=./data/wizard-sessions # preview + seed + temp logo on disk
101
+ WIZARD_SESSION_TTL_MS=7200000
102
+ HOSTING_BUCKET=... # final config + permanent logo only
103
+ CLOUDFRONT_BASE_URL=...
106
104
  ```
107
105
 
108
- ## AWS console (one-time logo public URL)
106
+ ## IAM (EC2 instance role)
109
107
 
110
- Logos are **not** public on S3 directly. They are served through **CloudFront** (same distribution as survey deploys).
108
+ Required for **submit** (not previews):
111
109
 
112
- Verify (usually already done if deploy works):
110
+ - `s3:PutObject`, `s3:GetObject` on hosting bucket
111
+ - `cloudfront:CreateInvalidation` (logo cache bust)
113
112
 
114
- 1. **CloudFront** → your distribution → Origins → hosting bucket is the origin
115
- 2. **Origin access** → OAC/OAI allows CloudFront to read the bucket (bucket policy blocks public access)
116
- 3. **Behavior** → default or `sites/*` path serves objects from the bucket
117
-
118
- No extra bucket policy for public read is required. The public URL is:
119
-
120
- `https://{CLOUDFRONT_DOMAIN}/sites/{surveyId}/assets/{logoFileName}`
121
-
122
- **IAM (EC2 instance role)** must allow: `s3:PutObject`, `s3:GetObject`, `s3:DeleteObject`, `s3:ListBucket` on the hosting bucket, plus `cloudfront:CreateInvalidation` on the distribution.
123
-
124
- ## CLI flow (review mode — default)
113
+ ## CLI flow
125
114
 
126
115
  ```bash
127
116
  export CFM_INSTANCE_ID="..." CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
128
117
  npx cfm-sdk customize-ui
129
- # export-previews → upload component previews to S3 → print client wizard link →
130
- # POLL until client submits → survey-ui-config.final.json + .diff.md
131
- # Agent applies codebase → npx cfm-sdk confirm-ui-config
132
118
  ```
133
119
 
134
- See [`wizard-config-handoff.md`](wizard-config-handoff.md).
120
+ 1. `export-previews` on agent machine
121
+ 2. Upload preview files to EC2 disk
122
+ 3. Print client wizard link
123
+ 4. Poll until `status: ready`
124
+ 5. Write `.final.json` + `.diff.md`
125
+
126
+ See [`wizard-config-handoff.md`](wizard-config-handoff.md), [`ui-customization-wizard.md`](ui-customization-wizard.md).