112 lines
4.6 KiB
SQL
112 lines
4.6 KiB
SQL
-- Unified immutable abuse-report submissions. Operational delivery/read/music
|
|
-- telemetry and auth-code delivery diagnostics intentionally use separate
|
|
-- tables and retention policies.
|
|
CREATE TABLE public.moderation_reports (
|
|
id bigserial PRIMARY KEY,
|
|
reporter_user_id bigint NOT NULL CHECK (reporter_user_id > 0),
|
|
source text NOT NULL CHECK (source IN (
|
|
'account_peer', 'profile_photo', 'messages_spam', 'messages',
|
|
'encrypted_spam', 'reaction', 'channel_spam', 'story', 'ephemeral',
|
|
'sponsored', 'antispam_false_positive'
|
|
)),
|
|
target_peer_type text NOT NULL CHECK (target_peer_type IN ('user', 'channel')),
|
|
target_peer_id bigint NOT NULL CHECK (target_peer_id > 0),
|
|
reason text NOT NULL CHECK (reason IN (
|
|
'spam', 'violence', 'pornography', 'child_abuse', 'other',
|
|
'copyright', 'geo_irrelevant', 'fake', 'illegal_drugs',
|
|
'personal_details'
|
|
)),
|
|
report_option text NOT NULL CHECK (
|
|
octet_length(report_option) BETWEEN 1 AND 32
|
|
),
|
|
report_comment text NOT NULL DEFAULT '' CHECK (
|
|
char_length(report_comment) <= 512
|
|
),
|
|
comment_hash bytea NOT NULL CHECK (octet_length(comment_hash) = 32),
|
|
fingerprint bytea NOT NULL CHECK (octet_length(fingerprint) = 32),
|
|
taxonomy_version smallint NOT NULL CHECK (taxonomy_version > 0),
|
|
created_at timestamptz NOT NULL,
|
|
CONSTRAINT moderation_reports_idempotency
|
|
UNIQUE (reporter_user_id, fingerprint)
|
|
);
|
|
|
|
CREATE INDEX moderation_reports_target_created_idx
|
|
ON public.moderation_reports (
|
|
target_peer_type, target_peer_id, created_at DESC, id DESC
|
|
);
|
|
|
|
CREATE INDEX moderation_reports_reporter_created_idx
|
|
ON public.moderation_reports (
|
|
reporter_user_id, created_at DESC, id DESC
|
|
);
|
|
|
|
CREATE TABLE public.moderation_report_items (
|
|
report_id bigint NOT NULL REFERENCES public.moderation_reports(id)
|
|
ON DELETE CASCADE,
|
|
ordinal smallint NOT NULL CHECK (ordinal BETWEEN 0 AND 99),
|
|
item_kind text NOT NULL CHECK (item_kind IN (
|
|
'peer', 'message', 'profile_photo', 'reaction', 'story',
|
|
'encrypted_chat', 'ephemeral', 'sponsored', 'antispam_decision'
|
|
)),
|
|
peer_type text NOT NULL CHECK (peer_type IN ('user', 'channel')),
|
|
peer_id bigint NOT NULL CHECK (peer_id > 0),
|
|
item_id bigint NOT NULL CHECK (item_id > 0),
|
|
secondary_id bigint NOT NULL DEFAULT 0 CHECK (secondary_id >= 0),
|
|
author_user_id bigint NOT NULL DEFAULT 0 CHECK (author_user_id >= 0),
|
|
evidence_schema_version smallint NOT NULL CHECK (
|
|
evidence_schema_version > 0
|
|
),
|
|
evidence jsonb NOT NULL CHECK (
|
|
jsonb_typeof(evidence) = 'object'
|
|
AND octet_length(evidence::text) <= 1048576
|
|
),
|
|
evidence_hash bytea NOT NULL CHECK (octet_length(evidence_hash) = 32),
|
|
PRIMARY KEY (report_id, ordinal),
|
|
CONSTRAINT moderation_report_items_identity
|
|
UNIQUE (
|
|
report_id, item_kind, peer_type, peer_id, item_id, secondary_id
|
|
)
|
|
);
|
|
|
|
CREATE INDEX moderation_report_items_lookup_idx
|
|
ON public.moderation_report_items (
|
|
item_kind, peer_type, peer_id, item_id, report_id
|
|
);
|
|
|
|
CREATE INDEX moderation_report_items_author_idx
|
|
ON public.moderation_report_items (
|
|
author_user_id, report_id
|
|
)
|
|
WHERE author_user_id > 0;
|
|
|
|
CREATE TABLE public.moderation_media_holds (
|
|
report_id bigint NOT NULL,
|
|
item_ordinal smallint NOT NULL,
|
|
media_kind text NOT NULL CHECK (media_kind IN ('photo', 'document', 'blob')),
|
|
storage_key text NOT NULL CHECK (
|
|
octet_length(storage_key) BETWEEN 1 AND 512
|
|
),
|
|
created_at timestamptz NOT NULL,
|
|
released_at timestamptz,
|
|
PRIMARY KEY (report_id, item_ordinal, media_kind, storage_key),
|
|
FOREIGN KEY (report_id, item_ordinal)
|
|
REFERENCES public.moderation_report_items(report_id, ordinal)
|
|
ON DELETE CASCADE,
|
|
CHECK (released_at IS NULL OR released_at >= created_at)
|
|
);
|
|
|
|
CREATE INDEX moderation_media_holds_active_key_idx
|
|
ON public.moderation_media_holds (media_kind, storage_key, report_id)
|
|
WHERE released_at IS NULL;
|
|
|
|
-- Crash-safe, one-way provenance for rows written by the pre-unified
|
|
-- ephemeral.reportMessage implementation. The legacy table remains immutable
|
|
-- until every deployed database has completed the application-level evidence
|
|
-- conversion; all new writes go exclusively to moderation_reports.
|
|
CREATE TABLE public.moderation_legacy_ephemeral_migrations (
|
|
legacy_report_id bigint PRIMARY KEY
|
|
REFERENCES public.ephemeral_abuse_reports(id) ON DELETE RESTRICT,
|
|
moderation_report_id bigint NOT NULL
|
|
REFERENCES public.moderation_reports(id) ON DELETE RESTRICT,
|
|
migrated_at timestamptz NOT NULL
|
|
);
|