add search, chat, and feedback analytics with dashboard

This commit is contained in:
miloschwartz
2026-09-28 14:03:29 -04:00
parent 9d1b9f3820
commit 6588fc870b
42 changed files with 5932 additions and 108 deletions
+20
View File
@@ -0,0 +1,20 @@
import { parseId, parseVote, recordMessageVote } from '@/lib/analytics/api';
import { json, readFeedback, storageError } from '@/lib/analytics/http';
/** `{ messageId, vote: 1 | -1 | 0, visitorId }` for an assistant response */
export async function POST(req: Request) {
const body = await readFeedback(req);
if (body instanceof Response) return body;
const messageId = parseId(body.messageId);
const vote = parseVote(body.vote);
if (!messageId || vote === null) return json(400, { error: 'Invalid feedback.' });
try {
const found = await recordMessageVote(messageId, parseId(body.visitorId), vote);
if (!found) return json(404, { error: 'Unknown message.' });
} catch (e) {
return storageError('message vote', e);
}
return json(200, { ok: true });
}
+24
View File
@@ -0,0 +1,24 @@
import { source } from '@/lib/source';
import { parseId, parseVote, recordPageVote } from '@/lib/analytics/api';
import { json, readFeedback, storageError } from '@/lib/analytics/http';
/** `{ page: '/some/path', vote: 1 | -1 | 0, visitorId }`; `0` removes the vote */
export async function POST(req: Request) {
const body = await readFeedback(req);
if (body instanceof Response) return body;
const visitorId = parseId(body.visitorId);
const vote = parseVote(body.vote);
const page = typeof body.page === 'string' ? body.page : '';
const slugs = page.split('/').filter(Boolean);
if (!visitorId || vote === null || !page.startsWith('/') || !source.getPage(slugs)) {
return json(400, { error: 'Invalid feedback.' });
}
try {
await recordPageVote(source.getPage(slugs)!.url, visitorId, vote);
} catch (e) {
return storageError('page vote', e);
}
return json(200, { ok: true });
}