@explorer02/cfm-survey-sdk 0.1.9 → 0.2.1

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 (41) hide show
  1. package/package.json +1 -1
  2. package/postinstall.js +5 -0
  3. package/templates/AGENT.md +4 -2
  4. package/templates/docs/00-integration/component-checklist.md +61 -0
  5. package/templates/docs/00-integration/constraints.md +17 -0
  6. package/templates/docs/01-components/01-survey-page.md +2 -0
  7. package/templates/docs/01-components/02-question.md +43 -56
  8. package/templates/docs/01-components/03-rating-scale.md +2 -0
  9. package/templates/docs/01-components/04-csat-scale.md +3 -1
  10. package/templates/docs/01-components/05-csat-matrix-scale.md +2 -0
  11. package/templates/docs/01-components/06-likert-matrix-scale.md +2 -0
  12. package/templates/docs/01-components/07-slider-matrix-scale.md +2 -0
  13. package/templates/docs/01-components/08-file-upload-scale.md +2 -0
  14. package/templates/docs/01-components/09-custom-slider-track.md +2 -0
  15. package/templates/docs/01-components/10-header-footer.md +3 -1
  16. package/templates/docs/01-components/11-progress-bar.md +2 -0
  17. package/templates/docs/01-components/12-language-selector.md +2 -0
  18. package/templates/docs/01-components/13-matrix-dropdown.md +2 -0
  19. package/templates/docs/01-components/README.md +4 -2
  20. package/templates/docs/02-reference/config-field-index.md +158 -0
  21. package/templates/docs/02-reference/routing-table.md +16 -16
  22. package/templates/docs/03-ui-specs/00-question-shell.md +102 -0
  23. package/templates/docs/03-ui-specs/01-rating.md +80 -0
  24. package/templates/docs/03-ui-specs/02-radio.md +57 -0
  25. package/templates/docs/03-ui-specs/03-text.md +51 -0
  26. package/templates/docs/03-ui-specs/04-csat.md +57 -0
  27. package/templates/docs/03-ui-specs/05-rating-scale.md +49 -0
  28. package/templates/docs/03-ui-specs/06-slider.md +42 -0
  29. package/templates/docs/03-ui-specs/07-matrix-cfm.md +66 -0
  30. package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +65 -0
  31. package/templates/docs/03-ui-specs/09-slider-matrix.md +61 -0
  32. package/templates/docs/03-ui-specs/10-file-upload.md +54 -0
  33. package/templates/docs/03-ui-specs/11-text-and-media.md +49 -0
  34. package/templates/docs/03-ui-specs/12-survey-chrome.md +60 -0
  35. package/templates/docs/03-ui-specs/README.md +80 -0
  36. package/templates/docs/03-ui-specs/shared/custom-slider-track.md +52 -0
  37. package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +38 -0
  38. package/templates/docs/MANIFEST.json +27 -1
  39. package/templates/docs/index.md +28 -13
  40. package/templates/docs/templates/Question.tsx +243 -0
  41. package/templates/docs/templates/implementation_plan.md +40 -0
@@ -0,0 +1,54 @@
1
+ # UI Spec: File Upload (`type: 'file_upload'`)
2
+
3
+ > **Implement from this spec** (npm installs). Monorepo reference: `apps/client/src/components/FileUploadScale.tsx`
4
+ > **SDK type:** `FileUploadQuestion` — `fetchSurvey/types/fileUpload.ts`
5
+ > **Component blueprint:** `01-components/08-file-upload-scale.md`
6
+
7
+ ## Config Inventory
8
+
9
+ | Field | Implemented | UI impact |
10
+ |-------|-------------|-----------|
11
+ | `uploadMessage` | ✅ | HTML in dropzone (bold 16px) |
12
+ | `supportedFileFormats` | ✅ | Validation + accept attribute |
13
+ | `maxFileCount` | ✅ | Total file limit |
14
+ | `fileSizeLimit` | ✅ | MB limit |
15
+ | `fileSizeLimitType` | ✅ | `PER_FILE` or `IN_TOTAL` |
16
+
17
+ ## Layout Anatomy
18
+
19
+ ```
20
+ [uploadMessage HTML in dashed dropzone]
21
+ File limit: N; File size limit: XMB/file|in total; Supports: ...
22
+ [local error banner — red if validation fails]
23
+ [file list cards: icon, name, size, remove ×]
24
+ ```
25
+
26
+ ## Interactive States
27
+
28
+ | State | Border | Background |
29
+ |-------|--------|------------|
30
+ | Default | `#d1d5db` dashed | `#f9fafb` |
31
+ | Hover | `#e20074` | `#fdf2f8` |
32
+ | Drag active | `#e20074` | `#fdf2f8` |
33
+
34
+ ## Local Validation (before SDK)
35
+
36
+ 1. Max file count exceeded
37
+ 2. Unsupported extension
38
+ 3. PER_FILE size exceeded
39
+ 4. IN_TOTAL cumulative size exceeded
40
+
41
+ Error banner: `#fee2e2` bg, `#b91c1c` text.
42
+
43
+ ## Answer Mutation
44
+
45
+ ```typescript
46
+ onSelect(File[] | undefined) // undefined when all removed
47
+ ```
48
+
49
+ ## Agent Checklist
50
+
51
+ - [ ] Hidden `<input type="file">` triggered by dropzone click
52
+ - [ ] Drag enter/over/leave/drop handlers
53
+ - [ ] Dynamic constraints line in dropzone
54
+ - [ ] File list with remove button (hover red)
@@ -0,0 +1,49 @@
1
+ # UI Spec: Text and Media (`type: 'text_and_media'`)
2
+
3
+ > **Reference:** `apps/client/src/components/Question.tsx` (inline)
4
+ > **SDK type:** `TextAndMediaQuestion` — `fetchSurvey/types/textAndMedia.ts`
5
+ > **Component blueprint:** `01-components/02-question.md`
6
+
7
+ ## Config Inventory
8
+
9
+ | Field | Implemented | UI impact |
10
+ |-------|-------------|-----------|
11
+ | `mediaUrl` | ✅ | Required to render media block |
12
+ | `mediaMimeType` | ✅ | `video/` or `VIDEO` → `<video>`; else `<img>` |
13
+ | `mediaTitle` | ✅ | Caption below media, centered gray text |
14
+ | `mediaAlignment` | ✅ | Flex justify: CENTER / RIGHT / default left |
15
+ | `mediaSize` | ✅ | Width `%` on media container; default 100% |
16
+
17
+ No answer input — display-only question.
18
+
19
+ ## Layout Anatomy
20
+
21
+ ```
22
+ [question title + description — standard shell]
23
+
24
+ ┌─ flex container (justify per mediaAlignment) ──────────────┐
25
+ │ ┌─ media block (width: mediaSize%) ──────────────────┐ │
26
+ │ │ <video controls> or <img> │ │
27
+ │ │ [optional mediaTitle caption] │ │
28
+ │ └─────────────────────────────────────────────────────┘ │
29
+ └────────────────────────────────────────────────────────────┘
30
+ ```
31
+
32
+ ## Alignment Mapping
33
+
34
+ | `mediaAlignment` | CSS |
35
+ |------------------|-----|
36
+ | `TOP_CENTER`, `BOTTOM_CENTER` | `justify-center` |
37
+ | `TOP_RIGHT`, `BOTTOM_RIGHT` | `justify-end` |
38
+ | default | `justify-start` |
39
+
40
+ ## Answer Mutation
41
+
42
+ None — no `onSelect` payload for this type.
43
+
44
+ ## Agent Checklist
45
+
46
+ - [ ] Render only when `mediaUrl` is present
47
+ - [ ] Video vs image from mime type
48
+ - [ ] `max-w-full rounded-md shadow-sm` on media element
49
+ - [ ] Optional centered caption for `mediaTitle`
@@ -0,0 +1,60 @@
1
+ # UI Spec: Survey Chrome
2
+
3
+ > **Reference:** `SurveyPage.tsx`, `Header.tsx`, `Footer.tsx`, `ProgressBar.tsx`, `LanguageSelector.tsx`
4
+ > **Component blueprints:** `01-components/01-survey-page.md`, `10-header-footer.md`, `11-progress-bar.md`, `12-language-selector.md`
5
+
6
+ ## SurveyPage — 5-State Machine
7
+
8
+ | State | Condition | UI |
9
+ |-------|-----------|-----|
10
+ | Loading | `surveyQueryResults.isLoading` | Centered "Loading..." |
11
+ | Error | `surveyQueryResults.error` | Red error message |
12
+ | Empty | `!survey` | "No survey data" |
13
+ | Submitted | `submitSurveyResults.data` | Thank you message |
14
+ | Active | else | Questions + nav |
15
+
16
+ ## Active Layout
17
+
18
+ ```
19
+ Header
20
+ main (max-w-4xl)
21
+ ProgressBar(progressPercentage)
22
+ LanguageSelector (hidden if ≤1 language)
23
+ Questions (space-y-12)
24
+ Submit error (if any)
25
+ Nav: Back (if page > 0) + Next/Submit
26
+ Footer
27
+ ```
28
+
29
+ ## Navigation Labels
30
+
31
+ German when `survey.language.startsWith('de')`:
32
+
33
+ | Action | EN | DE |
34
+ |--------|----|----|
35
+ | Back | Zurück | Back |
36
+ | Next | Weiter | Next |
37
+ | Submit | Absenden | Submit |
38
+ | Submitting | Wird gesendet... | Submitting... |
39
+
40
+ ## Button Tokens
41
+
42
+ - Back: `border-[#e20074] text-[#e20074] hover:bg-[#fdf2f8]`
43
+ - Primary: `bg-[#e20074] text-white hover:opacity-90`
44
+
45
+ ## ProgressBar
46
+
47
+ Pink fill bar, `300ms` width transition on `progressPercentage`.
48
+
49
+ ## LanguageSelector
50
+
51
+ - Hidden when `languages.length <= 1`
52
+ - Focus ring: `#2563eb`
53
+
54
+ ## Agent Checklist
55
+
56
+ - [ ] All 5 states implemented
57
+ - [ ] `onAction({ type: 'CHANGE' })` wired per question
58
+ - [ ] PREVIOUS / NEXT actions on nav buttons
59
+ - [ ] ProgressBar receives `state.progressPercentage`
60
+ - [ ] Header/Footer on every state branch
@@ -0,0 +1,80 @@
1
+ # UI Specifications — Reference Implementation Guide
2
+
3
+ > **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx). The monorepo path `apps/client/src/components/` is **not** available in client projects.
4
+ > **For monorepo devs:** cross-check against [`apps/client/src/components/`](../../../../../../apps/client/src/components/).
5
+ > Read the spec for **each question type present** in the fetched survey before writing React code.
6
+
7
+ ## How to Read a UI Spec
8
+
9
+ Each file in this folder follows the same structure:
10
+
11
+ 1. **Config inventory** — every SDK field, whether the reference client implements it
12
+ 2. **Layout anatomy** — structured ASCII diagram
13
+ 3. **Config decision tree** — matches `if/else` branches in reference code
14
+ 4. **Interactive states** — default, hover, selected, disabled, focus
15
+ 5. **Tooltips & labels** — positioning formulas
16
+ 6. **Color tokens** — exact hex values from reference client
17
+ 7. **Answer mutation** — `onSelect` / `onAction CHANGE` shape
18
+ 8. **Agent checklist**
19
+
20
+ ## Design Tokens (Reference Client)
21
+
22
+ | Token | Value | Usage |
23
+ |-------|-------|-------|
24
+ | Primary | `#e20074` | Borders, rings, dots, slider fill, selected text |
25
+ | Selected bg | `#fdf2f8` | Card options, CSAT buttons, matrix cells |
26
+ | NPS track highlight | `#fbe8f3` | Selected radio cell in NPS track row |
27
+ | NPS track bar | `#f2f2f2` | Gray bar behind NPS radios |
28
+ | Validation border | `#333333` | Error banner |
29
+ | Validation bg | `#d9d9d9` | Error banner |
30
+ | Row band | `#f3f4f6` | Slider matrix row background |
31
+ | Zebra row | `rgba(249,250,251,0.8)` | Matrix alternating rows |
32
+ | Tooltip bg | `#1f2937` | Hover tooltips on emoji/slider |
33
+ | Likert carousel dot (active) | `#2563eb` | LikertMatrix carousel only |
34
+ | CSAT carousel dot (active) | `#e20074` | CsatMatrix carousel |
35
+
36
+ ## Reference Component Index
37
+
38
+ | Spec file | Reference component | `question.type` |
39
+ |-----------|---------------------|-----------------|
40
+ | [00-question-shell.md](00-question-shell.md) | `Question.tsx` | All (wrapper) |
41
+ | [01-rating.md](01-rating.md) | `RatingScale.tsx` | `rating` |
42
+ | [02-radio.md](02-radio.md) | `Question.tsx` inline | `radio` |
43
+ | [03-text.md](03-text.md) | `Question.tsx` inline | `text` |
44
+ | [04-csat.md](04-csat.md) | `CsatScale.tsx` | `csat` |
45
+ | [05-rating-scale.md](05-rating-scale.md) | *(gap — reuse CsatScale patterns)* | `rating_scale` |
46
+ | [06-slider.md](06-slider.md) | *(gap — reuse CustomSliderTrack)* | `slider` |
47
+ | [07-matrix-cfm.md](07-matrix-cfm.md) | `LikertMatrixScale.tsx` | `matrix` + CFM |
48
+ | [08-matrix-csat-rating.md](08-matrix-csat-rating.md) | `CsatMatrixScale.tsx` | CSAT/RATING matrix |
49
+ | [09-slider-matrix.md](09-slider-matrix.md) | `SliderMatrixScale.tsx` | `slider_matrix` |
50
+ | [10-file-upload.md](10-file-upload.md) | `FileUploadScale.tsx` | `file_upload` |
51
+ | [11-text-and-media.md](11-text-and-media.md) | `Question.tsx` inline | `text_and_media` |
52
+ | [12-survey-chrome.md](12-survey-chrome.md) | `SurveyPage.tsx` + chrome | Shell |
53
+ | [shared/custom-slider-track.md](shared/custom-slider-track.md) | `CustomSliderTrack.tsx` | Primitive |
54
+ | [shared/matrix-dropdown.md](shared/matrix-dropdown.md) | `MatrixDropdown.tsx` | Primitive |
55
+
56
+ ## NPS Traffic-Light Colors
57
+
58
+ Use `option.color` from SDK — never invent colors:
59
+
60
+ | Value | Hex |
61
+ |-------|-----|
62
+ | 0 | `#e2001a` |
63
+ | 1 | `#e4251b` |
64
+ | 2 | `#ec610a` |
65
+ | 3 | `#f18b00` |
66
+ | 4 | `#f7b200` |
67
+ | 5 | `#fcd900` |
68
+ | 6 | `#fcd900` |
69
+ | 7 | `#9fca00` |
70
+ | 8 | `#6bb300` |
71
+ | 9 | `#339a00` |
72
+ | 10 | `#008000` |
73
+
74
+ ## When to Read
75
+
76
+ After Phase 3 in [`index.md`](../index.md), for each question in `state.currentQuestions`:
77
+
78
+ 1. Read [`02-reference/question-types/`](../02-reference/question-types/) for data shape
79
+ 2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `uiSpecs`)
80
+ 3. Cross-check [`config-field-index.md`](../02-reference/config-field-index.md)
@@ -0,0 +1,52 @@
1
+ # UI Spec: Custom Slider Track (shared primitive)
2
+
3
+ > **Implement from this spec** (npm installs). Monorepo reference: `apps/client/src/components/CustomSliderTrack.tsx`
4
+ > **Used by:** `SliderMatrixScale.tsx`, `CsatMatrixScale` (graphics), standalone `slider` (gap)
5
+
6
+ ## Layer Architecture
7
+
8
+ ```
9
+ 1. Gray inactive track (#e5e7eb, 4px height)
10
+ 2. Magenta fill bar (width = percentage%, #e20074 or #9ca3af if disabled)
11
+ 3. Tick marks (1px × 8px at ticks positions)
12
+ 4. Invisible <input type="range"> overlay (opacity 0, full hit area)
13
+ 5. Visual thumb: circle OR emoji (sliderType === 'graphics')
14
+ 6. Tooltip bubble on hover/drag (#1f2937 bg, rounded value)
15
+ ```
16
+
17
+ ## Props
18
+
19
+ | Prop | Role |
20
+ |------|------|
21
+ | `min`, `max`, `htmlStep` | Range input bounds |
22
+ | `value` | Current position |
23
+ | `disabled` | Gray theme, opacity 0.5, no interaction |
24
+ | `displayValues` | Reserved — tooltip always shows on hover/drag in client |
25
+ | `hasSelectedValue` | Reserved |
26
+ | `sliderType: 'graphics'` | Emoji thumb via `getEmojiForIndex` |
27
+ | `ticks` | Discrete tick count + emoji index scale |
28
+ | `reverseScaleOrder` | Flip emoji index calculation |
29
+
30
+ ## Interactive States
31
+
32
+ | State | Thumb | Tooltip |
33
+ |-------|-------|---------|
34
+ | Default | White circle, 2.5px magenta border | Hidden |
35
+ | Hover/drag | Pink glow ring `rgba(226,0,116,0.2)` | Dark bubble with `Math.round(value)` |
36
+ | Disabled | Gray border, opacity 0.5 | Hidden |
37
+ | Graphics | Emoji at percentage position | Same tooltip |
38
+
39
+ ## Emoji Index Formula
40
+
41
+ ```typescript
42
+ const idx = Math.round(((value - min) / (max - min)) * ((ticks || 10) - 1));
43
+ const displayIdx = reverseScaleOrder ? (ticks || 10) - 1 - idx : idx;
44
+ getEmojiForIndex(displayIdx, ticks || 10)
45
+ ```
46
+
47
+ ## Agent Checklist
48
+
49
+ - [ ] 4-layer overlay with invisible range input
50
+ - [ ] Tooltip on hover AND drag
51
+ - [ ] Graphics mode emoji thumb
52
+ - [ ] Transition disabled while dragging
@@ -0,0 +1,38 @@
1
+ # UI Spec: Matrix Dropdown (shared primitive)
2
+
3
+ > **Implement from this spec** (npm installs). Monorepo reference: `apps/client/src/components/MatrixDropdown.tsx`
4
+ > **Used by:** `LikertMatrixScale`, `CsatMatrixScale` vertical list
5
+
6
+ ## Modes
7
+
8
+ | `multiple` | Trigger | Selection |
9
+ |------------|---------|-----------|
10
+ | `false` | Single line + chevron | One value; checkmark on selected option |
11
+ | `true` | Tag chips with × | Toggle array; N/A mutex |
12
+
13
+ ## Interactive States
14
+
15
+ | State | Trigger border | Shadow |
16
+ |-------|----------------|--------|
17
+ | Closed | `#d1d5db` | subtle |
18
+ | Open | `#e20074` | `0 0 0 3px rgba(226,0,116,0.1)` |
19
+ | Option hover | bg `#fdf2f8` | — |
20
+ | Option selected | bg `#fdf2f8`, text `#e20074` | — |
21
+ | N/A mutex (multi) | Other options opacity 0.5, disabled | — |
22
+
23
+ ## N/A Mutex (multi-select)
24
+
25
+ ```typescript
26
+ if (val === null) {
27
+ if (multiValues.includes(null)) onChange([]);
28
+ else onChange([null]);
29
+ }
30
+ // When null selected, non-null options disabled
31
+ ```
32
+
33
+ ## Agent Checklist
34
+
35
+ - [ ] Click-outside closes panel
36
+ - [ ] HTML labels via dangerouslySetInnerHTML
37
+ - [ ] Single: close on select
38
+ - [ ] Multi: tag chips removable with ×
@@ -33,6 +33,8 @@
33
33
  "id": 4,
34
34
  "name": "planAndIngest",
35
35
  "read": [
36
+ "00-integration/component-checklist.md",
37
+ "03-ui-specs/README.md",
36
38
  "01-components/README.md",
37
39
  "01-components/01-survey-page.md",
38
40
  "01-components/02-question.md",
@@ -49,6 +51,7 @@
49
51
  "01-components/13-matrix-dropdown.md"
50
52
  ],
51
53
  "template": "templates/implementation_plan.md",
54
+ "questionDispatcher": "templates/Question.tsx",
52
55
  "output": "implementation_plan.md"
53
56
  },
54
57
  {
@@ -63,6 +66,8 @@
63
66
  "read": ["00-integration/constraints.md"],
64
67
  "checklist": [
65
68
  "questionDispatcherCoversAll12Types",
69
+ "matrixRoutesBySubType",
70
+ "noStubPlaceholderText",
66
71
  "everyQuestionWrapperHasId",
67
72
  "noInternalSdkImports",
68
73
  "surveyPageFiveStates",
@@ -125,5 +130,26 @@
125
130
  "component": "01-components/02-question.md",
126
131
  "reference": "02-reference/question-types/README.md#text_and_media"
127
132
  }
128
- }
133
+ },
134
+ "uiSpecs": {
135
+ "questionShell": "03-ui-specs/00-question-shell.md",
136
+ "rating": "03-ui-specs/01-rating.md",
137
+ "radio": "03-ui-specs/02-radio.md",
138
+ "text": "03-ui-specs/03-text.md",
139
+ "csat": "03-ui-specs/04-csat.md",
140
+ "rating_scale": "03-ui-specs/05-rating-scale.md",
141
+ "slider": "03-ui-specs/06-slider.md",
142
+ "matrix_CFM_MATRIX": "03-ui-specs/07-matrix-cfm.md",
143
+ "matrix_CSAT_MATRIX": "03-ui-specs/08-matrix-csat-rating.md",
144
+ "matrix_RATING_MATRIX": "03-ui-specs/08-matrix-csat-rating.md",
145
+ "slider_matrix": "03-ui-specs/09-slider-matrix.md",
146
+ "file_upload": "03-ui-specs/10-file-upload.md",
147
+ "text_and_media": "03-ui-specs/11-text-and-media.md",
148
+ "surveyChrome": "03-ui-specs/12-survey-chrome.md"
149
+ },
150
+ "sharedUiSpecs": {
151
+ "customSliderTrack": "03-ui-specs/shared/custom-slider-track.md",
152
+ "matrixDropdown": "03-ui-specs/shared/matrix-dropdown.md"
153
+ },
154
+ "configFieldIndex": "02-reference/config-field-index.md"
129
155
  }
@@ -11,10 +11,12 @@ docs/
11
11
  ├── index.md ← YOU ARE HERE
12
12
  ├── MANIFEST.json ← Phase + question-type routing (for tooling)
13
13
  ├── 00-integration/ ← Setup, hook contract, constraints
14
- ├── 01-components/ ← UI blueprints (read ALL before coding)
15
- ├── 02-reference/ ← Routing table + question-type data (on demand)
14
+ ├── 01-components/ ← Wiring blueprints (read ALL before coding)
15
+ ├── 02-reference/ ← Routing table + config-field-index (on demand)
16
+ ├── 03-ui-specs/ ← Authoritative UI specs (reference-client driven)
16
17
  └── templates/
17
- └── implementation_plan.md
18
+ ├── implementation_plan.md
19
+ └── Question.tsx ← Canonical dispatcher (copy before building)
18
20
  ```
19
21
 
20
22
  **Import rule:** Use whatever package name appears in the project's `package.json` (`@explorer02/cfm-survey-sdk` or `@repo/sdk`).
@@ -63,17 +65,26 @@ Optional: read `02-reference/routing-table.md` for type overview.
63
65
  ### PHASE 4: PLAN + INGEST (CRITICAL)
64
66
 
65
67
  1. Read **every** file in `01-components/` (all 14 blueprints)
66
- 2. Copy `docs/templates/implementation_plan.md` `./implementation_plan.md`
67
- 3. Fill every section do **not** invent a different structure
68
- 4. **Auto-proceed to Phase 5** do not wait for approval
69
-
70
- For each question type in the fetched survey, also read matching docs from `02-reference/question-types/` (see `MANIFEST.json` or `02-reference/routing-table.md`).
68
+ 2. Read `00-integration/component-checklist.md` and `03-ui-specs/README.md`
69
+ 3. **Inventory** every `(type, subType)` in `survey.pages` after instanceId fetch
70
+ 4. For **each type in the survey**, read matching `03-ui-specs/` (use `MANIFEST.json` `uiSpecs`) and `02-reference/question-types/` **blocking** for `matrix`, `slider_matrix`, `file_upload`
71
+ 5. Copy `docs/templates/implementation_plan.md` → `./implementation_plan.md` and fill every section
72
+ 6. Copy `docs/templates/Question.tsx` as the dispatcher starting point
73
+ 7. **Auto-proceed to Phase 5** — do not wait for approval
71
74
 
72
75
  ### PHASE 5: BUILD
73
76
 
74
- Read: `00-integration/constraints.md`
77
+ Read: `00-integration/constraints.md`, `00-integration/component-checklist.md`
78
+
79
+ Create all required scale component files **before** wiring `Question.tsx`. For each question in the survey:
80
+
81
+ 1. Read `02-reference/question-types/{type}.md` for data shape
82
+ 2. Read `03-ui-specs/{NN}-{type}.md` (use `MANIFEST.json` `uiSpecs`; split matrix by `subType`)
83
+ 3. If `matrixFormat`, `buttonType`, or `sliderType` is present → read `03-ui-specs/shared/` specs
84
+ 4. Cross-check `02-reference/config-field-index.md` for every non-default field
85
+ 5. Implement per ui-spec — monorepo devs may consult `apps/client/src/components/`; npm installs use ui-specs only
75
86
 
76
- Implement components per blueprints. Use exported types:
87
+ Implement components per blueprints + UI specs. Use exported types:
77
88
 
78
89
  ```typescript
79
90
  import { useSurveySDK, ACTIONS, type SurveyAction } from '@explorer02/cfm-survey-sdk';
@@ -85,7 +96,10 @@ Read: `00-integration/constraints.md` (troubleshooting)
85
96
 
86
97
  Checklist:
87
98
 
88
- - [ ] `Question.tsx` switch covers all 12 `question.type` values
99
+ - [ ] `Question.tsx` copied from `docs/templates/Question.tsx` — covers all 12 `question.type` values
100
+ - [ ] Matrix routes by `subType` (`CFM_MATRIX` vs `CSAT_MATRIX` / `RATING_MATRIX`)
101
+ - [ ] All scale components from `component-checklist.md` exist for types in survey
102
+ - [ ] **Zero stub text:** `grep -r "not yet implemented" src/ components/ app/` returns no matches
89
103
  - [ ] Every question wrapper has `id={question.id}`
90
104
  - [ ] No imports from `@explorer02/cfm-survey-sdk/src/...`
91
105
  - [ ] `SurveyPage` handles loading / error / empty / submitted / active
@@ -104,6 +118,7 @@ If yes: `npx cfm-sdk deploy` (preferred) or `npx vercel --prod --yes`
104
118
  | When | Read |
105
119
  |------|------|
106
120
  | Always first | `index.md`, `00-integration/setup.md`, `00-integration/useSurveySDK.md`, `00-integration/constraints.md` |
107
- | Before any React code | All `01-components/*.md` |
108
- | On demand | `02-reference/question-types/<type>.md` for types in survey |
121
+ | Before any React code | All `01-components/*.md`, `00-integration/component-checklist.md`, `templates/Question.tsx` |
122
+ | After instanceId fetch | `03-ui-specs/` per type in survey (blocking for matrix / slider_matrix / file_upload) |
123
+ | Config audit | `02-reference/config-field-index.md` |
109
124
  | Tooling | `MANIFEST.json`, `templates/implementation_plan.md` |