710ab06333
Additive/expand-contract: new append-only retained_identities table (the legal dossier of every detached credential, keyed by account_id, TTL'd by detached_at) plus nullable accounts columns last_login_at/last_login_ip (cold-load stamp) and deleted_at/deleted_display_name (tombstone + retained real name). Regenerates the go-jet models for accounts + retained_identities only.
48 lines
2.2 KiB
SQL
48 lines
2.2 KiB
SQL
-- Account deletion as legal retention (not erasure). Two additive pieces.
|
|
--
|
|
-- retained_identities is an append-only journal of every credential detached from an
|
|
-- account — on unlink, email change, or account deletion (reason). It preserves the legal
|
|
-- dossier (which email/vk/tg was linked, and when) while the live identities row is
|
|
-- removed, so the (kind, external_id) frees for a new account to reuse. No unique
|
|
-- constraint and no kind CHECK: the same credential may recur across accounts and events,
|
|
-- and the log stays robust to future identity kinds. detached_at drives the retention TTL.
|
|
--
|
|
-- accounts gains: last_login_at / last_login_ip (stamped on a cold app-load, throttled),
|
|
-- deleted_at (the tombstone marker), and deleted_display_name (the real name retained for
|
|
-- the admin dossier after the live display_name is scrubbed to the anonymised label).
|
|
--
|
|
-- Expand-contract: everything is additive (a new table plus nullable columns), so a
|
|
-- backend image rollback stays DB-safe — older code simply ignores them. The accounts
|
|
-- table shape changes, so its generated go-jet model is regenerated.
|
|
|
|
-- +goose Up
|
|
CREATE TABLE backend.retained_identities (
|
|
retained_id uuid NOT NULL,
|
|
account_id uuid NOT NULL,
|
|
kind text NOT NULL,
|
|
external_id text NOT NULL,
|
|
confirmed boolean DEFAULT false NOT NULL,
|
|
linked_at timestamp with time zone NOT NULL,
|
|
detached_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
reason text NOT NULL,
|
|
CONSTRAINT retained_identities_pkey PRIMARY KEY (retained_id),
|
|
CONSTRAINT retained_identities_reason_chk
|
|
CHECK ((reason = ANY (ARRAY['unlink'::text, 'change'::text, 'delete'::text])))
|
|
);
|
|
CREATE INDEX retained_identities_account_id_idx ON backend.retained_identities (account_id);
|
|
CREATE INDEX retained_identities_detached_at_idx ON backend.retained_identities (detached_at);
|
|
|
|
ALTER TABLE backend.accounts
|
|
ADD COLUMN last_login_at timestamp with time zone,
|
|
ADD COLUMN last_login_ip text,
|
|
ADD COLUMN deleted_at timestamp with time zone,
|
|
ADD COLUMN deleted_display_name text;
|
|
|
|
-- +goose Down
|
|
ALTER TABLE backend.accounts
|
|
DROP COLUMN last_login_at,
|
|
DROP COLUMN last_login_ip,
|
|
DROP COLUMN deleted_at,
|
|
DROP COLUMN deleted_display_name;
|
|
DROP TABLE backend.retained_identities;
|