docs: reorder & testing
This commit is contained in:
@@ -31,13 +31,14 @@ CREATE INDEX device_sessions_user_idx ON device_sessions (user_id);
|
||||
CREATE INDEX device_sessions_status_idx ON device_sessions (status);
|
||||
|
||||
CREATE TABLE auth_challenges (
|
||||
challenge_id uuid PRIMARY KEY,
|
||||
email text NOT NULL,
|
||||
code_hash bytea NOT NULL,
|
||||
attempts integer NOT NULL DEFAULT 0,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz NOT NULL,
|
||||
consumed_at timestamptz
|
||||
challenge_id uuid PRIMARY KEY,
|
||||
email text NOT NULL,
|
||||
code_hash bytea NOT NULL,
|
||||
attempts integer NOT NULL DEFAULT 0,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz NOT NULL,
|
||||
consumed_at timestamptz,
|
||||
preferred_language text NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE INDEX auth_challenges_email_idx ON auth_challenges (email);
|
||||
@@ -48,6 +49,30 @@ CREATE TABLE blocked_emails (
|
||||
blocked_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- session_revocations is the durable audit trail of every device-session
|
||||
-- revocation. Each revoke writes one row carrying the actor kind, actor
|
||||
-- id, and free-form reason. The table is append-only; reading it is the
|
||||
-- only way to answer "who and why revoked this session". The
|
||||
-- device_session_id column is not a foreign key because device_sessions
|
||||
-- rows survive after revoke (status='revoked'), and dropping a session
|
||||
-- through a future cleanup must not implicitly drop its audit history.
|
||||
CREATE TABLE session_revocations (
|
||||
revocation_id uuid PRIMARY KEY,
|
||||
device_session_id uuid NOT NULL,
|
||||
user_id uuid NOT NULL,
|
||||
actor_kind text NOT NULL,
|
||||
actor_user_id uuid,
|
||||
actor_username text,
|
||||
reason text NOT NULL DEFAULT '',
|
||||
revoked_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT session_revocations_actor_chk
|
||||
CHECK (actor_user_id IS NULL OR actor_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE INDEX session_revocations_user_idx ON session_revocations (user_id, revoked_at DESC);
|
||||
CREATE INDEX session_revocations_device_idx ON session_revocations (device_session_id, revoked_at DESC);
|
||||
CREATE INDEX session_revocations_actor_kind_idx ON session_revocations (actor_kind, revoked_at DESC);
|
||||
|
||||
-- =====================================================================
|
||||
-- User domain
|
||||
-- =====================================================================
|
||||
@@ -64,14 +89,17 @@ CREATE TABLE accounts (
|
||||
preferred_language text NOT NULL,
|
||||
time_zone text NOT NULL,
|
||||
declared_country text,
|
||||
permanent_block boolean NOT NULL DEFAULT false,
|
||||
deleted_actor_type text,
|
||||
deleted_actor_id text,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
deleted_at timestamptz,
|
||||
permanent_block boolean NOT NULL DEFAULT false,
|
||||
deleted_actor_type text,
|
||||
deleted_actor_user_id uuid,
|
||||
deleted_actor_username text,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
deleted_at timestamptz,
|
||||
CONSTRAINT accounts_email_unique UNIQUE (email),
|
||||
CONSTRAINT accounts_user_name_unique UNIQUE (user_name)
|
||||
CONSTRAINT accounts_user_name_unique UNIQUE (user_name),
|
||||
CONSTRAINT accounts_deleted_actor_chk
|
||||
CHECK (deleted_actor_user_id IS NULL OR deleted_actor_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE INDEX accounts_listing_idx
|
||||
@@ -88,19 +116,22 @@ CREATE INDEX accounts_declared_country_idx
|
||||
-- shape used by sanction_records/limit_records: the *_active rollup carries
|
||||
-- only the binding, the records table is the durable audit log.
|
||||
CREATE TABLE entitlement_records (
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
tier text NOT NULL,
|
||||
is_paid boolean NOT NULL,
|
||||
source text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_id text,
|
||||
reason_code text NOT NULL DEFAULT '',
|
||||
starts_at timestamptz NOT NULL DEFAULT now(),
|
||||
ends_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
tier text NOT NULL,
|
||||
is_paid boolean NOT NULL,
|
||||
source text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_user_id uuid,
|
||||
actor_username text,
|
||||
reason_code text NOT NULL DEFAULT '',
|
||||
starts_at timestamptz NOT NULL DEFAULT now(),
|
||||
ends_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT entitlement_records_tier_chk
|
||||
CHECK (tier IN ('free', 'monthly', 'yearly', 'permanent'))
|
||||
CHECK (tier IN ('free', 'monthly', 'yearly', 'permanent')),
|
||||
CONSTRAINT entitlement_records_actor_chk
|
||||
CHECK (actor_user_id IS NULL OR actor_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE INDEX entitlement_records_user_idx
|
||||
@@ -117,32 +148,41 @@ CREATE TABLE entitlement_snapshots (
|
||||
is_paid boolean NOT NULL,
|
||||
source text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_id text,
|
||||
actor_user_id uuid,
|
||||
actor_username text,
|
||||
reason_code text NOT NULL DEFAULT '',
|
||||
starts_at timestamptz NOT NULL,
|
||||
ends_at timestamptz,
|
||||
max_registered_race_names integer NOT NULL,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT entitlement_snapshots_tier_chk
|
||||
CHECK (tier IN ('free', 'monthly', 'yearly', 'permanent'))
|
||||
CHECK (tier IN ('free', 'monthly', 'yearly', 'permanent')),
|
||||
CONSTRAINT entitlement_snapshots_actor_chk
|
||||
CHECK (actor_user_id IS NULL OR actor_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE TABLE sanction_records (
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
sanction_code text NOT NULL,
|
||||
scope text NOT NULL,
|
||||
reason_code text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_id text,
|
||||
applied_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz,
|
||||
removed_at timestamptz,
|
||||
removed_by_type text,
|
||||
removed_by_id text,
|
||||
removed_reason_code text,
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
sanction_code text NOT NULL,
|
||||
scope text NOT NULL,
|
||||
reason_code text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_user_id uuid,
|
||||
actor_username text,
|
||||
applied_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz,
|
||||
removed_at timestamptz,
|
||||
removed_by_type text,
|
||||
removed_by_user_id uuid,
|
||||
removed_by_username text,
|
||||
removed_reason_code text,
|
||||
CONSTRAINT sanction_records_code_chk
|
||||
CHECK (sanction_code IN ('permanent_block'))
|
||||
CHECK (sanction_code IN ('permanent_block')),
|
||||
CONSTRAINT sanction_records_actor_chk
|
||||
CHECK (actor_user_id IS NULL OR actor_username IS NULL),
|
||||
CONSTRAINT sanction_records_removed_by_chk
|
||||
CHECK (removed_by_user_id IS NULL OR removed_by_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE INDEX sanction_records_user_idx
|
||||
@@ -161,19 +201,25 @@ CREATE TABLE sanction_active (
|
||||
CREATE INDEX sanction_active_code_idx ON sanction_active (sanction_code);
|
||||
|
||||
CREATE TABLE limit_records (
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
limit_code text NOT NULL,
|
||||
value integer NOT NULL,
|
||||
reason_code text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_id text,
|
||||
applied_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz,
|
||||
removed_at timestamptz,
|
||||
removed_by_type text,
|
||||
removed_by_id text,
|
||||
removed_reason_code text
|
||||
record_id uuid PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES accounts (user_id),
|
||||
limit_code text NOT NULL,
|
||||
value integer NOT NULL,
|
||||
reason_code text NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
actor_user_id uuid,
|
||||
actor_username text,
|
||||
applied_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz,
|
||||
removed_at timestamptz,
|
||||
removed_by_type text,
|
||||
removed_by_user_id uuid,
|
||||
removed_by_username text,
|
||||
removed_reason_code text,
|
||||
CONSTRAINT limit_records_actor_chk
|
||||
CHECK (actor_user_id IS NULL OR actor_username IS NULL),
|
||||
CONSTRAINT limit_records_removed_by_chk
|
||||
CHECK (removed_by_user_id IS NULL OR removed_by_username IS NULL)
|
||||
);
|
||||
|
||||
CREATE INDEX limit_records_user_idx
|
||||
|
||||
Reference in New Issue
Block a user