datewise/app/routes/webhooks.compliance.tsx
metatroncubeswdev e56182e0e3 chore: initial Datewise app (rebranded from SlotSure prototype)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:06:49 -04:00

41 lines
1.9 KiB
TypeScript

import { Prisma } from "@prisma/client";
import type { ActionFunctionArgs } from "react-router";
import prisma from "../db.server";
import { authenticate } from "../shopify.server";
/**
* Mandatory privacy webhooks.
* customers/data_request → we hold booking contact details; logged for the merchant to fulfil.
* customers/redact → anonymise that customer's bookings and waitlist entries.
* shop/redact → delete all shop data (48h after uninstall).
*/
export const action = async ({ request }: ActionFunctionArgs) => {
const { shop, topic, payload } = await authenticate.webhook(request);
const p = payload as { customer?: { email?: string; phone?: string }; orders_to_redact?: number[] };
const s = await prisma.shop.findUnique({ where: { domain: shop } });
if (!s) return new Response();
if (topic === "CUSTOMERS_DATA_REQUEST") {
const n = await prisma.booking.count({ where: { shopId: s.id, customerEmail: p.customer?.email ?? "__none__" } });
console.info(`data_request for ${shop}: ${n} bookings hold this customer's contact details`);
}
if (topic === "CUSTOMERS_REDACT") {
const orderIds = (p.orders_to_redact ?? []).map((id) => `gid://shopify/Order/${id}`);
const where = {
shopId: s.id,
OR: [{ orderId: { in: orderIds } }, ...(p.customer?.email ? [{ customerEmail: p.customer.email }] : [])],
};
await prisma.booking.updateMany({
where,
data: { customerName: null, customerEmail: null, customerPhone: null, address: Prisma.DbNull },
});
if (p.customer?.email || p.customer?.phone)
await prisma.waitlistEntry.deleteMany({ where: { shopId: s.id, OR: [{ email: p.customer?.email ?? "__" }, { phone: p.customer?.phone ?? "__" }] } });
}
if (topic === "SHOP_REDACT") {
await prisma.shop.delete({ where: { id: s.id } });
await prisma.session.deleteMany({ where: { shop } });
}
return new Response();
};