@designfever/web-review-kit 0.5.0 → 0.7.0

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 (42) hide show
  1. package/.env.sample +29 -0
  2. package/README.md +36 -10
  3. package/dist/chunk-AB5B6O77.js +584 -0
  4. package/dist/chunk-AB5B6O77.js.map +1 -0
  5. package/dist/{chunk-TWCSIBMY.js → chunk-RPVLRULC.js} +736 -201
  6. package/dist/chunk-RPVLRULC.js.map +1 -0
  7. package/dist/image.types-BmzkFSPX.d.cts +71 -0
  8. package/dist/image.types-BmzkFSPX.d.ts +71 -0
  9. package/dist/index.cjs +1251 -202
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +27 -3
  12. package/dist/index.d.ts +27 -3
  13. package/dist/index.js +50 -3
  14. package/dist/index.js.map +1 -1
  15. package/dist/react-shell.cjs +10135 -4070
  16. package/dist/react-shell.cjs.map +1 -1
  17. package/dist/react-shell.d.cts +37 -4
  18. package/dist/react-shell.d.ts +37 -4
  19. package/dist/react-shell.js +9258 -3707
  20. package/dist/react-shell.js.map +1 -1
  21. package/dist/token-Dt-ZH-YO.d.cts +88 -0
  22. package/dist/token-nJXPPdYX.d.ts +88 -0
  23. package/dist/{types-RvVa5ns-.d.cts → types-DT9Z66mV.d.cts} +14 -1
  24. package/dist/{types-RvVa5ns-.d.ts → types-DT9Z66mV.d.ts} +14 -1
  25. package/dist/vite.cjs +1116 -5
  26. package/dist/vite.cjs.map +1 -1
  27. package/dist/vite.d.cts +45 -1
  28. package/dist/vite.d.ts +45 -1
  29. package/dist/vite.js +800 -5
  30. package/dist/vite.js.map +1 -1
  31. package/docs/README.md +11 -5
  32. package/docs/adapters.md +126 -0
  33. package/docs/adaptor.sample.ts +13 -1
  34. package/docs/architecture.md +6 -1
  35. package/docs/code-review-0.6.0.md +232 -0
  36. package/docs/db-setup.md +4 -2
  37. package/docs/figma-image-mvp-0.7.0.md +327 -0
  38. package/docs/installation.md +44 -8
  39. package/docs/release-notes-0.6.0.md +108 -0
  40. package/docs/release-notes-0.7.0.md +128 -0
  41. package/package.json +6 -2
  42. package/dist/chunk-TWCSIBMY.js.map +0 -1
@@ -0,0 +1,232 @@
1
+ # 코드 리뷰 및 정리: 0.6.0 → 0.7.0 준비
2
+
3
+ 리뷰 대상: `df-web-review-kit@0.6.0` (`origin/main` 기준)
4
+ 작업 브랜치: `chore/0.7.0-code-review-cleanup`
5
+ 범위: `src/**` 구조 정리, 죽은 코드/죽은 export 제거, dead-code 검사 설정 추가
6
+
7
+ ---
8
+
9
+ ## 요약
10
+
11
+ 0.6.0에서 기능이 늘며 가장 크게 비대한 파일은 `src/react-shell/style.ts`였다. 단일 함수 안에 3,500줄 이상 CSS 문자열이 들어 있었고, Source Tree / QA list / composer / modal / ruler 스타일이 한 파일에 섞여 있었다.
12
+
13
+ 이번 0.7.0 준비 브랜치에서는 위험도가 낮은 정리부터 적용했다.
14
+
15
+ 1. `react-shell/style.ts`를 7개 스타일 chunk로 분리
16
+ 2. 실제 미사용 함수/타입/상수와 내부 전용 helper의 잘못된 export 제거
17
+ 3. `knip` 설정과 `pnpm lint:dead-code` 스크립트 추가
18
+ 4. `typecheck`, `typecheck:dev`, `lint:dead-code`, `build` 통과 확인
19
+
20
+ ---
21
+
22
+ ## 1. 한 파일에 몰린 곳
23
+
24
+ ### 정리 전 상위 파일
25
+
26
+ | 파일 | LOC | 문제 |
27
+ |---|---:|---|
28
+ | `src/react-shell/style.ts` | 3,579 | 단일 함수가 전체 review shell CSS 문자열을 보유 |
29
+ | `src/react-shell/review/shell.tsx` | 2,306 | `ReviewShell` 단일 컴포넌트에 상태/핸들러/렌더가 많이 남음 |
30
+ | `src/core/web.review.kit.view.ts` | 1,937 | overlay, scroll, draft, anchor 책임이 한 클래스에 집중 |
31
+ | `src/core/overlay.style.ts` | 1,025 | core overlay CSS 덩어리 |
32
+ | `src/core/dom.anchor.ts` | 818 | anchor 후보/매칭 로직 집중 |
33
+ | `src/react-shell/source.open.ts` | 785 | Source Tree 기능 확장으로 커짐 |
34
+
35
+ ### 이번 브랜치에서 처리한 부분
36
+
37
+ `src/react-shell/style.ts`를 작은 조립 파일로 줄이고, CSS는 역할별 파일로 이동했다.
38
+
39
+ | 파일 | 역할 | 현재 LOC |
40
+ |---|---|---:|
41
+ | `src/react-shell/style.ts` | style tag 주입 + chunk 조립 | 26 |
42
+ | `src/react-shell/style/base.ts` | token, reset, topbar 공통 | 401 |
43
+ | `src/react-shell/style/sitemap.ts` | sitemap modal/table | 317 |
44
+ | `src/react-shell/style/modals.ts` | settings/edit/prompt modal | 606 |
45
+ | `src/react-shell/style/toolbar.ts` | tools, side rail, presence | 530 |
46
+ | `src/react-shell/style/qa-panel.ts` | QA panel/list/card/actions | 722 |
47
+ | `src/react-shell/style/stage.ts` | stage/frame/target/device | 138 |
48
+ | `src/react-shell/style/source-inspector.ts` | source outline/popover/candidate | 153 |
49
+ | `src/react-shell/style/section-outline.ts` | section outline panel | 539 |
50
+ | `src/react-shell/style/ruler.ts` | ruler + responsive media query | 262 |
51
+
52
+ 동작 변화 없이 문자열을 나눠서 `ensureReviewShellStyle()`에서 concat만 하도록 정리했다.
53
+
54
+ > 0.7.0 후속(아래 6장)에서 `stage.ts`를 `stage` / `source-inspector` / `section-outline` 3개로 더 쪼갰다.
55
+
56
+ ---
57
+
58
+ ## 2. 죽은 코드 / 죽은 export 정리
59
+
60
+ `knip` 결과를 기준으로 public entry false positive와 실제 내부 전용 helper를 구분했다.
61
+
62
+ ### 삭제한 실제 미사용 코드
63
+
64
+ | 파일 | 삭제 내용 |
65
+ |---|---|
66
+ | `src/react-shell/prompt/prompt.ts` | 미사용 `formatItemMeta`, `formatDate` 삭제 |
67
+ | `src/react-shell/source.open.ts` | 미사용 `SOURCE_SELECTOR`, `getSourceHintElement`, `getElementSourceHint` 삭제 |
68
+ | `src/core/geometry.ts` | 미사용 `getAreaPopoverPosition` 삭제 |
69
+ | `src/core/location.ts` | 미사용 alias `getNormalizedPath` 삭제 |
70
+ | `src/core/review/format.ts` | 미사용 `formatAreaDraftMeta` 삭제 |
71
+
72
+ ### export만 제거하고 내부 helper로 남긴 것
73
+
74
+ 아래 항목은 같은 파일 내부에서는 쓰이지만 외부 export가 필요 없던 helper다. 삭제하지 않고 `export`만 제거했다.
75
+
76
+ - `src/react-shell/anchor.restore.ts`
77
+ - `getReviewItemExpectedDocumentRect`
78
+ - `getReviewAnchorMatchScore`
79
+ - `getElementDocumentRect`
80
+ - `getReviewTextFingerprintScore`
81
+ - `getReviewFingerprintTokens`
82
+ - `isScrollableReviewAnchorElement`
83
+ - `src/react-shell/prompt/prompt.ts`
84
+ - `formatPromptViewport`
85
+ - `formatPromptPoint`
86
+ - `formatPromptSelection`
87
+ - `decodePromptHtmlEntities`
88
+ - `getPromptAnchorCandidates`
89
+ - `formatPromptSourceHint`
90
+ - `src/core/geometry.ts`
91
+ - `rectanglesIntersect`
92
+ - `getPopoverBounds`
93
+ - `src/react-shell/route.ts`
94
+ - `normalizeReviewPathPrefix`
95
+ - `getHashRoutePath`
96
+ - `src/react-shell/settings.ts`
97
+ - `normalizeStoredReviewSidePanel`
98
+ - `normalizeStoredReviewQaStatusFilter`
99
+ - `src/react-shell/viewport.ts`
100
+ - `getFallbackPreset`
101
+ - `getViewportPresetDistance`
102
+ - `src/react-shell/target/target.ts`
103
+ - `HIDE_SCROLLBAR_STYLE_ID`
104
+ - `FIGMA_POINTER_LOCK_STYLE_ID`
105
+ - `src/react-shell/review/shell.actions.ts`
106
+ - `listReviewItems`
107
+ - `listSitemapReviewItems`
108
+ - 내부 타입 export 축소
109
+ - `src/core/review/draft.ts`
110
+ - `src/react-shell/sitemap/tree.ts`
111
+ - `src/react-shell/source.open.ts`
112
+ - `src/react-shell/types.ts`
113
+
114
+ ---
115
+
116
+ ## 3. Dead-code 검사 설정
117
+
118
+ 추가 파일:
119
+
120
+ - `knip.json`
121
+
122
+ 추가 스크립트:
123
+
124
+ ```json
125
+ "lint:dead-code": "knip"
126
+ ```
127
+
128
+ 설정 의도:
129
+
130
+ - public entry는 `src/index.ts`, `src/react-shell.tsx`, `src/vite.ts`로 명시
131
+ - 검사 대상은 `src/**/*.{ts,tsx}`로 제한
132
+ - `dist/**`와 `docs/adaptor.sample.ts` 같은 빌드 산출물/샘플은 검사 대상 밖에 둬서 false positive를 막음
133
+
134
+ 현재 `pnpm lint:dead-code`는 이 설정으로 0 issue 통과한다.
135
+
136
+ ---
137
+
138
+ ## 4. 아직 남은 큰 덩어리
139
+
140
+ 이번 브랜치에서는 위험도가 낮은 style split + dead-code cleanup까지만 적용했다. 아래는 별도 브랜치에서 작은 단위로 나누는 게 안전하다.
141
+
142
+ ### `src/react-shell/review/shell.tsx` (2,306 LOC)
143
+
144
+ 남은 책임:
145
+
146
+ - source panel resize / delayed close
147
+ - source candidate popover state
148
+ - section outline filtering / expand state
149
+ - prompt modal copy/open 흐름
150
+ - QA list selection + card action bridge
151
+
152
+ 추천 다음 작업:
153
+
154
+ 1. `use.source.panel.ts`
155
+ 2. `use.section.outline.ts`
156
+ 3. `use.prompt.modal.ts`
157
+ 4. `use.qa.selection.ts`
158
+
159
+ `ReviewShell`은 layout assembly + child component wiring 정도로 줄이는 게 목표다.
160
+
161
+ ### `src/core/web.review.kit.view.ts` (1,937 LOC)
162
+
163
+ 남은 책임:
164
+
165
+ - overlay 렌더링
166
+ - scroll sync
167
+ - draft 작성/취소/저장
168
+ - anchor restore
169
+ - marker lifecycle
170
+
171
+ 추천 다음 작업:
172
+
173
+ 1. draft controller 분리
174
+ 2. marker renderer 분리
175
+ 3. scroll/restore orchestration 분리
176
+ 4. view class는 조립/라이프사이클만 담당
177
+
178
+ ---
179
+
180
+ ## 5. 검증
181
+
182
+ 실행한 명령:
183
+
184
+ ```bash
185
+ pnpm lint:dead-code
186
+ pnpm typecheck
187
+ pnpm typecheck:dev
188
+ pnpm build
189
+ ```
190
+
191
+ 결과:
192
+
193
+ - `pnpm lint:dead-code` 통과
194
+ - `pnpm typecheck` 통과
195
+ - `pnpm typecheck:dev` 통과
196
+ - `pnpm build` 통과
197
+
198
+ `pnpm build` 결과로 `dist/**` 산출물이 갱신됐고, 기존 chunk hash는 `chunk-IN36JHEU` → `chunk-BDP7FS4Q`로 변경됐다.
199
+
200
+ ---
201
+
202
+ ## 6. 0.7.0 후속 정리 (continued)
203
+
204
+ 같은 브랜치에서 Figma image 기능이 추가된 뒤, 위험도 낮은 정리를 한 단계 더 진행했다. 모두 동작/공개 API 변화 없는 내부 리팩터이며 단계별 커밋으로 나눴다.
205
+
206
+ ### CSS
207
+
208
+ - `shell.tsx`에 인라인으로 박혀 있던 source-select 단축키 CSS(65줄)를 `react-shell/review/source.shortcut.style.ts`로 추출 (`createSourceShortcutStyle`).
209
+ - 비대했던 `style/stage.ts`(827줄)를 도메인 기준으로 3분할: `stage.ts`(138) / `source-inspector.ts`(153) / `section-outline.ts`(539). 실제 내용이 stage가 아니라 section/source 위주였던 점을 반영.
210
+
211
+ ### 네이밍 (내부 한정, export 무변경)
212
+
213
+ - `dom.anchor.ts`: `primary` → `primaryCandidate`, `safeClosest` → `tryClosest`.
214
+ - `normalizeStoredReviewSidePanel` 등 정상 normalizer는 형제 함수와의 일관성 때문에 유지.
215
+
216
+ ### 주석
217
+
218
+ - `dom.anchor.ts`의 경로 생성(`getDomPath`/`getDomPathBetween`)·스코어링(`getTextFingerprintScore`/`getSelectionMatchScore`) 알고리즘, `view.ts`의 큰 메서드(`createNotePopover`/`createAdjustmentControls`), 매직 넘버(z-index `2147483646`, 길이 제한 160/120, `roundRatio` 정밀도) 설명 추가.
219
+
220
+ ### 파일 분할 (안전 범위)
221
+
222
+ | 원본 | 추출 | 결과 |
223
+ |---|---|---|
224
+ | `vite.ts` (1492) | `vite/figma-asset.ts` (포맷/경로 헬퍼 10개) | 1424 |
225
+ | `core/web.review.kit.view.ts` (1937) | `core/draft.metrics.ts` (draft adjustment 순수 geometry) | 1901 |
226
+ | `react-shell/figma/images.panel.tsx` (737) | `figma/image-panel.utils.ts` (순수 유틸 8개) | 669 |
227
+
228
+ §4의 `web.review.kit.view.ts` 항목 중 "draft controller 분리"의 첫 조각으로 순수 geometry부터 뽑았다. `shell.tsx`의 대규모 hook 분리와 `images.panel`의 `ImageCard` 컴포넌트 분리(drag 상태·ref 결합으로 회귀 위험 큼)는 여전히 후속 작업으로 남겨 둔다.
229
+
230
+ ### 검증
231
+
232
+ 각 단계마다 `pnpm typecheck` 통과, 추출 단계는 `pnpm lint:dead-code`(knip) 0 issue, 최종 `pnpm build` 통과 확인.
package/docs/db-setup.md CHANGED
@@ -4,9 +4,11 @@ Supabase is an optional backend adapter. A host project may use it for canonical
4
4
 
5
5
  ## Environment
6
6
 
7
+ Start from [.env.sample](../.env.sample), then fill Supabase values only in the host project that uses the Supabase adapter.
8
+
7
9
  ```env
8
- VITE_REVIEW_PROJECT_ID=df-web-review-kit
9
- VITE_REVIEW_SUPABASE_URL=https://your-project.supabase.co
10
+ VITE_REVIEW_PROJECT_ID=my-project
11
+ VITE_REVIEW_SUPABASE_URL=
10
12
  VITE_REVIEW_SUPABASE_ANON_KEY=
11
13
  VITE_REVIEW_SUPABASE_TABLE=review_items
12
14
  VITE_REVIEW_SUPABASE_PRESENCE_PRIVATE=false
@@ -0,0 +1,327 @@
1
+ # Figma Image MVP 0.7.0 Structure Note
2
+
3
+ This is the investigation note for Todo 802, `Figma 이미지 MVP 구조 조사`.
4
+ It records the minimum 0.7.0 scope before implementation.
5
+
6
+ ## Goal
7
+
8
+ 0.7.0 should add a dev/local Figma image management MVP without breaking the
9
+ current host-helper flow.
10
+
11
+ - If a Figma image store is configured, the review shell uses the new image
12
+ management flow.
13
+ - If no Figma image store is configured, the shell keeps the current Figma
14
+ helper fallback: dispatch the host keyboard shortcut and detect the host
15
+ overlay.
16
+ - `FIGMA_TOKEN` is required only by the Figma image server/dev endpoint when it
17
+ renders or adds an image. It must not become a package-wide or browser env
18
+ requirement.
19
+ - Rendered images should be downloaded into a local/dev asset cache. Prefer webp
20
+ when an image transformer is configured, but keep `png`/`jpg` fallback without
21
+ adding a package dependency. Always keep the original `figmaUrl`, `fileKey`,
22
+ and `nodeId` so the image can be regenerated later.
23
+ - Removing keyboard shortcut helpers from host projects belongs after the MVP
24
+ has stabilized.
25
+
26
+ ## Current State
27
+
28
+ ### Existing Review Adapters
29
+
30
+ `WebReviewKitAdapter` is a QA item persistence contract:
31
+
32
+ - `get`
33
+ - `list`
34
+ - `create`
35
+ - `update`
36
+ - `remove`
37
+
38
+ `ReviewShellAdapter` wraps that contract for shell sources, status handling,
39
+ submission sync, and write-mode checks. It is intentionally centered on
40
+ `ReviewItem`.
41
+
42
+ Do not overload this adapter for Figma image bindings in 0.7.0. Figma images
43
+ need their own small store contract so QA item source switching, status updates,
44
+ and submission sync do not become coupled to image management.
45
+
46
+ ### Current Figma Integration
47
+
48
+ The current Figma integration is only a host-helper toggle:
49
+
50
+ - `docs/figma-overlay.md` states that the package does not fetch Figma data or
51
+ own a server-side token.
52
+ - `src/react-shell/figma.ts` reads `window.__figma` and builds a Figma frame
53
+ link from `fileKey->nodeId`.
54
+ - `src/react-shell/hooks/use.review.target.overlay.ts` dispatches `KeyF` into
55
+ the iframe target when the Figma overlay is toggled.
56
+ - `src/react-shell/settings.ts` and `use.review.settings.ts` store the current
57
+ `figma-token` setting in browser `localStorage`.
58
+ - `dev/src/main.tsx` currently provides a dev `window.__figma` fixture.
59
+
60
+ This flow should remain as the fallback for projects that have no image store.
61
+
62
+ ### Dev Server Gap
63
+
64
+ `src/vite.ts` currently exports source/data locator plugins only. There is no
65
+ middleware endpoint yet.
66
+
67
+ A local `fileAdapter` cannot be browser-only, because browser code cannot write
68
+ a JSON file. The local MVP should add a Vite/dev-server endpoint and expose a
69
+ browser store client that calls that endpoint.
70
+
71
+ ## Proposed 0.7.0 Shape
72
+
73
+ ### Public/Shell Option
74
+
75
+ Add an optional shell-level Figma image config. Keep it absent by default.
76
+
77
+ ```ts
78
+ type ReviewShellFigmaImagesOptions = {
79
+ store?: ReviewFigmaImageStore;
80
+ enabled?: boolean;
81
+ };
82
+
83
+ interface ReviewShellProps {
84
+ // existing props...
85
+ figmaImages?: ReviewShellFigmaImagesOptions;
86
+ }
87
+ ```
88
+
89
+ Fallback rule:
90
+
91
+ - `figmaImages?.store` exists: show/use Figma image management UI.
92
+ - `figmaImages?.store` is missing: keep the current host-helper overlay button
93
+ and keyboard shortcut behavior.
94
+
95
+ ### Store Contract
96
+
97
+ The 0.7.0 contract should be separate from `WebReviewKitAdapter`.
98
+
99
+ ```ts
100
+ type ReviewFigmaImageTarget =
101
+ | { type: 'route'; projectId: string; pageUrl: string; slot?: string }
102
+ | { type: 'figma-node'; projectId: string; fileKey: string; nodeId: string };
103
+
104
+ type ReviewFigmaImage = {
105
+ id: string;
106
+ projectId: string;
107
+ target: ReviewFigmaImageTarget;
108
+ figmaUrl: string;
109
+ fileKey: string;
110
+ nodeId: string;
111
+ imageUrl: string;
112
+ imageFormat: 'webp' | 'png' | 'jpg';
113
+ mimeType: string;
114
+ label?: string;
115
+ order: number;
116
+ storageKey?: string;
117
+ width?: number;
118
+ height?: number;
119
+ byteSize?: number;
120
+ createdAt: string;
121
+ updatedAt: string;
122
+ };
123
+
124
+ type ReviewFigmaImageStore = {
125
+ listImages(target: ReviewFigmaImageTarget): Promise<ReviewFigmaImage[]>;
126
+ addImage(input: {
127
+ target: ReviewFigmaImageTarget;
128
+ figmaUrl: string;
129
+ imageFormat?: 'webp' | 'png' | 'jpg';
130
+ }): Promise<ReviewFigmaImage>;
131
+ deleteImage(id: string): Promise<void>;
132
+ reorderImages(input: {
133
+ target: ReviewFigmaImageTarget;
134
+ imageIds: string[];
135
+ }): Promise<ReviewFigmaImage[]>;
136
+ updateImage(
137
+ id: string,
138
+ patch: Partial<Pick<ReviewFigmaImage, 'label' | 'order'>>
139
+ ): Promise<ReviewFigmaImage>;
140
+ };
141
+ ```
142
+
143
+ `addImage` owns the internal image rendering/upload/cache step. The UI should
144
+ not know whether the returned `imageUrl` came from a local dev server,
145
+ OpenClaw-hosted upload, or a future Cloudflare-backed uploader.
146
+
147
+ Default target output is `image/webp` with a quality setting around 90-95 for
148
+ review/reference overlays, but the package should not force an image conversion
149
+ dependency for the dev MVP. Without a configured transformer, the local cache
150
+ stores the actual Figma render format (`png` or `jpg`) and records that real
151
+ `mimeType`/`imageFormat` in metadata.
152
+
153
+ ### Module Layout
154
+
155
+ Use the architecture doc's existing direction, but convert the current single
156
+ `src/react-shell/figma.ts` file into a small module when implementation begins.
157
+
158
+ ```txt
159
+ src/figma/
160
+ image.types.ts
161
+ parse.ts
162
+
163
+ src/react-shell/figma/
164
+ image.client.ts
165
+ image.panel.tsx
166
+ image.state.ts
167
+ frame.ts
168
+
169
+ src/vite.ts
170
+ reviewFigmaImageStore()
171
+ ```
172
+
173
+ Suggested responsibilities:
174
+
175
+ - `src/figma/parse.ts`: parse Figma node copy links into `fileKey` and `nodeId`.
176
+ - `src/react-shell/figma/image.client.ts`: browser client for the dev endpoint
177
+ or any host-provided store.
178
+ - `src/react-shell/figma/image.panel.tsx`: list/add/delete/reorder UI.
179
+ - `src/vite.ts`: dev middleware for local JSON metadata and Figma rendering.
180
+
181
+ ### Local MVP Endpoint
182
+
183
+ Add a dev plugin instead of trying to write files from browser code.
184
+
185
+ ```ts
186
+ reviewFigmaImageStore({
187
+ enabled: true,
188
+ projectId: 'df-web-review-kit',
189
+ dataFile: '.df-review/figma-images.json',
190
+ });
191
+ ```
192
+
193
+ Endpoint shape can stay internal for 0.7.0, but should map directly to the
194
+ store contract:
195
+
196
+ - `GET /__dfwr/figma-images`
197
+ - `POST /__dfwr/figma-images`
198
+ - `PATCH /__dfwr/figma-images/:id`
199
+ - `DELETE /__dfwr/figma-images/:id`
200
+
201
+ The dev endpoint reads `FIGMA_TOKEN` from server env only when it needs to call
202
+ Figma. Do not expose `VITE_FIGMA_TOKEN`.
203
+
204
+ Token validation is intentionally lazy:
205
+
206
+ - Store missing or disabled: no token check, keep the current host-helper
207
+ fallback.
208
+ - Store enabled but no image render/add request has happened: no token check.
209
+ - Image render/add request: require `FIGMA_TOKEN` from the dev/server
210
+ environment and return `DFWR_FIGMA_TOKEN_MISSING` when it is absent.
211
+
212
+ ## Impact Files
213
+
214
+ Expected package-side implementation files:
215
+
216
+ - `.env.sample`: document server-only `FIGMA_TOKEN` separately from browser
217
+ `VITE_*` values.
218
+ - `src/types.ts` or `src/figma/image.types.ts`: shared Figma image types.
219
+ - `src/index.ts`: export public Figma image types/parser only if needed by host
220
+ projects.
221
+ - `src/react-shell/types.ts`: add optional `figmaImages`.
222
+ - `src/react-shell/review/shell.tsx`: pass state/actions into the panel and
223
+ preserve existing fallback behavior.
224
+ - `src/react-shell/topbar.tsx`: keep the existing overlay toggle available when
225
+ no image store exists.
226
+ - `src/react-shell/review/settings.modal.tsx` and
227
+ `src/react-shell/hooks/use.review.settings.ts`: stop treating browser
228
+ `figma-token` as the new API token. Keep it only for legacy host helpers if
229
+ needed.
230
+ - `src/vite.ts`: add the dev local metadata endpoint.
231
+ - `dev/vite.config.ts` and `dev/src/main.tsx`: wire the local MVP for dogfood.
232
+
233
+ Token helpers already added for the implementation steps:
234
+
235
+ - `readReviewFigmaToken()` / `requireReviewFigmaToken()` validate an explicit
236
+ token/env object without reading browser globals.
237
+ - `readReviewFigmaServerToken()` / `requireReviewFigmaServerToken()` are
238
+ exported from `@designfever/web-review-kit/vite` for dev/server-only code.
239
+ - `ReviewFigmaTokenError` carries `DFWR_FIGMA_TOKEN_MISSING` so UI/API callers
240
+ can show a clear setup error.
241
+
242
+ Parser/render helpers already added for the implementation steps:
243
+
244
+ - `parseReviewFigmaNodeRef()` accepts either a Figma copy link or existing
245
+ `fileKey->nodeId` value.
246
+ - URL `node-id` values are normalized from Figma web form like `4-228` to API
247
+ form like `4:228`.
248
+ - `createReviewFigmaFrameUrl()` centralizes Figma frame link generation.
249
+ - `renderReviewFigmaServerImage()` is exported from
250
+ `@designfever/web-review-kit/vite` and calls Figma `/v1/images/:fileKey` with
251
+ a server-side token.
252
+ - The Figma API render URL is a temporary source URL. The local file adapter now
253
+ downloads it into the dev asset cache before writing JSON metadata.
254
+
255
+ Local metadata store helpers already added for the implementation steps:
256
+
257
+ - `createReviewFigmaImageStoreClient()` creates a browser-side
258
+ `ReviewFigmaImageStore` that calls the dev endpoint.
259
+ - `reviewFigmaImageStore()` is exported from
260
+ `@designfever/web-review-kit/vite` and adds the local dev middleware.
261
+ - The default endpoint is `/__dfwr/figma-images`.
262
+ - The dev fixture stores metadata at `.df-review/figma-images.json`; the
263
+ `.df-review` folder is gitignored.
264
+ - The local middleware downloads rendered image binaries into
265
+ `.df-review/figma-assets` by default and stores the served local asset URL as
266
+ `imageUrl`.
267
+ - The asset endpoint defaults to `/__dfwr/figma-images/assets`.
268
+ - `cacheAssets: false` keeps the old temporary render URL behavior for debugging.
269
+ - `transformAsset` can convert the downloaded data before it is written, which
270
+ is where a future sharp/Cloudflare webp conversion step should plug in.
271
+
272
+ Review page multi-image UI already added for the implementation steps:
273
+
274
+ - When `figmaImages.store` is configured, the shell shows a Figma Images side
275
+ panel.
276
+ - The panel supports list, add, delete, reorder, select, and overlay opacity
277
+ controls for the current route + viewport target.
278
+ - When no store is configured, the legacy host-helper Figma overlay fallback is
279
+ still used.
280
+
281
+ Release snapshot helpers already added for the implementation steps:
282
+
283
+ - `createReviewFigmaImagesSnapshot()` clones and sorts image metadata for JSON
284
+ persistence.
285
+ - `createReviewFigmaReleaseSnapshot()` returns a release-shaped JSON object
286
+ with `figmaImagesSnapshot`.
287
+ - `collectReviewFigmaReleaseSnapshot()` can collect images through any
288
+ `ReviewFigmaImageStore` for a set of targets.
289
+ - The local Vite middleware exposes
290
+ `GET/POST /__dfwr/figma-images/snapshot` for dev release JSON snapshots.
291
+
292
+ Expected host-project follow-up files after stabilization:
293
+
294
+ - `lexus_official_v2026/src/helper/helper.review-kit.ts`: remove per-project
295
+ helper wiring only after 0.7.0 fallback has been verified.
296
+ - Host review route files: pass the image store config only for projects that
297
+ opt into the new flow.
298
+
299
+ ## Release Boundary
300
+
301
+ There is no runtime "review release" model in the current package code. The
302
+ existing release files are package release notes.
303
+
304
+ For 0.7.0, do not introduce a release table or separate release image store.
305
+ Todo 808 can keep this simple by snapshotting the current image list as JSON on
306
+ whatever release object gets introduced:
307
+
308
+ ```ts
309
+ figmaImagesSnapshot: ReviewFigmaImage[];
310
+ ```
311
+
312
+ That is enough to ensure old review releases do not change when the current
313
+ project/page Figma bindings are edited later.
314
+
315
+ ## Verification Plan
316
+
317
+ For Todo 802, this document is the artifact.
318
+
319
+ For the following implementation todos:
320
+
321
+ - Adapter missing: `/review` still works with current keyboard shortcut/Figma
322
+ helper fallback.
323
+ - Adapter configured and `FIGMA_TOKEN` missing: adding/rendering a Figma image
324
+ returns a clear error without breaking the rest of the review shell.
325
+ - Adapter configured and `FIGMA_TOKEN` present: a Figma node copy link can be
326
+ added, listed, deleted, reordered, and survives dev server restart.
327
+ - Existing QA adapters still pass `pnpm typecheck` and `pnpm build`.
@@ -3,6 +3,7 @@
3
3
  Install `df-web-review-kit` in a host project and mount the review shell on a `/review` route.
4
4
 
5
5
  The default setup is local-only. Remote DB and presence are optional adapters.
6
+ For the QA adapter and Figma image store split, see [Adapter boundaries](adapters.md).
6
7
 
7
8
  ## Package Install
8
9
 
@@ -16,6 +17,22 @@ Supabase is optional. Install it only in host projects that use the Supabase ada
16
17
  pnpm add @supabase/supabase-js
17
18
  ```
18
19
 
20
+ ## Environment
21
+
22
+ Copy the repository [.env.sample](../.env.sample) into the host project as `.env.local`.
23
+
24
+ ```bash
25
+ cp node_modules/@designfever/web-review-kit/.env.sample .env.local
26
+ ```
27
+
28
+ For a local-only setup, set only the project id:
29
+
30
+ ```env
31
+ VITE_REVIEW_PROJECT_ID=my-project
32
+ ```
33
+
34
+ Supabase and source-opening values are optional. Leave Supabase URL/key empty when the review shell should use local browser storage only.
35
+
19
36
  ## Vite Route
20
37
 
21
38
  Create a review entry such as:
@@ -44,7 +61,7 @@ import {
44
61
  localAdapter,
45
62
  } from '@designfever/web-review-kit';
46
63
 
47
- const REVIEW_PROJECT_ID = 'my-project';
64
+ const REVIEW_PROJECT_ID = import.meta.env.VITE_REVIEW_PROJECT_ID || 'my-project';
48
65
  const REVIEW_PATH_PREFIX = '/review';
49
66
 
50
67
  const local = localAdapter({
@@ -111,7 +128,7 @@ import {
111
128
  } from '@designfever/web-review-kit';
112
129
  import { createClient } from '@supabase/supabase-js';
113
130
 
114
- const REVIEW_PROJECT_ID = 'my-project';
131
+ const REVIEW_PROJECT_ID = import.meta.env.VITE_REVIEW_PROJECT_ID || 'my-project';
115
132
  const REVIEW_PATH_PREFIX = '/review';
116
133
 
117
134
  const local = localAdapter({
@@ -218,7 +235,19 @@ export default defineConfig({
218
235
 
219
236
  Captured DOM nodes will include `data-wrk-source-file`, `data-wrk-source-line`, and `data-wrk-source-column`. Data locator also injects `__wrkDataFile` and `__wrkDataLine` props into page data section objects so the shell can expose matching `data-wrk-data-*` hints when host components forward those props to section wrappers.
220
237
 
221
- In the review shell, hold `Option` over the target iframe to show source candidates from the DOM ancestry. Click the target to pin the candidate list, then choose which file to open. The side rail Source Tree panel lists section/source/data candidates and can scroll to a section or open its source/data file. If the file path is absolute, it opens directly. If the plugin stores relative paths, pass `sourceRoot` when mounting the shell.
238
+ In the review shell, hold `Option` over the target iframe to show source candidates from the DOM ancestry. Click the target to pin the candidate list, then choose which file to open. The side rail Source Tree panel lists section/source/data candidates and can scroll to a section or open its source/data file. It can also show live box metrics, text/font metadata, media URLs, and class tags for each node. If the file path is absolute, it opens directly. If the plugin stores relative paths, pass `sourceRoot` when mounting the shell.
239
+
240
+ Source opening reads these optional host env values from `.env.local`:
241
+
242
+ ```env
243
+ VITE_REVIEW_SOURCE_ROOT=/absolute/path/to/project
244
+ VITE_REVIEW_SOURCE_EDITOR=cursor
245
+ VITE_REVIEW_SOURCE_URL_TEMPLATE=
246
+ ```
247
+
248
+ `VITE_REVIEW_SOURCE_ROOT` is needed when the locator stores relative paths. Absolute source paths can open without it. `VITE_REVIEW_SOURCE_EDITOR` supports `vscode`, `cursor`, `webstorm`, and `custom`. Use `VITE_REVIEW_SOURCE_URL_TEMPLATE` only with `custom`; the template supports `{path}`, `{encodedPath}`, `{line}`, and `{column}`.
249
+
250
+ In Vite/ESM hosts, env values override matching `sourceRoot`, `sourceInspector.editor`, and `sourceInspector.urlTemplate` init values. Init values still work as a fallback for existing projects and CommonJS consumers.
222
251
 
223
252
  ```tsx
224
253
  mountReviewShell({
@@ -226,9 +255,7 @@ mountReviewShell({
226
255
  pages,
227
256
  adapters,
228
257
  reviewPathPrefix: REVIEW_PATH_PREFIX,
229
- sourceRoot: import.meta.env.VITE_REVIEW_SOURCE_ROOT,
230
258
  sourceInspector: {
231
- editor: 'vscode', // 'vscode' | 'cursor' | 'webstorm' | 'custom'
232
259
  maxDepth: 9,
233
260
  hoverOutline: true,
234
261
  includePlacer: false,
@@ -242,9 +269,13 @@ Set `sourceInspector.enabled` to `false` when source code opening should be unav
242
269
 
243
270
  Use this only in dev/review builds. Source paths are written into the browser DOM and can be persisted with QA items.
244
271
 
272
+ Source Tree filter/options, side panel state, and QA status filter are browser-local UI preferences. They are stored in localStorage and are not sent through the adapter.
273
+
274
+ In React shell mode, DOM/area draft composers dock into the QA panel when the shell provides a composer host. This keeps mobile Safari keyboard/viewport resize from moving a floating composer layer over the target frame.
275
+
245
276
  ## Custom Adapter
246
277
 
247
- If a team or host project owns its own QA backend, keep that adapter in the host project or in a separate package. Start from [adaptor.sample.ts](adaptor.sample.ts) and map its `WebReviewKitAdapter` methods to your backend API.
278
+ If a team or host project owns its own QA backend, keep that adapter in the host project or in a separate package. Start from [adaptor.sample.ts](adaptor.sample.ts) and map its `WebReviewKitAdapter` methods to your backend API. Do not put Figma image storage into the QA adapter; use a separate `ReviewFigmaImageStore`.
248
279
 
249
280
  The sample explains the main interfaces:
250
281
 
@@ -257,12 +288,17 @@ Private keys, admin credentials, canonical numbering, and permission checks shou
257
288
 
258
289
  ## Environment
259
290
 
291
+ The full copyable template is [.env.sample](../.env.sample).
292
+
260
293
  ```env
261
- VITE_REVIEW_PROJECT_ID=df-web-review-kit
262
- VITE_REVIEW_SUPABASE_URL=https://your-project.supabase.co
294
+ VITE_REVIEW_PROJECT_ID=my-project
295
+ VITE_REVIEW_SUPABASE_URL=
263
296
  VITE_REVIEW_SUPABASE_ANON_KEY=
264
297
  VITE_REVIEW_SUPABASE_TABLE=review_items
265
298
  VITE_REVIEW_SUPABASE_PRESENCE_PRIVATE=false
299
+ VITE_REVIEW_SOURCE_ROOT=/absolute/path/to/project
300
+ VITE_REVIEW_SOURCE_EDITOR=cursor
301
+ VITE_REVIEW_SOURCE_URL_TEMPLATE=
266
302
  ```
267
303
 
268
304
  Rules: