@designfever/web-review-kit 0.1.0 → 0.3.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 (45) hide show
  1. package/README.md +77 -179
  2. package/dist/{chunk-U5K2YGGL.js → chunk-I76WEDLA.js} +2248 -2722
  3. package/dist/chunk-I76WEDLA.js.map +1 -0
  4. package/dist/index.cjs +2346 -2603
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +10 -6
  7. package/dist/index.d.ts +10 -6
  8. package/dist/index.js +220 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/react-shell.cjs +8953 -6632
  11. package/dist/react-shell.cjs.map +1 -1
  12. package/dist/react-shell.d.cts +8 -3
  13. package/dist/react-shell.d.ts +8 -3
  14. package/dist/react-shell.js +5956 -3636
  15. package/dist/react-shell.js.map +1 -1
  16. package/dist/{types-D_mNjOHx.d.cts → types-Cf2x5ky6.d.cts} +8 -14
  17. package/dist/{types-D_mNjOHx.d.ts → types-Cf2x5ky6.d.ts} +8 -14
  18. package/dist/vite.cjs +186 -0
  19. package/dist/vite.cjs.map +1 -0
  20. package/dist/vite.d.cts +16 -0
  21. package/dist/vite.d.ts +16 -0
  22. package/dist/vite.js +161 -0
  23. package/dist/vite.js.map +1 -0
  24. package/docs/README.md +21 -30
  25. package/docs/adaptor.sample.ts +182 -0
  26. package/docs/architecture.md +125 -0
  27. package/docs/db-setup.md +253 -0
  28. package/docs/figma-overlay.md +52 -0
  29. package/docs/grid-overlay.md +38 -0
  30. package/docs/installation.md +108 -40
  31. package/package.json +22 -6
  32. package/dist/chunk-U5K2YGGL.js.map +0 -1
  33. package/docs/adapter-handoff.md +0 -146
  34. package/docs/concept.md +0 -102
  35. package/docs/df-sheet-adapter.md +0 -336
  36. package/docs/df-sheet-next.md +0 -222
  37. package/docs/initial-plan.md +0 -226
  38. package/docs/package-split-checkpoint.md +0 -79
  39. package/docs/presence-handoff.md +0 -138
  40. package/docs/review-feedback-2026-06-20.md +0 -267
  41. package/docs/smoke-baseline-2026-06-20.md +0 -41
  42. package/docs/stabilize-ui-work-guide.md +0 -243
  43. package/docs/supabase-presence.md +0 -198
  44. package/docs/supabase-review-items.md +0 -365
  45. package/docs/supabase.md +0 -205
@@ -1,41 +0,0 @@
1
- # Smoke baseline 2026-06-20
2
-
3
- Scope: `packages/df-web-review-kit` task 761, before UI token/chrome changes.
4
-
5
- Environment:
6
-
7
- - Branch: `uforgot/feat/review-kit-stabilize-ui`
8
- - Dev URL: `http://127.0.0.1:5181/review/?target=%2F&w=540&h=1080`
9
- - Timestamp: `2026-06-20 11:31:21 KST`
10
- - `.env`: Supabase URL, anon key, table, presence-private flags were present. Secret values were not logged.
11
-
12
- Commands:
13
-
14
- ```bash
15
- pnpm review-kit:build
16
- pnpm exec vite --host 127.0.0.1 --port 5181 --strictPort
17
- ```
18
-
19
- Checklist result:
20
-
21
- | Check | Result | Note |
22
- | --- | --- | --- |
23
- | Local note create | Pass | Created `smoke-761 local note` from review shell UI. |
24
- | Local element QA create | Pass | Created `smoke-761 local element`; item had `anchor` and `selection`. |
25
- | Local area QA create | Pass* | CDP drag event was unreliable for the area drawer, so a synthetic area item was inserted through the same local storage shape to validate listing/rendering baseline. Manual browser drag still needs a quick human pass if this becomes a regression point. |
26
- | Item restore after scroll | Pass | Stable lower-page item restored from `scrollY 0` to `6487`, target top `517`. |
27
- | Remote submit to Supabase | Pass | Local item submitted; remote source showed canonical `#10`. |
28
- | Remote source list | Pass | `source=supabase` listed the smoke item plus existing remote items. |
29
- | Remote status change | Pass | Status changed from `todo` to `doing` and persisted after refresh. |
30
- | Remote delete | Pass | Smoke item deleted from Supabase; no longer present after refresh. |
31
- | `/review?source=supabase&target=...&item=...` restore | Pass | Remote item URL restored to the lower-page anchor before deletion: `/review/?target=%2F&w=540&h=1080&source=supabase&item=852662d1-410a-46b9-b047-b0abba55e83f`. |
32
-
33
- Cleanup:
34
-
35
- - Deleted the remote smoke item from Supabase.
36
- - Removed local `smoke-761` items from localStorage.
37
-
38
- Notes:
39
-
40
- - Figma overlay loaded because the local token was available; this was not part of the 761 smoke scope.
41
- - The area creation interaction should be manually spot-checked once UI chrome work starts, because automated pointer drag did not open the area note drawer reliably in CDP.
@@ -1,243 +0,0 @@
1
- # Stabilize UI work guide
2
-
3
- Branch:
4
-
5
- ```txt
6
- uforgot/feat/review-kit-stabilize-ui
7
- ```
8
-
9
- Purpose:
10
-
11
- `df-web-review-kit`를 package로 분리하기 전에 0.1 기반을 안정화하고, review shell chrome을 token 기반 UI로 정리한다.
12
-
13
- ## Scope
14
-
15
- In scope:
16
-
17
- - Fix DOM anchor restore bug.
18
- - Establish smoke test baseline for current review workflow.
19
- - Introduce `df-review-token` layer inspired by Vercel Geist tokens.
20
- - Apply tokenized UI to review shell chrome.
21
- - Split only the React shell parts that block the UI cleanup.
22
- - Prepare package split checklist.
23
-
24
- Out of scope:
25
-
26
- - Figma overlay module migration.
27
- - Editing proposal feature.
28
- - Source patch AI adapter.
29
- - Full rewrite of `react-shell.tsx`.
30
-
31
- Follow-up branches:
32
-
33
- ```txt
34
- uforgot/feat/review-kit-figma-module
35
- uforgot/feat/review-kit-editing-proposal
36
- ```
37
-
38
- ## Work order
39
-
40
- ### 0. Fix anchor restore
41
-
42
- Files:
43
-
44
- ```txt
45
- src/react-shell/anchor-restore.ts
46
- src/core/web-review-kit-app.ts
47
- ```
48
-
49
- Goal:
50
-
51
- Element-mode review items must restore by DOM anchor even when their `scope` is a viewport scope such as `mobile` or `desktop`.
52
-
53
- Context:
54
-
55
- Current `queryReviewItemAnchorElement` exits unless `item.scope === 'dom'`, but element-mode items can be stored as `kind: note` with `anchor + selection` and viewport scope.
56
-
57
- Deliverable:
58
-
59
- - Shared or local predicate that treats `scope === 'dom'` or `kind === 'note' && anchor && selection` as anchor-restorable.
60
- - Anchor restore path uses that predicate.
61
-
62
- Verification:
63
-
64
- - Create an element-mode QA item.
65
- - Scroll away.
66
- - Click the item in the QA list.
67
- - The target element is restored by selector/anchor, not only by stale coordinates.
68
-
69
- ### 1. Capture smoke baseline
70
-
71
- Goal:
72
-
73
- Before UI changes, confirm the current workflow still works.
74
-
75
- Deliverable:
76
-
77
- - Manual smoke checklist result in the PR/commit notes or a short docs note.
78
-
79
- Verification checklist:
80
-
81
- - Local note create.
82
- - Local element QA create.
83
- - Local area QA create.
84
- - Item restore after scroll.
85
- - Remote submit to Supabase.
86
- - Remote source list.
87
- - Remote status change.
88
- - Remote delete.
89
- - `/review?source=supabase&target=...&item=...` restore.
90
-
91
- ### 2. Add review token layer
92
-
93
- Files:
94
-
95
- ```txt
96
- src/react-shell/style.ts
97
- src/core/overlay-style.ts
98
- ```
99
-
100
- Goal:
101
-
102
- Adopt a developer-tool UI tone using Vercel Geist as reference, without depending on Vercel token names at runtime.
103
-
104
- Rules:
105
-
106
- - Use `df-review-token` or `--df-review-*` naming.
107
- - Do not expose `geist` or `vercel` as public API names.
108
- - Keep light/dark theme support.
109
- - Use neutral surfaces, restrained color, clear state colors.
110
- - Do not change target page styling.
111
-
112
- Deliverable:
113
-
114
- - CSS custom properties for color, spacing, radius, typography, shadow/border.
115
- - Existing chrome components consume those variables.
116
-
117
- Verification:
118
-
119
- - Dark and light themes render correctly.
120
- - Buttons, selects, cards, modals, and overlay controls keep usable contrast.
121
- - Target iframe content is not affected.
122
-
123
- ### 3. Apply UI chrome refresh
124
-
125
- Files:
126
-
127
- ```txt
128
- src/react-shell.tsx
129
- src/react-shell/style.ts
130
- src/core/overlay-style.ts
131
- ```
132
-
133
- Goal:
134
-
135
- Refresh only the review tool UI, not the host website UI.
136
-
137
- Targets:
138
-
139
- - Topbar.
140
- - Path input and load/copy buttons.
141
- - Source select and refresh button.
142
- - Viewport preset buttons.
143
- - Grid, Figma, ruler, settings controls.
144
- - QA cards.
145
- - Prompt/settings/sitemap modals.
146
-
147
- Deliverable:
148
-
149
- - More consistent developer-tool chrome.
150
- - Icon buttons stay compact.
151
- - Text does not overflow in compact panels.
152
-
153
- Verification:
154
-
155
- - Mobile, tablet, desktop, wide review presets.
156
- - QA list open/closed states.
157
- - Empty state and filtered state.
158
- - Prompt/settings/sitemap modals.
159
-
160
- ### 4. Split only blocking React shell parts
161
-
162
- Goal:
163
-
164
- Reduce `react-shell.tsx` risk without turning this branch into a rewrite.
165
-
166
- Allowed splits:
167
-
168
- - `Topbar`.
169
- - `ItemList`.
170
- - `SettingsModal`.
171
- - `PromptModal`.
172
- - `SitemapModal`.
173
-
174
- Rules:
175
-
176
- - Split only when the UI token work becomes hard to review in one file.
177
- - Keep behavior unchanged.
178
- - Avoid new state architecture in this branch.
179
-
180
- Deliverable:
181
-
182
- - Smaller reviewable components if needed.
183
- - No broad refactor.
184
-
185
- Verification:
186
-
187
- - Typecheck passes.
188
- - Existing interactions still work.
189
-
190
- ### 5. Package split checkpoint
191
-
192
- Goal:
193
-
194
- Make the package ready to split after this branch, before Figma module migration.
195
-
196
- Checklist:
197
-
198
- - `package.json` export map is accurate.
199
- - `files` list is intentional.
200
- - `react` and `react-dom` stay peer dependencies.
201
- - Decide whether `lucide-react` is peer or bundled.
202
- - `src`, `dist`, and `docs` publishing policy is explicit.
203
- - Host project consumes the package through the same exported API.
204
-
205
- Deliverable:
206
-
207
- - Short package split note or checklist update.
208
-
209
- Verification:
210
-
211
- ```bash
212
- pnpm --dir packages/df-web-review-kit typecheck
213
- pnpm exec tsc --noEmit
214
- pnpm review-kit:build
215
- ```
216
-
217
- ## Figma module boundary for next branch
218
-
219
- Figma overlay migration should start only after this branch is stable.
220
-
221
- Boundary:
222
-
223
- - Package core renders overlay.
224
- - Host provides image URL/blob or a Figma asset adapter.
225
- - Browser-exposed Figma token and Figma REST fetch do not enter package core.
226
- - Current viewport replaces host zustand `isMobile/clientWidth` dependency.
227
-
228
- Expected next branch:
229
-
230
- ```txt
231
- uforgot/feat/review-kit-figma-module
232
- ```
233
-
234
- ## Completion criteria
235
-
236
- This branch is ready for review when:
237
-
238
- - Anchor restore bug is fixed.
239
- - Smoke baseline is documented.
240
- - UI token layer is in place.
241
- - Review shell chrome is visually consistent.
242
- - Typecheck and build pass.
243
- - Figma migration remains out of scope.
@@ -1,198 +0,0 @@
1
- # Supabase presence adapter
2
-
3
- ## 목적
4
-
5
- `df-web-review-kit`의 `ReviewPresenceAdapter` contract를 Supabase Realtime Presence로 구현하고 운영하기 위한 문서다.
6
-
7
- Lexus pilot Supabase project:
8
-
9
- ```txt
10
- name: bb-qa
11
- url: https://vhqnvfkamnpgyqclohso.supabase.co
12
- ```
13
-
14
- 공식 문서 기준:
15
-
16
- - Presence는 접속자/활성 문서 같은 느리게 변하는 상태 공유에 맞다: https://supabase.com/docs/guides/realtime/presence
17
- - Realtime은 Broadcast, Presence, Postgres Changes를 제공한다: https://supabase.com/docs/guides/realtime
18
- - DB 변경 fan-out은 Broadcast가 scalability/security 측면에서 권장되고, Postgres Changes는 단순하지만 scale이 약하다: https://supabase.com/docs/guides/realtime/subscribing-to-database-changes
19
- - private Broadcast/Presence는 `realtime.messages` RLS policy와 `private: true` channel 설정이 필요하다: https://supabase.com/docs/guides/realtime/authorization
20
-
21
- ## 현재 결론
22
-
23
- 이번 presence 요구사항은 Supabase Presence가 맞다.
24
-
25
- 목표는 "QA item이 바뀌면 실시간으로 동기화"가 아니라 "현재 누가 어떤 page/viewport/source를 보고 있는지"다. 따라서 Postgres Changes나 Broadcast보다 Presence가 먼저다.
26
-
27
- 현재 shell UI는 두 단계로 보여준다.
28
-
29
- - 우측 QA panel: 현재 page에 있는 user id만 표시
30
- - sitemap: page별 user id 표시
31
-
32
- ## Channel 전략
33
-
34
- 권장 channel topic:
35
-
36
- ```txt
37
- review-presence-<projectId>
38
- ```
39
-
40
- page별 channel이 아니라 project 단위 channel을 쓴다. 그래야 `/review`를 열어 둔 사람이 서로 다른 page를 보고 있어도 sitemap에서 "누가 어느 페이지에 있는지"를 볼 수 있다.
41
-
42
- Payload의 `target`/`routeKey`로 page를 구분한다.
43
-
44
- topic은 Supabase Realtime 호환성을 위해 `:` 같은 구분자를 쓰지 않고, adapter에서 `channelPrefix`와 `projectId`를 alphanumeric/`_`/`-` slug로 normalize한다.
45
-
46
- ## Adapter implementation
47
-
48
- 현재 구현 위치:
49
-
50
- ```txt
51
- packages/df-web-review-kit/src/react-shell/supabase-presence.ts
52
- ```
53
-
54
- 현재 package adapter는 Supabase client를 직접 생성하지 않고 `client`를 주입받는다. Host page 쪽에서 `@supabase/supabase-js`의 `createClient()`를 호출해 넘긴다. 이렇게 하면 package 본체가 Supabase dependency에 강하게 묶이지 않는다.
55
-
56
- 현재 구현 특징:
57
-
58
- - channel topic은 `review-presence-<projectId>`로 생성한다.
59
- - `projectId`, `sessionId`, `userId`, `routeKey`, `target`, `source`, `viewport`, `mode`, `selectedItemId`, `selectedReviewNumber`를 track한다.
60
- - StrictMode/HMR에서 같은 topic channel이 중복으로 남지 않도록 bridge/refCount를 둔다.
61
- - `presenceState()` 결과는 `sessionId` 기준으로 dedupe한다.
62
- - primary Supabase presence 연결이 실패하면 `createFallbackPresenceAdapter()`로 local BroadcastChannel presence를 쓸 수 있다.
63
-
64
- ## Public dev mode
65
-
66
- 초기 연결 검증은 public channel로도 가능하다.
67
-
68
- ```ts
69
- const presence = createSupabasePresenceAdapter({
70
- client: supabase,
71
- private: false,
72
- });
73
- ```
74
-
75
- 주의:
76
-
77
- - public channel은 같은 Supabase project key를 가진 사용자가 topic을 알면 subscribe 가능하다.
78
- - dev smoke test까지만 허용한다.
79
-
80
- ## Private production mode
81
-
82
- production은 private channel을 권장한다.
83
-
84
- ```ts
85
- const presence = createSupabasePresenceAdapter({
86
- client: supabase,
87
- private: true,
88
- });
89
- ```
90
-
91
- client는 인증 세션을 가진 Supabase client여야 한다. private channel은 Realtime Authorization policy가 필요하다.
92
-
93
- ## RLS sketch
94
-
95
- Supabase Realtime Authorization은 `realtime.messages`에 대한 RLS policy로 Broadcast/Presence 권한을 계산한다.
96
-
97
- project membership table을 둔다고 가정한다.
98
-
99
- ```sql
100
- create table if not exists public.review_project_members (
101
- project_id text not null,
102
- user_id uuid not null references auth.users(id) on delete cascade,
103
- created_at timestamptz not null default now(),
104
- primary key (project_id, user_id)
105
- );
106
-
107
- alter table public.review_project_members enable row level security;
108
-
109
- create policy review_project_members_read_own
110
- on public.review_project_members
111
- for select
112
- to authenticated
113
- using ((select auth.uid()) = user_id);
114
-
115
- create index if not exists review_project_members_user_project_idx
116
- on public.review_project_members (user_id, project_id);
117
- ```
118
-
119
- Presence topic은 `review-presence-<projectId>` 형식이므로 RLS에서 topic을 project id로 해석한다.
120
-
121
- ```sql
122
- create or replace function public.review_presence_project_id(topic text)
123
- returns text
124
- language sql
125
- immutable
126
- as $$
127
- select nullif(regexp_replace(topic, '^review-presence-', ''), topic);
128
- $$;
129
- ```
130
-
131
- Presence read/write policy:
132
-
133
- ```sql
134
- create policy "authenticated can listen to review presence"
135
- on realtime.messages
136
- for select
137
- to authenticated
138
- using (
139
- realtime.messages.extension = 'presence'
140
- and exists (
141
- select 1
142
- from public.review_project_members member
143
- where member.user_id = (select auth.uid())
144
- and member.project_id = public.review_presence_project_id((select realtime.topic()))
145
- )
146
- );
147
-
148
- create policy "authenticated can track review presence"
149
- on realtime.messages
150
- for insert
151
- to authenticated
152
- with check (
153
- realtime.messages.extension = 'presence'
154
- and exists (
155
- select 1
156
- from public.review_project_members member
157
- where member.user_id = (select auth.uid())
158
- and member.project_id = public.review_presence_project_id((select realtime.topic()))
159
- )
160
- );
161
- ```
162
-
163
- RLS performance notes:
164
-
165
- - `auth.uid()`는 `(select auth.uid())` 형태로 감싸서 per-row 호출을 줄인다.
166
- - RLS 조건에서 조회하는 `(user_id, project_id)`는 composite index를 둔다.
167
- - policy가 복잡해질수록 channel join latency가 늘 수 있다.
168
-
169
- ## Env
170
-
171
- Lexus pilot에 붙일 때 후보 env:
172
-
173
- ```txt
174
- VITE_REVIEW_SUPABASE_URL=https://vhqnvfkamnpgyqclohso.supabase.co
175
- VITE_REVIEW_SUPABASE_ANON_KEY=
176
- VITE_REVIEW_SUPABASE_PRESENCE_PRIVATE=false
177
- ```
178
-
179
- 브라우저에는 anon key만 둔다. service role key는 절대 넣지 않는다.
180
-
181
- `VITE_REVIEW_SUPABASE_ANON_KEY`가 비어 있으면 shell은 local BroadcastChannel presence로 fallback한다.
182
-
183
- ## QA checklist
184
-
185
- 1. Settings에서 각 브라우저에 다른 `User ID` 입력
186
- 2. Browser A/B: 같은 target page로 `/review?target=/&w=540&h=1080`
187
- 3. A/B 양쪽 우측 QA panel에서 서로의 user id 확인
188
- 4. Browser B를 다른 target page로 이동
189
- 5. A의 우측 QA panel에서는 B가 사라지고, sitemap에서는 B가 이동한 page에 표시되는지 확인
190
- 6. B에서 viewport 변경 후 presence payload의 viewport가 바뀌는지 devtools로 확인
191
- 7. B에서 다른 QA item 선택 후 `selectedReviewNumber`가 payload에 들어가는지 devtools로 확인
192
- 8. B tab close 후 A에서 B가 사라지는지 확인
193
-
194
- ## Open decisions
195
-
196
- - public dev mode를 package에 남길지.
197
- - private presence를 실제 production에서 쓸 때 auth/member policy를 어디까지 package 문서화할지.
198
- - sitemap presence를 별도 dashboard로 키울지.