-- +goose Up -- Stage 8 social UI: two changes to the friend graph. -- -- 1. A declined friend request is now remembered permanently (status 'declined') -- instead of deleting the row, so a recipient's explicit "no" blocks the same -- requester from re-sending (anti-spam). An ignored request still lazily -- expires (30 days, computed from created_at in Go) and can then be re-sent; a -- one-time friend code from the same person bypasses a prior decline. This -- widens friendships_status_chk; the Stage 4 "declining deletes the row" rule -- is superseded (cancelling by the requester still deletes). -- -- 2. friend_codes backs the code-redeem add-a-friend path: the player who wants to -- be added issues a one-time 6-digit numeric code; whoever enters it becomes -- their friend immediately. Only the hex-encoded SHA-256 of the code is stored -- (the plaintext is never persisted, matching the session and email-code -- models); expires_at bounds the 12h TTL and consumed_at marks single use. At -- most one live code exists per issuer (issuing a new one clears the prior -- unconsumed code, enforced in Go). This adds a table, so the generated jet code -- is regenerated (cmd/jetgen). SET search_path = backend, pg_catalog; ALTER TABLE friendships DROP CONSTRAINT friendships_status_chk, ADD CONSTRAINT friendships_status_chk CHECK (status IN ('pending', 'accepted', 'declined')); CREATE TABLE friend_codes ( code_id uuid PRIMARY KEY, account_id uuid NOT NULL REFERENCES accounts (account_id) ON DELETE CASCADE, code_hash text NOT NULL, expires_at timestamptz NOT NULL, consumed_at timestamptz, created_at timestamptz NOT NULL DEFAULT now() ); -- Backs "clear the issuer's prior live code" on issue. CREATE INDEX friend_codes_account_idx ON friend_codes (account_id); -- Backs the redeem lookup by code hash. CREATE INDEX friend_codes_code_hash_idx ON friend_codes (code_hash); -- +goose Down SET search_path = backend, pg_catalog; DROP TABLE friend_codes; ALTER TABLE friendships DROP CONSTRAINT friendships_status_chk, ADD CONSTRAINT friendships_status_chk CHECK (status IN ('pending', 'accepted'));