feat(consent): user_terms_consents + /v1/me/consent

This commit is contained in:
Sven (AAMOS AI)
2026-08-13 02:06:44 +07:00
parent 1df3ca1709
commit 61c3193f17
8 changed files with 10534 additions and 1 deletions
+35 -1
View File
@@ -1,5 +1,5 @@
import type { FastifyInstance } from "fastify";
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
import { buildErasurePlan, eraseUser, schema } from "@app/database";
import {
consentInputSchema,
@@ -8,6 +8,7 @@ import {
updateMeInputSchema,
updatePreferencesInputSchema,
} from "@app/validation";
import { TERMS_VERSION } from "@app/shared-types";
import { computeDailyTargets, DEFAULT_TARGETS } from "@app/nutrition-engine";
import { errors, parse } from "../lib/errors.js";
import { audit, generateInviteCode, getActiveHouseholdId } from "../lib/helpers.js";
@@ -166,6 +167,39 @@ export async function meRoutes(app: FastifyInstance) {
return { ok: true, householdId };
});
// --- Villkorssamtycke (terms) ---
app.post("/v1/me/consent", auth, async (req) => {
const now = new Date();
const [row] = await app.db
.insert(schema.userTermsConsents)
.values({ userId: req.userId, termsVersion: TERMS_VERSION, acceptedAt: now })
.onConflictDoNothing({ target: [schema.userTermsConsents.userId, schema.userTermsConsents.termsVersion] })
.returning();
return {
accepted: true,
version: TERMS_VERSION,
acceptedAt: row?.acceptedAt ?? now,
};
});
app.get("/v1/me/consent", auth, async (req) => {
const [row] = await app.db
.select()
.from(schema.userTermsConsents)
.where(
and(
eq(schema.userTermsConsents.userId, req.userId),
eq(schema.userTermsConsents.termsVersion, TERMS_VERSION),
),
)
.limit(1);
return {
accepted: row != null,
version: TERMS_VERSION,
acceptedAt: row?.acceptedAt ?? null,
};
});
// --- Samtycken (spec §33: separata) ---
app.get("/v1/me/consents", auth, async (req) => {
return app.db