Phase 1 ops core: base blocks, feedback, canary fixes
- 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.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
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 };
|
||||
});
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import { analyticsRoutes } from "./routes/analytics.js";
|
||||
import { onboardingRoutes } from "./routes/onboarding.js";
|
||||
import { activationRoutes } from "./routes/activation.js";
|
||||
import { opsRoutes } from "./routes/ops.js";
|
||||
import { feedbackRoutes } from "./routes/feedback.js";
|
||||
|
||||
declare module "fastify" {
|
||||
interface FastifyInstance {
|
||||
@@ -100,6 +101,7 @@ export async function buildServer(config: AppConfig) {
|
||||
await app.register(onboardingRoutes);
|
||||
await app.register(activationRoutes);
|
||||
await app.register(opsRoutes);
|
||||
await app.register(feedbackRoutes);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user