@designfever/web-review-kit 0.1.0 → 0.2.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.
- package/README.md +59 -184
- package/dist/{chunk-U5K2YGGL.js → chunk-EJDROXJM.js} +2583 -3085
- package/dist/chunk-EJDROXJM.js.map +1 -0
- package/dist/index.cjs +2615 -2900
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -6
- package/dist/index.d.ts +10 -6
- package/dist/index.js +220 -7
- package/dist/index.js.map +1 -1
- package/dist/react-shell.cjs +8364 -6651
- package/dist/react-shell.cjs.map +1 -1
- package/dist/react-shell.d.cts +7 -3
- package/dist/react-shell.d.ts +7 -3
- package/dist/react-shell.js +5163 -3425
- package/dist/react-shell.js.map +1 -1
- package/dist/{types-D_mNjOHx.d.cts → types-NiCp9JJQ.d.cts} +6 -14
- package/dist/{types-D_mNjOHx.d.ts → types-NiCp9JJQ.d.ts} +6 -14
- package/docs/README.md +21 -30
- package/docs/adaptor.sample.ts +182 -0
- package/docs/architecture.md +125 -0
- package/docs/db-setup.md +253 -0
- package/docs/figma-overlay.md +52 -0
- package/docs/grid-overlay.md +38 -0
- package/docs/installation.md +75 -40
- package/package.json +8 -3
- package/dist/chunk-U5K2YGGL.js.map +0 -1
- package/docs/adapter-handoff.md +0 -146
- package/docs/concept.md +0 -102
- package/docs/df-sheet-adapter.md +0 -336
- package/docs/df-sheet-next.md +0 -222
- package/docs/initial-plan.md +0 -226
- package/docs/package-split-checkpoint.md +0 -79
- package/docs/presence-handoff.md +0 -138
- package/docs/review-feedback-2026-06-20.md +0 -267
- package/docs/smoke-baseline-2026-06-20.md +0 -41
- package/docs/stabilize-ui-work-guide.md +0 -243
- package/docs/supabase-presence.md +0 -198
- package/docs/supabase-review-items.md +0 -365
- package/docs/supabase.md +0 -205
package/docs/db-setup.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# DB Setup
|
|
2
|
+
|
|
3
|
+
Supabase is an optional backend adapter. A host project may use it for canonical QA items and Realtime Presence, but the public package does not own the Supabase project or any operator secrets.
|
|
4
|
+
|
|
5
|
+
## Environment
|
|
6
|
+
|
|
7
|
+
```env
|
|
8
|
+
VITE_REVIEW_PROJECT_ID=df-web-review-kit
|
|
9
|
+
VITE_REVIEW_SUPABASE_URL=https://your-project.supabase.co
|
|
10
|
+
VITE_REVIEW_SUPABASE_ANON_KEY=
|
|
11
|
+
VITE_REVIEW_SUPABASE_TABLE=review_items
|
|
12
|
+
VITE_REVIEW_SUPABASE_PRESENCE_PRIVATE=false
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use only an `anon` key in browser env. Keep `service_role`, OpenClaw `KUKU_*`, and future admin keys in an operator layer or backend service.
|
|
16
|
+
|
|
17
|
+
## Review Item Schema
|
|
18
|
+
|
|
19
|
+
Run this in the Supabase SQL editor to create the tables, indexes, RPC, and grants.
|
|
20
|
+
|
|
21
|
+
```sql
|
|
22
|
+
create table if not exists public.review_items (
|
|
23
|
+
id text primary key,
|
|
24
|
+
project_id text not null,
|
|
25
|
+
route_key text not null,
|
|
26
|
+
source text not null default 'supabase',
|
|
27
|
+
review_number integer,
|
|
28
|
+
status text not null default 'todo',
|
|
29
|
+
item jsonb not null,
|
|
30
|
+
created_at timestamptz not null default now(),
|
|
31
|
+
updated_at timestamptz not null default now()
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
create unique index if not exists review_items_project_review_number_idx
|
|
35
|
+
on public.review_items (project_id, source, review_number)
|
|
36
|
+
where review_number is not null;
|
|
37
|
+
|
|
38
|
+
create index if not exists review_items_project_route_updated_idx
|
|
39
|
+
on public.review_items (project_id, source, route_key, updated_at desc);
|
|
40
|
+
|
|
41
|
+
create index if not exists review_items_project_status_idx
|
|
42
|
+
on public.review_items (project_id, source, status);
|
|
43
|
+
|
|
44
|
+
create table if not exists public.review_project_counters (
|
|
45
|
+
project_id text not null,
|
|
46
|
+
source text not null default 'supabase',
|
|
47
|
+
next_review_number integer not null default 1,
|
|
48
|
+
updated_at timestamptz not null default now(),
|
|
49
|
+
primary key (project_id, source),
|
|
50
|
+
constraint review_project_counters_next_review_number_check
|
|
51
|
+
check (next_review_number > 0)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
create or replace function public.create_review_item(
|
|
55
|
+
p_id text,
|
|
56
|
+
p_project_id text,
|
|
57
|
+
p_route_key text,
|
|
58
|
+
p_source text,
|
|
59
|
+
p_status text,
|
|
60
|
+
p_item jsonb
|
|
61
|
+
)
|
|
62
|
+
returns public.review_items
|
|
63
|
+
language plpgsql
|
|
64
|
+
security invoker
|
|
65
|
+
set search_path = public
|
|
66
|
+
as $$
|
|
67
|
+
declare
|
|
68
|
+
v_review_number integer;
|
|
69
|
+
v_now timestamptz := now();
|
|
70
|
+
v_row public.review_items;
|
|
71
|
+
begin
|
|
72
|
+
insert into public.review_project_counters (
|
|
73
|
+
project_id,
|
|
74
|
+
source,
|
|
75
|
+
next_review_number,
|
|
76
|
+
updated_at
|
|
77
|
+
)
|
|
78
|
+
select
|
|
79
|
+
p_project_id,
|
|
80
|
+
p_source,
|
|
81
|
+
coalesce(max(review_number), 0) + 2,
|
|
82
|
+
v_now
|
|
83
|
+
from public.review_items
|
|
84
|
+
where project_id = p_project_id
|
|
85
|
+
and source = p_source
|
|
86
|
+
on conflict (project_id, source) do update
|
|
87
|
+
set next_review_number = greatest(
|
|
88
|
+
public.review_project_counters.next_review_number + 1,
|
|
89
|
+
excluded.next_review_number
|
|
90
|
+
),
|
|
91
|
+
updated_at = excluded.updated_at
|
|
92
|
+
returning next_review_number - 1 into v_review_number;
|
|
93
|
+
|
|
94
|
+
insert into public.review_items (
|
|
95
|
+
id,
|
|
96
|
+
project_id,
|
|
97
|
+
route_key,
|
|
98
|
+
source,
|
|
99
|
+
review_number,
|
|
100
|
+
status,
|
|
101
|
+
item,
|
|
102
|
+
created_at,
|
|
103
|
+
updated_at
|
|
104
|
+
)
|
|
105
|
+
values (
|
|
106
|
+
p_id,
|
|
107
|
+
p_project_id,
|
|
108
|
+
p_route_key,
|
|
109
|
+
p_source,
|
|
110
|
+
v_review_number,
|
|
111
|
+
p_status,
|
|
112
|
+
p_item || jsonb_build_object(
|
|
113
|
+
'id', p_id,
|
|
114
|
+
'reviewNumber', v_review_number,
|
|
115
|
+
'projectId', p_project_id,
|
|
116
|
+
'routeKey', p_route_key,
|
|
117
|
+
'normalizedPath', coalesce(nullif(p_item->>'normalizedPath', ''), p_route_key),
|
|
118
|
+
'status', p_status,
|
|
119
|
+
'externalIssueId', p_id,
|
|
120
|
+
'submittedAt', coalesce(p_item->>'submittedAt', v_now::text),
|
|
121
|
+
'submitStatus', coalesce(p_item->>'submitStatus', 'submitted'),
|
|
122
|
+
'createdAt', v_now::text,
|
|
123
|
+
'updatedAt', v_now::text
|
|
124
|
+
),
|
|
125
|
+
v_now,
|
|
126
|
+
v_now
|
|
127
|
+
)
|
|
128
|
+
returning * into v_row;
|
|
129
|
+
|
|
130
|
+
return v_row;
|
|
131
|
+
end;
|
|
132
|
+
$$;
|
|
133
|
+
|
|
134
|
+
grant execute on function public.create_review_item(
|
|
135
|
+
text,
|
|
136
|
+
text,
|
|
137
|
+
text,
|
|
138
|
+
text,
|
|
139
|
+
text,
|
|
140
|
+
jsonb
|
|
141
|
+
) to anon;
|
|
142
|
+
|
|
143
|
+
grant select, insert, update, delete on public.review_items to anon;
|
|
144
|
+
grant select, insert, update on public.review_project_counters to anon;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## RLS Policies
|
|
148
|
+
|
|
149
|
+
Run this after the schema SQL. Replace `df-web-review-kit` if `VITE_REVIEW_PROJECT_ID` uses a different value.
|
|
150
|
+
|
|
151
|
+
```sql
|
|
152
|
+
alter table public.review_items enable row level security;
|
|
153
|
+
alter table public.review_project_counters enable row level security;
|
|
154
|
+
|
|
155
|
+
drop policy if exists review_items_sample_read on public.review_items;
|
|
156
|
+
create policy review_items_sample_read
|
|
157
|
+
on public.review_items
|
|
158
|
+
for select
|
|
159
|
+
to anon
|
|
160
|
+
using (project_id = 'df-web-review-kit');
|
|
161
|
+
|
|
162
|
+
drop policy if exists review_items_sample_insert on public.review_items;
|
|
163
|
+
create policy review_items_sample_insert
|
|
164
|
+
on public.review_items
|
|
165
|
+
for insert
|
|
166
|
+
to anon
|
|
167
|
+
with check (project_id = 'df-web-review-kit');
|
|
168
|
+
|
|
169
|
+
drop policy if exists review_items_sample_update on public.review_items;
|
|
170
|
+
create policy review_items_sample_update
|
|
171
|
+
on public.review_items
|
|
172
|
+
for update
|
|
173
|
+
to anon
|
|
174
|
+
using (project_id = 'df-web-review-kit')
|
|
175
|
+
with check (project_id = 'df-web-review-kit');
|
|
176
|
+
|
|
177
|
+
drop policy if exists review_items_sample_delete on public.review_items;
|
|
178
|
+
create policy review_items_sample_delete
|
|
179
|
+
on public.review_items
|
|
180
|
+
for delete
|
|
181
|
+
to anon
|
|
182
|
+
using (project_id = 'df-web-review-kit');
|
|
183
|
+
|
|
184
|
+
drop policy if exists review_project_counters_sample_read on public.review_project_counters;
|
|
185
|
+
create policy review_project_counters_sample_read
|
|
186
|
+
on public.review_project_counters
|
|
187
|
+
for select
|
|
188
|
+
to anon
|
|
189
|
+
using (project_id = 'df-web-review-kit');
|
|
190
|
+
|
|
191
|
+
drop policy if exists review_project_counters_sample_insert on public.review_project_counters;
|
|
192
|
+
create policy review_project_counters_sample_insert
|
|
193
|
+
on public.review_project_counters
|
|
194
|
+
for insert
|
|
195
|
+
to anon
|
|
196
|
+
with check (project_id = 'df-web-review-kit');
|
|
197
|
+
|
|
198
|
+
drop policy if exists review_project_counters_sample_update on public.review_project_counters;
|
|
199
|
+
create policy review_project_counters_sample_update
|
|
200
|
+
on public.review_project_counters
|
|
201
|
+
for update
|
|
202
|
+
to anon
|
|
203
|
+
using (project_id = 'df-web-review-kit')
|
|
204
|
+
with check (project_id = 'df-web-review-kit');
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Adapter Behavior
|
|
208
|
+
|
|
209
|
+
- `list`: reads by `project_id`, `source`, optional `route_key`, optional `status`.
|
|
210
|
+
- `create`: discards local draft number and calls `create_review_item` for a canonical `review_number`.
|
|
211
|
+
- `update`: updates row columns and the nested `item` JSON.
|
|
212
|
+
- `remove`: deletes the row.
|
|
213
|
+
|
|
214
|
+
Remote numbers are canonical. Local draft numbers can overlap between browsers and are not reused as remote numbers.
|
|
215
|
+
|
|
216
|
+
## Presence
|
|
217
|
+
|
|
218
|
+
Supabase Presence is optional session state. It is not QA item storage.
|
|
219
|
+
|
|
220
|
+
Default topic:
|
|
221
|
+
|
|
222
|
+
```txt
|
|
223
|
+
review-presence-<projectId>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The adapter normalizes unsafe topic characters. `private=false` is enough for quick dev validation. `private=true` requires an authenticated Supabase session and Realtime authorization policies for `realtime.messages`.
|
|
227
|
+
|
|
228
|
+
Use project-level channels instead of page-level channels so the sitemap can show who is on each page.
|
|
229
|
+
|
|
230
|
+
## Security
|
|
231
|
+
|
|
232
|
+
The RLS policies above are sample/dev policies. Anyone with the anon key and allowed `project_id` can create, update, and delete QA rows.
|
|
233
|
+
|
|
234
|
+
For production, use one of these instead:
|
|
235
|
+
|
|
236
|
+
- Supabase Auth plus project member table based RLS
|
|
237
|
+
- Supabase Edge Function
|
|
238
|
+
- host project backend proxy
|
|
239
|
+
- private admin service
|
|
240
|
+
|
|
241
|
+
Never put a `service_role` key in browser env.
|
|
242
|
+
|
|
243
|
+
## Validation
|
|
244
|
+
|
|
245
|
+
1. Open `/review?source=supabase`.
|
|
246
|
+
2. Create a local item.
|
|
247
|
+
3. Submit it to remote.
|
|
248
|
+
4. Confirm the local draft disappears.
|
|
249
|
+
5. Confirm remote list/get works.
|
|
250
|
+
6. Change status.
|
|
251
|
+
7. Delete the remote item.
|
|
252
|
+
8. Create another remote item and confirm the number is not reused.
|
|
253
|
+
9. If presence is enabled, open two browser tabs and confirm each user appears on the active page or sitemap.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Figma Overlay
|
|
2
|
+
|
|
3
|
+
The Figma overlay button in the review shell toggles a host-page helper. The package does not fetch Figma data by itself and does not own a server-side Figma token.
|
|
4
|
+
|
|
5
|
+
## User Flow
|
|
6
|
+
|
|
7
|
+
- Open `/review`.
|
|
8
|
+
- Click the settings button.
|
|
9
|
+
- Enter a Figma token if the host helper requires one.
|
|
10
|
+
- Click the Figma overlay button or press `f`.
|
|
11
|
+
|
|
12
|
+
The token is stored in browser localStorage with this key:
|
|
13
|
+
|
|
14
|
+
```txt
|
|
15
|
+
figma-token
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Treat this as a dev/debug convenience. Do not use it for private server tokens.
|
|
19
|
+
|
|
20
|
+
## Availability
|
|
21
|
+
|
|
22
|
+
The shell currently enables the Figma overlay on viewport presets whose `kind` is:
|
|
23
|
+
|
|
24
|
+
- `mobile`
|
|
25
|
+
- `wide`
|
|
26
|
+
|
|
27
|
+
Other viewport kinds show the unavailable message.
|
|
28
|
+
|
|
29
|
+
## Host Requirements
|
|
30
|
+
|
|
31
|
+
The target page inside the iframe must already support the Figma helper.
|
|
32
|
+
|
|
33
|
+
Expected behavior:
|
|
34
|
+
|
|
35
|
+
- The target page reacts to a `KeyboardEvent` with `code: 'KeyF'`.
|
|
36
|
+
- The target page mounts a visible Figma helper layer.
|
|
37
|
+
- The helper root uses one of these selectors:
|
|
38
|
+
- `.helper-figma-root`
|
|
39
|
+
- `.helper-figma-loading-backdrop`
|
|
40
|
+
|
|
41
|
+
The review shell uses those selectors only to detect whether the overlay is active.
|
|
42
|
+
|
|
43
|
+
## Troubleshooting
|
|
44
|
+
|
|
45
|
+
If the button does nothing:
|
|
46
|
+
|
|
47
|
+
- Confirm the iframe target page is same-origin and can receive dispatched keyboard events.
|
|
48
|
+
- Confirm the host helper listens for `KeyF`.
|
|
49
|
+
- Confirm the helper renders `.helper-figma-root` or `.helper-figma-loading-backdrop`.
|
|
50
|
+
- Confirm the current viewport preset is `mobile` or `wide`.
|
|
51
|
+
|
|
52
|
+
If the overlay needs a private Figma integration, move that work to a backend/admin service and expose only browser-safe state to the host page.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Grid Overlay
|
|
2
|
+
|
|
3
|
+
The grid overlay button in the review shell toggles a host-page layout/helper overlay. It is for visual alignment while reviewing pages.
|
|
4
|
+
|
|
5
|
+
## User Flow
|
|
6
|
+
|
|
7
|
+
- Open `/review`.
|
|
8
|
+
- Click the grid button or press `g`.
|
|
9
|
+
- The target page toggles its own grid/helper layer.
|
|
10
|
+
|
|
11
|
+
## Host Requirements
|
|
12
|
+
|
|
13
|
+
The target page inside the iframe must already support the grid helper.
|
|
14
|
+
|
|
15
|
+
Expected behavior:
|
|
16
|
+
|
|
17
|
+
- The target page reacts to a `KeyboardEvent` with `code: 'KeyG'`.
|
|
18
|
+
- The target page toggles a visible grid/helper layer.
|
|
19
|
+
- The active state is reflected by one of these:
|
|
20
|
+
- `document.body.classList.contains('is-help')`
|
|
21
|
+
- `.helper.onShow`
|
|
22
|
+
|
|
23
|
+
The review shell uses those signals to keep the toolbar button state in sync.
|
|
24
|
+
|
|
25
|
+
## Notes
|
|
26
|
+
|
|
27
|
+
- The package does not prescribe the grid design.
|
|
28
|
+
- The grid overlay is not persisted as QA data.
|
|
29
|
+
- Use project-specific CSS/helper code in the host page when the grid differs by brand or design system.
|
|
30
|
+
|
|
31
|
+
## Troubleshooting
|
|
32
|
+
|
|
33
|
+
If the icon state does not change:
|
|
34
|
+
|
|
35
|
+
- Confirm the target page helper is mounted.
|
|
36
|
+
- Confirm it listens for `KeyG`.
|
|
37
|
+
- Confirm it sets `body.is-help` or `.helper.onShow`.
|
|
38
|
+
- Confirm the iframe is same-origin and keyboard events are not blocked.
|
package/docs/installation.md
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
# Installation
|
|
2
2
|
|
|
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
6
|
|
|
7
|
-
|
|
7
|
+
## Package Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
pnpm add @designfever/web-review-kit react react-dom
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Supabase
|
|
13
|
+
Supabase is optional. Install it only in host projects that use the Supabase adapter.
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
pnpm add @supabase/supabase-js
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## Vite Route
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
"@designfever/web-review-kit": "file:packages/df-web-review-kit"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Vite route
|
|
21
|
+
Create a review entry such as:
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
```txt
|
|
24
|
+
page/review/index.html
|
|
25
|
+
page/review/index.tsx
|
|
26
|
+
```
|
|
28
27
|
|
|
29
28
|
Minimal `index.html`:
|
|
30
29
|
|
|
@@ -33,7 +32,7 @@ Minimal `index.html`:
|
|
|
33
32
|
<script type="module" src="./index.tsx"></script>
|
|
34
33
|
```
|
|
35
34
|
|
|
36
|
-
Minimal `index.tsx`:
|
|
35
|
+
Minimal local-only `index.tsx`:
|
|
37
36
|
|
|
38
37
|
```tsx
|
|
39
38
|
import {
|
|
@@ -46,6 +45,8 @@ import {
|
|
|
46
45
|
} from '@designfever/web-review-kit';
|
|
47
46
|
|
|
48
47
|
const REVIEW_PROJECT_ID = 'my-project';
|
|
48
|
+
const REVIEW_PATH_PREFIX = '/review';
|
|
49
|
+
|
|
49
50
|
const local = localAdapter({
|
|
50
51
|
storageKey: `${REVIEW_PROJECT_ID}-review-items`,
|
|
51
52
|
});
|
|
@@ -69,13 +70,13 @@ mountReviewShell({
|
|
|
69
70
|
remove: (id) => local.remove(id),
|
|
70
71
|
},
|
|
71
72
|
],
|
|
72
|
-
reviewPathPrefix:
|
|
73
|
+
reviewPathPrefix: REVIEW_PATH_PREFIX,
|
|
73
74
|
});
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
## Supabase
|
|
77
|
+
## Supabase Adapter
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Host projects that choose Supabase create the client themselves and pass it into the package adapter.
|
|
79
80
|
|
|
80
81
|
```tsx
|
|
81
82
|
import {
|
|
@@ -93,7 +94,7 @@ import {
|
|
|
93
94
|
} from '@designfever/web-review-kit';
|
|
94
95
|
import { createClient } from '@supabase/supabase-js';
|
|
95
96
|
|
|
96
|
-
const REVIEW_PROJECT_ID = '
|
|
97
|
+
const REVIEW_PROJECT_ID = 'my-project';
|
|
97
98
|
const REVIEW_PATH_PREFIX = '/review';
|
|
98
99
|
|
|
99
100
|
const local = localAdapter({
|
|
@@ -157,13 +158,35 @@ const presence = supabaseClient
|
|
|
157
158
|
localPresence
|
|
158
159
|
)
|
|
159
160
|
: localPresence;
|
|
161
|
+
|
|
162
|
+
mountReviewShell({
|
|
163
|
+
projectId: REVIEW_PROJECT_ID,
|
|
164
|
+
pages,
|
|
165
|
+
adapters,
|
|
166
|
+
presence,
|
|
167
|
+
reviewPathPrefix: REVIEW_PATH_PREFIX,
|
|
168
|
+
});
|
|
160
169
|
```
|
|
161
170
|
|
|
162
|
-
|
|
171
|
+
See [DB setup](db-setup.md) before enabling Supabase in a shared environment.
|
|
172
|
+
|
|
173
|
+
## Custom Adapter
|
|
174
|
+
|
|
175
|
+
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.
|
|
176
|
+
|
|
177
|
+
The sample explains the main interfaces:
|
|
178
|
+
|
|
179
|
+
- `ReviewItem`: the full QA payload to persist as structured JSON.
|
|
180
|
+
- `ReviewItemQuery`: filters used by page lists and sitemap counts.
|
|
181
|
+
- `WebReviewKitAdapter`: core CRUD contract.
|
|
182
|
+
- `ReviewShellAdapter`: React shell wiring for source labels, write modes, status updates, and delete actions.
|
|
183
|
+
|
|
184
|
+
Private keys, admin credentials, canonical numbering, and permission checks should stay in your backend, not in browser code.
|
|
163
185
|
|
|
164
186
|
## Environment
|
|
165
187
|
|
|
166
188
|
```env
|
|
189
|
+
VITE_REVIEW_PROJECT_ID=df-web-review-kit
|
|
167
190
|
VITE_REVIEW_SUPABASE_URL=https://your-project.supabase.co
|
|
168
191
|
VITE_REVIEW_SUPABASE_ANON_KEY=
|
|
169
192
|
VITE_REVIEW_SUPABASE_TABLE=review_items
|
|
@@ -172,13 +195,13 @@ VITE_REVIEW_SUPABASE_PRESENCE_PRIVATE=false
|
|
|
172
195
|
|
|
173
196
|
Rules:
|
|
174
197
|
|
|
175
|
-
-
|
|
176
|
-
- `service_role`
|
|
177
|
-
-
|
|
198
|
+
- Browser env uses a Supabase `anon` key only.
|
|
199
|
+
- Never expose `service_role` in browser env.
|
|
200
|
+
- OpenClaw/operator secrets stay outside the host browser and outside this package.
|
|
178
201
|
|
|
179
|
-
## Viewport
|
|
202
|
+
## Viewport Presets
|
|
180
203
|
|
|
181
|
-
|
|
204
|
+
Pass `presets` when a project has custom design widths.
|
|
182
205
|
|
|
183
206
|
```tsx
|
|
184
207
|
mountReviewShell({
|
|
@@ -194,29 +217,41 @@ mountReviewShell({
|
|
|
194
217
|
});
|
|
195
218
|
```
|
|
196
219
|
|
|
197
|
-
##
|
|
198
|
-
|
|
199
|
-
Lexus repo 기준:
|
|
220
|
+
## Local Dev Harness
|
|
200
221
|
|
|
201
222
|
```bash
|
|
202
223
|
pnpm dev:review
|
|
203
|
-
pnpm review-kit:typecheck
|
|
204
|
-
pnpm typecheck:review
|
|
205
|
-
pnpm review-kit:build
|
|
206
|
-
pnpm build:review
|
|
207
224
|
```
|
|
208
225
|
|
|
209
|
-
|
|
226
|
+
Open `http://127.0.0.1:5177/review/`.
|
|
227
|
+
|
|
228
|
+
Fixture pages:
|
|
229
|
+
|
|
230
|
+
- `/`: note, area, and DOM marker creation
|
|
231
|
+
- `/components/`: controls and panel spacing
|
|
232
|
+
- `/long-form/`: scroll and anchor restore
|
|
233
|
+
|
|
234
|
+
## Checks
|
|
235
|
+
|
|
236
|
+
Package repo:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
pnpm typecheck
|
|
240
|
+
pnpm build
|
|
241
|
+
pnpm typecheck:dev
|
|
242
|
+
pnpm build:dev
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Host repo:
|
|
210
246
|
|
|
211
|
-
|
|
247
|
+
```bash
|
|
248
|
+
pnpm typecheck
|
|
249
|
+
pnpm build
|
|
250
|
+
```
|
|
212
251
|
|
|
213
|
-
|
|
252
|
+
Manual smoke:
|
|
214
253
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- local item을 remote로 등록하면 local draft 삭제 확인
|
|
220
|
-
- remote source에서 status update/delete 확인
|
|
221
|
-
- `/review?source=supabase&target=...&item=...` restore 확인
|
|
222
|
-
- Supabase `reviewNumber`가 삭제 후 재사용되지 않는지 확인
|
|
254
|
+
1. Open `/review`.
|
|
255
|
+
2. Create local note, DOM marker, and area marker.
|
|
256
|
+
3. If Supabase is enabled, submit a local item to remote.
|
|
257
|
+
4. Confirm local draft removal, remote list display, status update, delete, and deep-link restore.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designfever/web-review-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Designfever web page review overlay toolkit.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -41,21 +41,26 @@
|
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsup src/index.ts src/react-shell.tsx --format esm,cjs --dts --sourcemap --clean --external react --external react-dom --external react/jsx-runtime",
|
|
43
43
|
"dev": "tsup src/index.ts src/react-shell.tsx --format esm,cjs --dts --sourcemap --watch --external react --external react-dom --external react/jsx-runtime",
|
|
44
|
+
"dev:review": "vite --config dev/vite.config.ts",
|
|
45
|
+
"build:dev": "vite build --config dev/vite.config.ts",
|
|
44
46
|
"prepare": "pnpm build",
|
|
45
|
-
"typecheck": "tsc --noEmit"
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"typecheck:dev": "tsc --noEmit -p tsconfig.dev.json"
|
|
46
49
|
},
|
|
47
50
|
"peerDependencies": {
|
|
48
51
|
"react": ">=18",
|
|
49
52
|
"react-dom": ">=18"
|
|
50
53
|
},
|
|
51
54
|
"devDependencies": {
|
|
55
|
+
"@supabase/supabase-js": "^2.108.2",
|
|
52
56
|
"@types/react": "^19.2.17",
|
|
53
57
|
"@types/react-dom": "^19.2.3",
|
|
54
58
|
"lucide-react": "^1.20.0",
|
|
55
59
|
"react": "^19.2.7",
|
|
56
60
|
"react-dom": "^19.2.7",
|
|
57
61
|
"tsup": "^8.3.6",
|
|
58
|
-
"typescript": "^6.0.2"
|
|
62
|
+
"typescript": "^6.0.2",
|
|
63
|
+
"vite": "^8.0.8"
|
|
59
64
|
},
|
|
60
65
|
"packageManager": "pnpm@9.0.0"
|
|
61
66
|
}
|