-- Stickers in chat. -- -- A sticker IS a sādhana reward — same catalog, same artwork — so there is no -- separate sticker table. What's new is a second way to come by one: someone -- sends you theirs and you keep it. -- -- saved_stickers records only that second route. A reward you earned is -- already yours through sadhna_reward_grants, and duplicating it here would -- give two answers to "do I own this?". CREATE TABLE IF NOT EXISTS saved_stickers ( user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, reward_id UUID NOT NULL REFERENCES sadhna_rewards(id) ON DELETE CASCADE, -- Who sent it. Kept for provenance, and SET NULL rather than CASCADE so -- deleting an account doesn't take away stickers other people saved. saved_from UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (user_id, reward_id) ); -- "What's in my sticker drawer?" — the whole reason this table exists. CREATE INDEX IF NOT EXISTS saved_stickers_user_idx ON saved_stickers (user_id, created_at DESC); -- A sticker message: kind 'sticker', with the artwork denormalized onto the -- attachment's existing image_url/title columns. -- -- Denormalized rather than resolved per read, unlike a shared post: the -- catalog is static art with no viewer-dependent visibility, so there is -- nothing to re-check and a join on every message would buy nothing. ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_kind_check; ALTER TABLE message_attachments ADD CONSTRAINT message_attachments_kind_check CHECK (kind IN ('image', 'video', 'audio', 'file', 'link', 'entity', 'quote', 'sticker')); -- entity_id carries the reward key on a sticker attachment, so a recipient can -- save it without the client having to trust a URL it was handed. ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_entity_type_check; ALTER TABLE message_attachments ADD CONSTRAINT message_attachments_entity_type_check CHECK (entity_type IS NULL OR entity_type IN ('post', 'comment', 'profile', 'collection', 'sticker'));