49 lines
2.0 KiB
SQL
49 lines
2.0 KiB
SQL
-- Visitor journey reconstruction. Two tables, two retention policies.
|
|
--
|
|
-- session_events: every analytics event the SvelteKit /api/track endpoint
|
|
-- receives, keyed by the anon_id cookie set in hooks.server.ts. This buffer
|
|
-- is the source for journey reconstruction when a visitor submits the
|
|
-- booking form. It is pruned aggressively (24h TTL) so we don't hoard
|
|
-- behavioural data for visitors who never enquire.
|
|
--
|
|
-- submission_journeys: when a visitor submits the booking/contact form,
|
|
-- /api/track/promote copies their recent session_events into this table
|
|
-- linked to the submission email. These rows are kept so the owner can
|
|
-- review the journey from the CP dashboard.
|
|
--
|
|
-- The promotion step is the only place where an anonymous browsing record
|
|
-- becomes linked to a named person, and it only happens because that
|
|
-- person chose to submit a form. The privacy policy covers this.
|
|
|
|
create table if not exists session_events (
|
|
id bigserial primary key,
|
|
anon_id text not null,
|
|
event_name text not null,
|
|
page_path text,
|
|
params jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index if not exists session_events_anon_idx
|
|
on session_events (anon_id, created_at);
|
|
|
|
-- Used by the probabilistic prune in /api/track to find rows past TTL.
|
|
create index if not exists session_events_created_idx
|
|
on session_events (created_at);
|
|
|
|
create table if not exists submission_journeys (
|
|
id bigserial primary key,
|
|
email text not null,
|
|
anon_id text,
|
|
-- Snapshot of session_events rows at promotion time (server-captured).
|
|
events jsonb not null default '[]'::jsonb,
|
|
-- Client-side sessionStorage buffer sent with the promote request, as a
|
|
-- fallback for events that never reached /api/track (e.g. blocked at the
|
|
-- network layer alongside gtag).
|
|
client_events jsonb not null default '[]'::jsonb,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index if not exists submission_journeys_email_idx
|
|
on submission_journeys (email, created_at desc);
|