4687f46384
- Add app/ekonomi/anvandare/prenumerationer/butik/feedback blocks to computeOpsSummary. - New feedback table, POST /api/feedback, GDPR erasure wiring. - Canary: only count unverified/rejected published recipes; treat verified/editorial as safe. - Add 'rejected' recipe verification status enum value. - Fix food-safety lint baseline: remove egg/cured fish from raw-protein list, relax genomstekt regex, add safe-cooking phrases to seed recipes. - Seed recipes now get verificationStatus=editorial. - Tests: ops summary blocks, feedback route, me.residual cleanup.
49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
import type { FastifyInstance } from "fastify";
|
||
import { z } from "zod";
|
||
import { schema, trackProductAnalytics } from "@app/database";
|
||
import { feedbackSubmitted } from "@app/analytics";
|
||
import { errors, parse } from "../lib/errors.js";
|
||
|
||
const createFeedbackSchema = z.object({
|
||
typ: z.enum(["bug", "onskemal"]),
|
||
rubrik: z.string().min(1).max(200),
|
||
text: z.string().min(1).max(5000),
|
||
plattform: z.enum(["ios", "android", "web"]).optional(),
|
||
appVersion: z.string().max(32).optional(),
|
||
});
|
||
|
||
/**
|
||
* POST /api/feedback – användarfeedback (doc §2).
|
||
* Skapar en öppen ticket och spårar ett anonymiserat analytics-event.
|
||
* Själva text-kroppen visas aldrig i /ops/v1/summary.
|
||
*/
|
||
export async function feedbackRoutes(app: FastifyInstance) {
|
||
const auth = { preHandler: [app.authenticate] };
|
||
|
||
app.post("/api/feedback", auth, async (req) => {
|
||
const body = parse(createFeedbackSchema, req.body);
|
||
|
||
const [row] = await app.db
|
||
.insert(schema.feedback)
|
||
.values({
|
||
userId: req.userId,
|
||
typ: body.typ,
|
||
rubrik: body.rubrik,
|
||
text: body.text,
|
||
status: "oppen",
|
||
plattform: body.plattform ?? null,
|
||
appVersion: body.appVersion ?? null,
|
||
})
|
||
.returning();
|
||
|
||
if (!row) throw errors.internal("Kunde inte skapa feedback.");
|
||
|
||
await trackProductAnalytics(app.db, req.userId, {
|
||
...feedbackSubmitted(),
|
||
properties: { typ: body.typ },
|
||
});
|
||
|
||
return { id: row.id, status: row.status };
|
||
});
|
||
}
|