Files

94 lines
2.8 KiB
TypeScript

import type { CollectionConfig } from "payload";
import { canViewAnalytics } from "@/access";
/**
* One row per tracked event (page_view, booking_started, ...). Deliberately
* append-only and never writable via the public/admin API - the only writer
* is app/(payload)/api/analytics/track/route.ts, which uses the trusted
* Local API (overrideAccess: true by default) to insert rows despite
* `create` being locked to `() => false` here. The only deleter is the
* cleanup cron (lib/analytics/cleanup.ts), same mechanism.
*
* No name/email/IP/UA is ever stored - see lib/analytics/salt.ts for how
* `visitorHash` is derived without persisting anything identifying.
*/
export const AnalyticsEvents: CollectionConfig = {
slug: "analytics-events",
labels: {
singular: "Messereignis",
plural: "Messereignisse",
},
admin: {
group: "Auswertung",
hidden: true,
// High-volume, low-signal raw data - not meant for manual browsing.
// The Analytics dashboard (a custom admin view) reads it programmatically.
},
access: {
create: () => false,
read: canViewAnalytics,
update: () => false,
delete: () => false,
},
timestamps: true,
indexes: [{ fields: ["visitorHash", "createdAt"] }, { fields: ["createdAt"] }],
fields: [
{
name: "sessionId",
type: "text",
required: true,
index: true,
},
{
name: "visitorHash",
type: "text",
required: true,
// Daily-rotating pseudonymous hash (see lib/analytics/salt.ts) - never
// a raw IP/UA, never stable across days, never exposed to the client.
},
{
name: "path",
type: "text",
required: true,
index: true,
},
{
name: "eventName",
type: "text",
required: true,
index: true,
// Deliberately free-text, not a select/enum: new event names (see
// lib/analytics/events.ts) never require a schema migration.
defaultValue: "page_view",
},
{
name: "referrerHost",
type: "text",
// Hostname only (never a full URL/query string). document.referrer is
// fixed for a tab's whole lifetime (it doesn't change on client-side
// route transitions), so this naturally reflects how the visitor
// originally arrived, sent unchanged with every event in the session.
},
{
name: "device",
type: "select",
options: [
{ label: "Mobile", value: "mobile" },
{ label: "Desktop", value: "desktop" },
{ label: "Tablet", value: "tablet" },
],
},
{
name: "browser",
type: "select",
options: [
{ label: "Chrome", value: "chrome" },
{ label: "Firefox", value: "firefox" },
{ label: "Safari", value: "safari" },
{ label: "Edge", value: "edge" },
{ label: "Sonstige", value: "other" },
],
},
],
};