jat-feedback 1.1.0 → 1.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 +153 -136
- package/dist/jat-feedback.js +25 -19
- package/dist/jat-feedback.mjs +2574 -2299
- package/package.json +3 -2
- package/supabase/functions/jat-webhook/index.ts +156 -0
- package/supabase/migrations/1.0.0_feedback_reports.sql +111 -0
package/README.md
CHANGED
|
@@ -11,25 +11,11 @@ User clicks "Report Bug" → Widget captures context → POST /api/feedback/repo
|
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
-
### Option 1: CDN (recommended)
|
|
15
|
-
|
|
16
|
-
```html
|
|
17
|
-
<script src="https://unpkg.com/jat-feedback@^1/dist/jat-feedback.js"></script>
|
|
18
|
-
<jat-feedback project="my-app"></jat-feedback>
|
|
19
|
-
<script>
|
|
20
|
-
document.querySelector('jat-feedback').setAttribute('endpoint', location.origin);
|
|
21
|
-
</script>
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Option 2: npm
|
|
25
|
-
|
|
26
14
|
```bash
|
|
27
15
|
npm install jat-feedback
|
|
28
16
|
```
|
|
29
17
|
|
|
30
|
-
|
|
31
|
-
import 'jat-feedback';
|
|
32
|
-
```
|
|
18
|
+
The package includes the widget bundle, Supabase migration, and edge function — all three are needed for the full pipeline.
|
|
33
19
|
|
|
34
20
|
## Widget Attributes
|
|
35
21
|
|
|
@@ -82,9 +68,32 @@ Full setup for any SvelteKit app with Supabase. Creates the feedback pipeline fr
|
|
|
82
68
|
|
|
83
69
|
### Step 1: Add Widget to app.html
|
|
84
70
|
|
|
71
|
+
The widget is a web component bundled at `dist/jat-feedback.js`. Use `vite-plugin-static-copy` to copy it into your build output, then load it from your own server.
|
|
72
|
+
|
|
73
|
+
**vite.config.ts:**
|
|
74
|
+
```typescript
|
|
75
|
+
import { sveltekit } from '@sveltejs/vite-plugin-svelte';
|
|
76
|
+
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
77
|
+
|
|
78
|
+
export default {
|
|
79
|
+
plugins: [
|
|
80
|
+
sveltekit(),
|
|
81
|
+
viteStaticCopy({
|
|
82
|
+
targets: [
|
|
83
|
+
{
|
|
84
|
+
src: 'node_modules/jat-feedback/dist/jat-feedback.js',
|
|
85
|
+
dest: '.'
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
})
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**src/app.html:**
|
|
85
94
|
```html
|
|
86
|
-
<!--
|
|
87
|
-
<script src="
|
|
95
|
+
<!-- before closing </body> tag -->
|
|
96
|
+
<script src="/jat-feedback.js"></script>
|
|
88
97
|
<jat-feedback project="YOUR_PROJECT"></jat-feedback>
|
|
89
98
|
<script>
|
|
90
99
|
(function() {
|
|
@@ -164,7 +173,6 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|
|
164
173
|
}
|
|
165
174
|
|
|
166
175
|
const reporter = body.metadata?.reporter || {};
|
|
167
|
-
const org = body.metadata?.organization || {};
|
|
168
176
|
|
|
169
177
|
const { data: row, error: insertError } = await supabase
|
|
170
178
|
.from('feedback_reports')
|
|
@@ -179,8 +187,6 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|
|
179
187
|
reporter_email: reporter.email || null,
|
|
180
188
|
reporter_name: reporter.name || null,
|
|
181
189
|
reporter_role: reporter.role || null,
|
|
182
|
-
organization_id: org.id || null,
|
|
183
|
-
organization_name: org.name || null,
|
|
184
190
|
console_logs: body.console_logs || null,
|
|
185
191
|
selected_elements: body.selected_elements || null,
|
|
186
192
|
screenshot_paths: screenshotPaths.length > 0 ? screenshotPaths : null,
|
|
@@ -208,104 +214,21 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|
|
208
214
|
};
|
|
209
215
|
```
|
|
210
216
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
### Step 3: Supabase Migration
|
|
214
|
-
|
|
215
|
-
Create a migration file (e.g., `supabase/migrations/YYYYMMDD000000_feedback_reports.sql`):
|
|
216
|
-
|
|
217
|
-
```sql
|
|
218
|
-
-- Feedback reports table for jat-feedback widget
|
|
219
|
-
-- Widget POSTs to /api/feedback/report → this table
|
|
220
|
-
-- JAT ingest daemon polls for jat_status = 'new'
|
|
221
|
-
|
|
222
|
-
CREATE TABLE IF NOT EXISTS feedback_reports (
|
|
223
|
-
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
224
|
-
title TEXT NOT NULL,
|
|
225
|
-
description TEXT DEFAULT '',
|
|
226
|
-
type TEXT DEFAULT 'bug' CHECK (type IN ('bug', 'enhancement', 'other')),
|
|
227
|
-
priority TEXT DEFAULT 'medium' CHECK (priority IN ('low', 'medium', 'high', 'critical')),
|
|
228
|
-
page_url TEXT,
|
|
229
|
-
user_agent TEXT,
|
|
230
|
-
|
|
231
|
-
-- Reporter identity
|
|
232
|
-
reporter_user_id UUID REFERENCES auth.users(id),
|
|
233
|
-
reporter_email TEXT,
|
|
234
|
-
reporter_name TEXT,
|
|
235
|
-
reporter_role TEXT,
|
|
236
|
-
|
|
237
|
-
-- Organization context (remove if not applicable)
|
|
238
|
-
organization_id UUID,
|
|
239
|
-
organization_name TEXT,
|
|
240
|
-
|
|
241
|
-
-- Structured data
|
|
242
|
-
console_logs JSONB,
|
|
243
|
-
selected_elements JSONB,
|
|
244
|
-
screenshot_paths TEXT[],
|
|
245
|
-
metadata JSONB,
|
|
246
|
-
|
|
247
|
-
-- JAT ingest tracking
|
|
248
|
-
jat_status TEXT DEFAULT 'new' CHECK (jat_status IN ('new', 'ingested', 'failed', 'rejected')),
|
|
249
|
-
jat_task_id TEXT,
|
|
250
|
-
|
|
251
|
-
-- User-facing status tracking
|
|
252
|
-
status TEXT DEFAULT 'submitted'
|
|
253
|
-
CHECK (status IN ('submitted', 'in_progress', 'completed', 'wontfix', 'closed')),
|
|
254
|
-
dev_notes TEXT,
|
|
255
|
-
user_response TEXT CHECK (user_response IN ('accepted', 'rejected')),
|
|
256
|
-
user_response_at TIMESTAMPTZ,
|
|
257
|
-
rejection_reason TEXT,
|
|
258
|
-
|
|
259
|
-
created_at TIMESTAMPTZ DEFAULT now()
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
-- Indexes
|
|
263
|
-
CREATE INDEX idx_feedback_reports_jat_status ON feedback_reports(jat_status) WHERE jat_status = 'new';
|
|
264
|
-
CREATE INDEX idx_feedback_reports_jat_rejected ON feedback_reports(jat_status) WHERE jat_status = 'rejected';
|
|
265
|
-
CREATE INDEX idx_feedback_reports_reporter ON feedback_reports(reporter_user_id, created_at DESC);
|
|
266
|
-
|
|
267
|
-
-- Storage bucket for screenshots
|
|
268
|
-
INSERT INTO storage.buckets (id, name, public) VALUES ('feedback-screenshots', 'feedback-screenshots', false)
|
|
269
|
-
ON CONFLICT (id) DO NOTHING;
|
|
270
|
-
|
|
271
|
-
-- RLS policies
|
|
272
|
-
ALTER TABLE feedback_reports ENABLE ROW LEVEL SECURITY;
|
|
273
|
-
|
|
274
|
-
CREATE POLICY "Authenticated users can insert feedback"
|
|
275
|
-
ON feedback_reports FOR INSERT TO authenticated
|
|
276
|
-
WITH CHECK (true);
|
|
277
|
-
|
|
278
|
-
CREATE POLICY "Users can read own feedback reports"
|
|
279
|
-
ON feedback_reports FOR SELECT TO authenticated
|
|
280
|
-
USING (reporter_user_id = auth.uid());
|
|
281
|
-
|
|
282
|
-
CREATE POLICY "Users can respond to own feedback"
|
|
283
|
-
ON feedback_reports FOR UPDATE TO authenticated
|
|
284
|
-
USING (reporter_user_id = auth.uid())
|
|
285
|
-
WITH CHECK (reporter_user_id = auth.uid());
|
|
286
|
-
|
|
287
|
-
CREATE POLICY "Service role full access to feedback"
|
|
288
|
-
ON feedback_reports FOR ALL TO service_role
|
|
289
|
-
USING (true) WITH CHECK (true);
|
|
290
|
-
|
|
291
|
-
-- Storage policies
|
|
292
|
-
CREATE POLICY "Authenticated users can upload feedback screenshots"
|
|
293
|
-
ON storage.objects FOR INSERT TO authenticated
|
|
294
|
-
WITH CHECK (bucket_id = 'feedback-screenshots');
|
|
295
|
-
|
|
296
|
-
CREATE POLICY "Service role can read feedback screenshots"
|
|
297
|
-
ON storage.objects FOR SELECT TO service_role
|
|
298
|
-
USING (bucket_id = 'feedback-screenshots');
|
|
299
|
-
```
|
|
217
|
+
### Step 3: Run the Supabase Migration
|
|
300
218
|
|
|
301
|
-
|
|
219
|
+
The `feedback_reports` table schema is included in this package. Copy it into your migrations folder and push:
|
|
302
220
|
|
|
303
221
|
```bash
|
|
222
|
+
# Copy the migration (rename to match your timestamp convention)
|
|
223
|
+
cp node_modules/jat-feedback/supabase/migrations/1.0.0_feedback_reports.sql \
|
|
224
|
+
supabase/migrations/$(date +%Y%m%d%H%M%S)_feedback_reports.sql
|
|
225
|
+
|
|
226
|
+
# Push to Supabase
|
|
304
227
|
supabase db push
|
|
305
|
-
# or
|
|
306
|
-
supabase migration up
|
|
307
228
|
```
|
|
308
229
|
|
|
230
|
+
**When upgrading jat-feedback:** check `node_modules/jat-feedback/supabase/migrations/` for new versioned files (e.g. `1.1.0_*.sql`) and copy+apply any you haven't run yet.
|
|
231
|
+
|
|
309
232
|
### Step 4: Wire User Context
|
|
310
233
|
|
|
311
234
|
In your authenticated layout, set widget attributes after login so reports include user identity.
|
|
@@ -323,8 +246,6 @@ onMount(() => {
|
|
|
323
246
|
// Adjust based on where your app stores display name:
|
|
324
247
|
if (user.user_metadata?.full_name) el.setAttribute('user-name', user.user_metadata.full_name);
|
|
325
248
|
if (user.user_metadata?.role) el.setAttribute('user-role', user.user_metadata.role);
|
|
326
|
-
// If your app has organizations:
|
|
327
|
-
// if (user.organization_id) el.setAttribute('org-id', user.organization_id);
|
|
328
249
|
}
|
|
329
250
|
}
|
|
330
251
|
});
|
|
@@ -372,12 +293,11 @@ Add this entry to the `sources` array.
|
|
|
372
293
|
"labels": ["widget", "feedback"]
|
|
373
294
|
},
|
|
374
295
|
"table": "feedback_reports",
|
|
375
|
-
"statusColumn": "
|
|
376
|
-
"statusNew": "
|
|
377
|
-
"statusDone": "ingested",
|
|
296
|
+
"statusColumn": "status",
|
|
297
|
+
"statusNew": "submitted",
|
|
378
298
|
"taskIdColumn": "jat_task_id",
|
|
379
299
|
"titleColumn": "title",
|
|
380
|
-
"descriptionTemplate": "**Reporter:** {reporter_name} ({reporter_email})\n**Page:** {page_url}\n**Browser:** {user_agent}\n\n{description}",
|
|
300
|
+
"descriptionTemplate": "**Reporter:** {reporter_name} ({reporter_email}) — {reporter_role}\n**Page:** {page_url}\n**Browser:** {user_agent}\n\n{description}",
|
|
381
301
|
"authorColumn": "reporter_email",
|
|
382
302
|
"timestampColumn": "created_at",
|
|
383
303
|
"attachmentColumn": "screenshot_paths",
|
|
@@ -404,12 +324,11 @@ Add this entry to the `sources` array.
|
|
|
404
324
|
"projectUrl": "https://YOUR_SUPABASE_PROJECT_ID.supabase.co",
|
|
405
325
|
"secretName": "YOUR_PROJECT-supabase-service-role",
|
|
406
326
|
"table": "feedback_reports",
|
|
407
|
-
"statusColumn": "
|
|
408
|
-
"statusNew": "
|
|
409
|
-
"statusDone": "ingested",
|
|
327
|
+
"statusColumn": "status",
|
|
328
|
+
"statusNew": "submitted",
|
|
410
329
|
"taskIdColumn": "jat_task_id",
|
|
411
330
|
"titleColumn": "title",
|
|
412
|
-
"descriptionTemplate": "**Reporter:** {reporter_name} ({reporter_email})\n**Page:** {page_url}\n**Browser:** {user_agent}\n\n{description}",
|
|
331
|
+
"descriptionTemplate": "**Reporter:** {reporter_name} ({reporter_email}) — {reporter_role}\n**Page:** {page_url}\n**Browser:** {user_agent}\n\n{description}",
|
|
413
332
|
"authorColumn": "reporter_email",
|
|
414
333
|
"timestampColumn": "created_at",
|
|
415
334
|
"attachmentColumn": "screenshot_paths",
|
|
@@ -437,16 +356,53 @@ Add this entry to the `sources` array.
|
|
|
437
356
|
},
|
|
438
357
|
"referenceTable": "feedback_reports",
|
|
439
358
|
"referenceIdFrom": "item_id"
|
|
440
|
-
}
|
|
359
|
+
},
|
|
360
|
+
"actions": [
|
|
361
|
+
{
|
|
362
|
+
"id": "sync_status",
|
|
363
|
+
"label": "Sync Status",
|
|
364
|
+
"description": "Push current task status to Supabase",
|
|
365
|
+
"type": "callback",
|
|
366
|
+
"event": "status_changed",
|
|
367
|
+
"icon": "refresh"
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"id": "open_record",
|
|
371
|
+
"label": "View in Supabase",
|
|
372
|
+
"description": "Open the original feedback report in Supabase dashboard",
|
|
373
|
+
"type": "link",
|
|
374
|
+
"urlTemplate": "{projectUrl}/project/default/editor/feedback_reports?filter=id%3Deq.{referenceId}",
|
|
375
|
+
"icon": "external-link"
|
|
376
|
+
}
|
|
377
|
+
]
|
|
441
378
|
}
|
|
442
379
|
```
|
|
443
380
|
|
|
444
381
|
- **automation**: Auto-spawn an agent when a report is ingested
|
|
445
|
-
- **callback**: Push JAT task status changes back to Supabase
|
|
382
|
+
- **callback**: Push JAT task status changes back to Supabase — requires deploying the `jat-webhook` edge function (see Step 6)
|
|
383
|
+
- **actions**: Adds "Sync Status" and "View in Supabase" buttons in the JAT IDE task panel
|
|
446
384
|
|
|
447
385
|
The ingest daemon picks up config changes automatically (no restart needed).
|
|
448
386
|
|
|
449
|
-
### Step 6:
|
|
387
|
+
### Step 6: Deploy the JAT Webhook Edge Function (for callbacks)
|
|
388
|
+
|
|
389
|
+
The `jat-webhook` Supabase Edge Function receives status-change callbacks from JAT and updates your `feedback_reports` rows. It's included in this package — copy it into your project and deploy it.
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# Copy the function into your project
|
|
393
|
+
mkdir -p supabase/functions/jat-webhook
|
|
394
|
+
cp node_modules/jat-feedback/supabase/functions/jat-webhook/index.ts \
|
|
395
|
+
supabase/functions/jat-webhook/index.ts
|
|
396
|
+
|
|
397
|
+
# Deploy to Supabase
|
|
398
|
+
supabase functions deploy jat-webhook
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
The function uses `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` — both are injected automatically by Supabase, no extra configuration needed.
|
|
402
|
+
|
|
403
|
+
**Skip this step** if you don't need bidirectional status sync (i.e., you only want JAT to ingest reports, not push status back to Supabase).
|
|
404
|
+
|
|
405
|
+
### Step 7: Verify
|
|
450
406
|
|
|
451
407
|
```bash
|
|
452
408
|
# Check the API endpoint is working
|
|
@@ -471,14 +427,14 @@ jat ingest status
|
|
|
471
427
|
│ jat-feedback │────►│ Your App │────►│ Supabase │────►│ JAT Ingest │
|
|
472
428
|
│ (widget) │ │ /api/report │ │ feedback_ │ │ Daemon │
|
|
473
429
|
│ │ │ │ │ reports │ │ │
|
|
474
|
-
└──────────────┘ └──────────────┘
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
430
|
+
└──────────────┘ └──────────────┘ └──────┬───────┘ └──────┬───────┘
|
|
431
|
+
▲ │
|
|
432
|
+
│ ▼
|
|
433
|
+
┌──────┴───────┐ ┌──────────────┐
|
|
434
|
+
│ jat-webhook │◄──│ JAT Task │
|
|
435
|
+
│ (edge fn) │ │ status │
|
|
436
|
+
│ status sync │ │ changes │
|
|
437
|
+
└──────────────┘ └──────────────┘
|
|
482
438
|
```
|
|
483
439
|
|
|
484
440
|
## Column Reference
|
|
@@ -487,11 +443,72 @@ The `feedback_reports` table columns used by the pipeline:
|
|
|
487
443
|
|
|
488
444
|
| Column | Type | Purpose |
|
|
489
445
|
|--------|------|---------|
|
|
490
|
-
| `
|
|
446
|
+
| `status` | TEXT | Lifecycle: `submitted` → `in_progress` → `completed` → `accepted` \| `rejected` |
|
|
491
447
|
| `jat_task_id` | TEXT | JAT task ID written back after ingest (e.g., `myapp-abc`) |
|
|
492
|
-
| `
|
|
448
|
+
| `rejection_reason` | TEXT | User-provided reason when rejecting a completed report |
|
|
493
449
|
| `dev_notes` | TEXT | Developer notes pushed back via callback |
|
|
494
|
-
|
|
450
|
+
|
|
451
|
+
## Upgrading
|
|
452
|
+
|
|
453
|
+
npm never auto-updates — you need to explicitly upgrade and then handle each type of change manually.
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# 1. Update the package
|
|
457
|
+
npm install jat-feedback@latest
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Then handle whatever changed in the release notes:
|
|
461
|
+
|
|
462
|
+
**Widget JS changes** (UI, behavior, new attributes):
|
|
463
|
+
```bash
|
|
464
|
+
# Nothing extra — the updated bundle is copied to your build output automatically
|
|
465
|
+
# Just redeploy your app
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Schema changes** (new columns, indexes):
|
|
469
|
+
```bash
|
|
470
|
+
# Check for new migration files
|
|
471
|
+
ls node_modules/jat-feedback/supabase/migrations/
|
|
472
|
+
|
|
473
|
+
# Copy any new ones into your project and run them
|
|
474
|
+
cp node_modules/jat-feedback/supabase/migrations/1.1.0_*.sql \
|
|
475
|
+
supabase/migrations/$(date +%Y%m%d%H%M%S)_feedback_1_1_0.sql
|
|
476
|
+
|
|
477
|
+
supabase db push
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Edge function changes** (webhook behavior):
|
|
481
|
+
```bash
|
|
482
|
+
# Re-copy and redeploy
|
|
483
|
+
cp node_modules/jat-feedback/supabase/functions/jat-webhook/index.ts \
|
|
484
|
+
supabase/functions/jat-webhook/index.ts
|
|
485
|
+
|
|
486
|
+
supabase functions deploy jat-webhook
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Versioning
|
|
490
|
+
|
|
491
|
+
This package follows semver. The `^` range in consuming projects (`"jat-feedback": "^1.1.0"`) means:
|
|
492
|
+
|
|
493
|
+
- **Patch and minor** (1.1.x, 1.2.0) — auto-accepted by `npm install`
|
|
494
|
+
- **Major** (2.0.0) — requires manual version bump in `package.json`
|
|
495
|
+
|
|
496
|
+
### What triggers a major version
|
|
497
|
+
|
|
498
|
+
| Change | Version |
|
|
499
|
+
|--------|---------|
|
|
500
|
+
| New nullable column (additive) | patch/minor |
|
|
501
|
+
| New widget attribute (optional) | minor |
|
|
502
|
+
| Removing or renaming a column | **major** |
|
|
503
|
+
| Changing a column's type | **major** |
|
|
504
|
+
| Renaming `status` values (e.g. `submitted` → `new`) | **major** |
|
|
505
|
+
| Required integrations.json config field added/renamed | **major** |
|
|
506
|
+
|
|
507
|
+
### Rule for additive schema changes
|
|
508
|
+
|
|
509
|
+
Any column added in a `1.x` release **must** be nullable with no required default. This ensures consuming projects don't break even if they haven't run the migration yet — the insert just omits the column and it lands as `NULL`.
|
|
510
|
+
|
|
511
|
+
If a new column is required (non-nullable, no default), that's a breaking change and belongs in a major version.
|
|
495
512
|
|
|
496
513
|
## License
|
|
497
514
|
|