core: consolidate badges schema (#7513)

This commit is contained in:
spaced4ndy authored and GitHub committed 2026-09-15 10:15:34 +00:00
1 parent bac8d187ba
commit 069efad7a2
12 files changed
+247 -397

No files matched your search

@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20261001_user_badges where
module Simplex.Chat.Store.Postgres.Migrations.M20260915_user_badges where
import Data.Text (Text)
import qualified Data.Text as T
@@ -58,18 +58,6 @@ CREATE INDEX @idx_payments_provider_ref ON @payments(provider, provider_ref);
CREATE INDEX @idx_payments_invoice ON @payments(invoice_id);
CREATE TABLE @subscription_charges(
charge_id TEXT NOT NULL PRIMARY KEY,
payment_id TEXT NOT NULL REFERENCES @payments ON DELETE CASCADE,
provider_charge_ref TEXT NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
amount BIGINT NOT NULL,
currency TEXT NOT NULL,
charged_at TIMESTAMPTZ NOT NULL,
UNIQUE(payment_id, provider_charge_ref)
);
CREATE TABLE @badge_prices(
price_id TEXT NOT NULL PRIMARY KEY,
badge_type TEXT NOT NULL,
@@ -97,14 +85,90 @@ CREATE TABLE @badge_purchases(
master_key BYTEA NOT NULL,
initial_badge_type TEXT NOT NULL,
current_badge_type TEXT NOT NULL,
payment_id TEXT REFERENCES @payments,
status TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
UNIQUE(purchase_key),
UNIQUE(payment_id)
UNIQUE(purchase_key)
);
CREATE TABLE @badge_ledger(
entry_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
entry_uuid TEXT NOT NULL,
badge_purchase_id BIGINT NOT NULL REFERENCES @badge_purchases ON DELETE CASCADE,
change_months SMALLINT NOT NULL,
balance_months SMALLINT NOT NULL,
balance_start_ts TIMESTAMPTZ NOT NULL,
balance_anchor_ts TIMESTAMPTZ NOT NULL,
balance_badge_type TEXT NOT NULL,
was_paused_since TIMESTAMPTZ,
service_created_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
entry_type TEXT NOT NULL,
entry_credit_type TEXT,
entry_debit_type TEXT
);
CREATE UNIQUE INDEX @idx_badge_ledger_uuid ON @badge_ledger(entry_uuid);
CREATE INDEX @idx_badge_ledger_purchase ON @badge_ledger(badge_purchase_id, entry_id);
CREATE TABLE @badge_issuances(
issuance_id TEXT NOT NULL PRIMARY KEY,
badge_purchase_id BIGINT NOT NULL REFERENCES @badge_purchases ON DELETE CASCADE,
entry_id BIGINT REFERENCES @badge_ledger,
badge_type TEXT NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
expiry TIMESTAMPTZ NOT NULL,
credential BYTEA NOT NULL,
created_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX @idx_badge_issuances_purchase ON @badge_issuances(badge_purchase_id, issuance_id);
CREATE INDEX @idx_badge_issuances_entry ON @badge_issuances(entry_id);
CREATE UNIQUE INDEX @idx_badge_issuances_purchase_entry ON @badge_issuances(badge_purchase_id, entry_id);
|]
badgeSchemaTablesDown :: Text
badgeSchemaTablesDown =
[r|
DROP INDEX @idx_badge_issuances_purchase;
DROP INDEX @idx_badge_issuances_entry;
DROP INDEX @idx_badge_issuances_purchase_entry;
DROP TABLE @badge_issuances;
DROP INDEX @idx_badge_ledger_uuid;
DROP INDEX @idx_badge_ledger_purchase;
DROP TABLE @badge_ledger;
DROP TABLE @badge_purchases;
DROP INDEX @idx_payments_provider_ref;
DROP INDEX @idx_payments_invoice;
DROP TABLE @payments;
DROP TABLE @invoices;
DROP INDEX @idx_badge_offers_price;
DROP TABLE @badge_offers;
DROP TABLE @badge_prices;
|]
{- TODO [badges] deferred draft schema for paid purchases, subscriptions, upgrades and transfers.
CREATE TABLE @subscription_charges(
charge_id TEXT NOT NULL PRIMARY KEY,
payment_id TEXT NOT NULL REFERENCES @payments ON DELETE CASCADE,
provider_charge_ref TEXT NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
amount BIGINT NOT NULL,
currency TEXT NOT NULL,
charged_at TIMESTAMPTZ NOT NULL,
UNIQUE(payment_id, provider_charge_ref)
);
ALTER TABLE @badge_purchases ADD COLUMN payment_id TEXT REFERENCES @payments;
CREATE UNIQUE INDEX @idx_badge_purchases_payment ON @badge_purchases(payment_id);
CREATE TABLE @badge_invoices(
invoice_id TEXT NOT NULL PRIMARY KEY REFERENCES @invoices ON DELETE CASCADE,
badge_purchase_id BIGINT NOT NULL REFERENCES @badge_purchases ON DELETE CASCADE,
@@ -136,30 +200,13 @@ CREATE TABLE @badge_subscription_changes(
CREATE INDEX @idx_badge_subscription_changes_purchase ON @badge_subscription_changes(badge_purchase_id);
CREATE TABLE @badge_ledger(
entry_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
entry_uuid TEXT NOT NULL,
badge_purchase_id BIGINT NOT NULL REFERENCES @badge_purchases ON DELETE CASCADE,
change_months SMALLINT NOT NULL,
balance_months SMALLINT NOT NULL,
balance_start_ts TIMESTAMPTZ NOT NULL,
balance_anchor_ts TIMESTAMPTZ NOT NULL,
balance_badge_type TEXT NOT NULL,
was_paused_since TIMESTAMPTZ,
service_created_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
entry_type TEXT NOT NULL,
entry_credit_type TEXT,
entry_debit_type TEXT,
payment_id TEXT REFERENCES @payments,
charge_id TEXT REFERENCES @subscription_charges,
from_purchase_id BIGINT REFERENCES @badge_purchases,
to_purchase_id BIGINT REFERENCES @badge_purchases
);
ALTER TABLE @badge_ledger ADD COLUMN payment_id TEXT REFERENCES @payments;
CREATE UNIQUE INDEX @idx_badge_ledger_uuid ON @badge_ledger(entry_uuid);
ALTER TABLE @badge_ledger ADD COLUMN charge_id TEXT REFERENCES @subscription_charges;
CREATE INDEX @idx_badge_ledger_purchase ON @badge_ledger(badge_purchase_id, entry_id);
ALTER TABLE @badge_ledger ADD COLUMN from_purchase_id BIGINT REFERENCES @badge_purchases;
ALTER TABLE @badge_ledger ADD COLUMN to_purchase_id BIGINT REFERENCES @badge_purchases;
CREATE INDEX @idx_badge_ledger_payment ON @badge_ledger(payment_id);
@@ -169,58 +216,28 @@ CREATE INDEX @idx_badge_ledger_from_purchase ON @badge_ledger(from_purchase_id);
CREATE INDEX @idx_badge_ledger_to_purchase ON @badge_ledger(to_purchase_id);
CREATE TABLE @badge_issuances(
issuance_id TEXT NOT NULL PRIMARY KEY,
badge_purchase_id BIGINT NOT NULL REFERENCES @badge_purchases ON DELETE CASCADE,
entry_id BIGINT REFERENCES @badge_ledger,
badge_type TEXT NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
expiry TIMESTAMPTZ NOT NULL,
credential BYTEA NOT NULL,
created_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX @idx_badge_issuances_purchase ON @badge_issuances(badge_purchase_id, issuance_id);
CREATE INDEX @idx_badge_issuances_entry ON @badge_issuances(entry_id);
CREATE UNIQUE INDEX @idx_badge_issuances_purchase_entry ON @badge_issuances(badge_purchase_id, entry_id);
|]
badgeSchemaTablesDown :: Text
badgeSchemaTablesDown =
[r|
DROP INDEX @idx_badge_issuances_purchase;
DROP INDEX @idx_badge_issuances_entry;
DROP INDEX @idx_badge_issuances_purchase_entry;
DROP TABLE @badge_issuances;
DROP INDEX @idx_badge_ledger_uuid;
DROP INDEX @idx_badge_ledger_purchase;
-- down
DROP INDEX @idx_badge_ledger_payment;
DROP INDEX @idx_badge_ledger_charge;
DROP INDEX @idx_badge_ledger_from_purchase;
DROP INDEX @idx_badge_ledger_to_purchase;
DROP TABLE @badge_ledger;
ALTER TABLE @badge_ledger DROP COLUMN payment_id;
ALTER TABLE @badge_ledger DROP COLUMN charge_id;
ALTER TABLE @badge_ledger DROP COLUMN from_purchase_id;
ALTER TABLE @badge_ledger DROP COLUMN to_purchase_id;
DROP INDEX @idx_badge_subscription_changes_purchase;
DROP TABLE @badge_subscription_changes;
DROP INDEX @idx_badge_invoices_purchase;
DROP INDEX @idx_badge_invoices_offer;
DROP INDEX @idx_badge_invoices_price;
DROP TABLE @badge_invoices;
DROP TABLE @badge_purchases;
DROP INDEX @idx_badge_purchases_payment;
ALTER TABLE @badge_purchases DROP COLUMN payment_id;
DROP TABLE @subscription_charges;
DROP INDEX @idx_payments_provider_ref;
DROP INDEX @idx_payments_invoice;
DROP TABLE @payments;
DROP TABLE @invoices;
DROP INDEX @idx_badge_offers_price;
DROP TABLE @badge_offers;
DROP TABLE @badge_prices;
|]
-}
m20261001_user_badges :: Text
m20261001_user_badges =
m20260915_user_badges :: Text
m20260915_user_badges =
badgeSchema ""
<> [r|
ALTER TABLE badge_purchases ADD COLUMN user_id BIGINT REFERENCES users ON DELETE CASCADE;
@@ -233,10 +250,6 @@ ALTER TABLE badge_purchases ADD COLUMN alert_acked_episode TEXT;
ALTER TABLE badge_purchases ADD COLUMN alert_snooze_until TIMESTAMPTZ;
ALTER TABLE payments ADD COLUMN evidence BYTEA;
ALTER TABLE payments ADD COLUMN receipt_code TEXT;
ALTER TABLE badge_ledger ADD COLUMN entry_type_unknown SMALLINT NOT NULL DEFAULT 0;
ALTER TABLE badge_ledger ADD COLUMN entry_type_value TEXT;
@@ -267,8 +280,8 @@ ALTER TABLE badge_purchases ADD COLUMN badge_code_redemption_id BIGINT REFERENCE
CREATE UNIQUE INDEX idx_badge_purchases_code_redemption ON badge_purchases(badge_code_redemption_id);
|]
down_m20261001_user_badges :: Text
down_m20261001_user_badges =
down_m20260915_user_badges :: Text
down_m20260915_user_badges =
[r|
DROP INDEX idx_badge_purchases_code_redemption;
DROP INDEX idx_badge_purchases_user;
@@ -280,3 +293,14 @@ ALTER TABLE users DROP COLUMN shown_badge_id;
DROP INDEX idx_badge_code_redemptions_user;
DROP TABLE badge_code_redemptions;
|]
{- TODO [badges] deferred with the draft above, client only.
ALTER TABLE payments ADD COLUMN evidence BYTEA;
ALTER TABLE payments ADD COLUMN receipt_code TEXT;
-- down
ALTER TABLE payments DROP COLUMN evidence;
ALTER TABLE payments DROP COLUMN receipt_code;
-}
@@ -191,17 +191,6 @@ ALTER TABLE test_chat_schema.badge_code_redemptions ALTER COLUMN badge_code_rede
CREATE TABLE test_chat_schema.badge_invoices (
invoice_id text NOT NULL,
badge_purchase_id bigint NOT NULL,
price_id text NOT NULL,
offer_id text,
months smallint NOT NULL,
created_at timestamp with time zone NOT NULL
);
CREATE TABLE test_chat_schema.badge_issuances (
issuance_id text NOT NULL,
badge_purchase_id bigint NOT NULL,
@@ -231,10 +220,6 @@ CREATE TABLE test_chat_schema.badge_ledger (
entry_type text NOT NULL,
entry_credit_type text,
entry_debit_type text,
payment_id text,
charge_id text,
from_purchase_id bigint,
to_purchase_id bigint,
entry_type_unknown smallint DEFAULT 0 NOT NULL,
entry_type_value text,
balance_checked smallint
@@ -282,7 +267,6 @@ CREATE TABLE test_chat_schema.badge_purchases (
master_key bytea NOT NULL,
initial_badge_type text NOT NULL,
current_badge_type text NOT NULL,
payment_id text,
status text NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
@@ -307,22 +291,6 @@ ALTER TABLE test_chat_schema.badge_purchases ALTER COLUMN badge_purchase_id ADD
CREATE TABLE test_chat_schema.badge_subscription_changes (
change_id text NOT NULL,
badge_purchase_id bigint NOT NULL,
from_badge_type text NOT NULL,
to_badge_type text NOT NULL,
from_provider_ref text,
to_provider_ref text,
effective text NOT NULL,
status text NOT NULL,
effective_at timestamp with time zone,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL
);
CREATE TABLE test_chat_schema.calls (
call_id bigint NOT NULL,
contact_id bigint NOT NULL,
@@ -1378,9 +1346,7 @@ CREATE TABLE test_chat_schema.payments (
grace_until timestamp with time zone,
cancelled smallint DEFAULT 0 NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
evidence bytea,
receipt_code text
updated_at timestamp with time zone NOT NULL
);
@@ -1679,19 +1645,6 @@ CREATE TABLE test_chat_schema.snd_files (
CREATE TABLE test_chat_schema.subscription_charges (
charge_id text NOT NULL,
payment_id text NOT NULL,
provider_charge_ref text NOT NULL,
period_start timestamp with time zone NOT NULL,
period_end timestamp with time zone NOT NULL,
amount bigint NOT NULL,
currency text NOT NULL,
charged_at timestamp with time zone NOT NULL
);
CREATE TABLE test_chat_schema.usage_conditions (
usage_conditions_id bigint NOT NULL,
conditions_commit text NOT NULL,
@@ -1804,11 +1757,6 @@ ALTER TABLE ONLY test_chat_schema.badge_code_redemptions
ALTER TABLE ONLY test_chat_schema.badge_invoices
ADD CONSTRAINT badge_invoices_pkey PRIMARY KEY (invoice_id);
ALTER TABLE ONLY test_chat_schema.badge_issuances
ADD CONSTRAINT badge_issuances_pkey PRIMARY KEY (issuance_id);
@@ -1829,11 +1777,6 @@ ALTER TABLE ONLY test_chat_schema.badge_prices
ALTER TABLE ONLY test_chat_schema.badge_purchases
ADD CONSTRAINT badge_purchases_payment_id_key UNIQUE (payment_id);
ALTER TABLE ONLY test_chat_schema.badge_purchases
ADD CONSTRAINT badge_purchases_pkey PRIMARY KEY (badge_purchase_id);
@@ -1844,11 +1787,6 @@ ALTER TABLE ONLY test_chat_schema.badge_purchases
ALTER TABLE ONLY test_chat_schema.badge_subscription_changes
ADD CONSTRAINT badge_subscription_changes_pkey PRIMARY KEY (change_id);
ALTER TABLE ONLY test_chat_schema.calls
ADD CONSTRAINT calls_pkey PRIMARY KEY (call_id);
@@ -2164,16 +2102,6 @@ ALTER TABLE ONLY test_chat_schema.snd_files
ALTER TABLE ONLY test_chat_schema.subscription_charges
ADD CONSTRAINT subscription_charges_payment_id_provider_charge_ref_key UNIQUE (payment_id, provider_charge_ref);
ALTER TABLE ONLY test_chat_schema.subscription_charges
ADD CONSTRAINT subscription_charges_pkey PRIMARY KEY (charge_id);
ALTER TABLE ONLY test_chat_schema.usage_conditions
ADD CONSTRAINT usage_conditions_conditions_commit_key UNIQUE (conditions_commit);
@@ -2230,18 +2158,6 @@ CREATE INDEX idx_badge_code_redemptions_user ON test_chat_schema.badge_code_rede
CREATE INDEX idx_badge_invoices_offer ON test_chat_schema.badge_invoices USING btree (offer_id);
CREATE INDEX idx_badge_invoices_price ON test_chat_schema.badge_invoices USING btree (price_id);
CREATE INDEX idx_badge_invoices_purchase ON test_chat_schema.badge_invoices USING btree (badge_purchase_id);
CREATE INDEX idx_badge_issuances_entry ON test_chat_schema.badge_issuances USING btree (entry_id);
@@ -2254,26 +2170,10 @@ CREATE UNIQUE INDEX idx_badge_issuances_purchase_entry ON test_chat_schema.badge
CREATE INDEX idx_badge_ledger_charge ON test_chat_schema.badge_ledger USING btree (charge_id);
CREATE INDEX idx_badge_ledger_from_purchase ON test_chat_schema.badge_ledger USING btree (from_purchase_id);
CREATE INDEX idx_badge_ledger_payment ON test_chat_schema.badge_ledger USING btree (payment_id);
CREATE INDEX idx_badge_ledger_purchase ON test_chat_schema.badge_ledger USING btree (badge_purchase_id, entry_id);
CREATE INDEX idx_badge_ledger_to_purchase ON test_chat_schema.badge_ledger USING btree (to_purchase_id);
CREATE UNIQUE INDEX idx_badge_ledger_uuid ON test_chat_schema.badge_ledger USING btree (entry_uuid);
@@ -2290,10 +2190,6 @@ CREATE INDEX idx_badge_purchases_user ON test_chat_schema.badge_purchases USING
CREATE INDEX idx_badge_subscription_changes_purchase ON test_chat_schema.badge_subscription_changes USING btree (badge_purchase_id);
CREATE INDEX idx_calls_chat_item_id ON test_chat_schema.calls USING btree (chat_item_id);
@@ -3067,26 +2963,6 @@ ALTER TABLE ONLY test_chat_schema.badge_code_redemptions
ALTER TABLE ONLY test_chat_schema.badge_invoices
ADD CONSTRAINT badge_invoices_badge_purchase_id_fkey FOREIGN KEY (badge_purchase_id) REFERENCES test_chat_schema.badge_purchases(badge_purchase_id) ON DELETE CASCADE;
ALTER TABLE ONLY test_chat_schema.badge_invoices
ADD CONSTRAINT badge_invoices_invoice_id_fkey FOREIGN KEY (invoice_id) REFERENCES test_chat_schema.invoices(invoice_id) ON DELETE CASCADE;
ALTER TABLE ONLY test_chat_schema.badge_invoices
ADD CONSTRAINT badge_invoices_offer_id_fkey FOREIGN KEY (offer_id) REFERENCES test_chat_schema.badge_offers(offer_id);
ALTER TABLE ONLY test_chat_schema.badge_invoices
ADD CONSTRAINT badge_invoices_price_id_fkey FOREIGN KEY (price_id) REFERENCES test_chat_schema.badge_prices(price_id);
ALTER TABLE ONLY test_chat_schema.badge_issuances
ADD CONSTRAINT badge_issuances_badge_purchase_id_fkey FOREIGN KEY (badge_purchase_id) REFERENCES test_chat_schema.badge_purchases(badge_purchase_id) ON DELETE CASCADE;
@@ -3102,26 +2978,6 @@ ALTER TABLE ONLY test_chat_schema.badge_ledger
ALTER TABLE ONLY test_chat_schema.badge_ledger
ADD CONSTRAINT badge_ledger_charge_id_fkey FOREIGN KEY (charge_id) REFERENCES test_chat_schema.subscription_charges(charge_id);
ALTER TABLE ONLY test_chat_schema.badge_ledger
ADD CONSTRAINT badge_ledger_from_purchase_id_fkey FOREIGN KEY (from_purchase_id) REFERENCES test_chat_schema.badge_purchases(badge_purchase_id);
ALTER TABLE ONLY test_chat_schema.badge_ledger
ADD CONSTRAINT badge_ledger_payment_id_fkey FOREIGN KEY (payment_id) REFERENCES test_chat_schema.payments(payment_id);
ALTER TABLE ONLY test_chat_schema.badge_ledger
ADD CONSTRAINT badge_ledger_to_purchase_id_fkey FOREIGN KEY (to_purchase_id) REFERENCES test_chat_schema.badge_purchases(badge_purchase_id);
ALTER TABLE ONLY test_chat_schema.badge_offers
ADD CONSTRAINT badge_offers_price_id_fkey FOREIGN KEY (price_id) REFERENCES test_chat_schema.badge_prices(price_id);
@@ -3132,21 +2988,11 @@ ALTER TABLE ONLY test_chat_schema.badge_purchases
ALTER TABLE ONLY test_chat_schema.badge_purchases
ADD CONSTRAINT badge_purchases_payment_id_fkey FOREIGN KEY (payment_id) REFERENCES test_chat_schema.payments(payment_id);
ALTER TABLE ONLY test_chat_schema.badge_purchases
ADD CONSTRAINT badge_purchases_user_id_fkey FOREIGN KEY (user_id) REFERENCES test_chat_schema.users(user_id) ON DELETE CASCADE;
ALTER TABLE ONLY test_chat_schema.badge_subscription_changes
ADD CONSTRAINT badge_subscription_changes_badge_purchase_id_fkey FOREIGN KEY (badge_purchase_id) REFERENCES test_chat_schema.badge_purchases(badge_purchase_id) ON DELETE CASCADE;
ALTER TABLE ONLY test_chat_schema.calls
ADD CONSTRAINT calls_chat_item_id_fkey FOREIGN KEY (chat_item_id) REFERENCES test_chat_schema.chat_items(chat_item_id) ON DELETE CASCADE;
@@ -3802,11 +3648,6 @@ ALTER TABLE ONLY test_chat_schema.snd_files
ALTER TABLE ONLY test_chat_schema.subscription_charges
ADD CONSTRAINT subscription_charges_payment_id_fkey FOREIGN KEY (payment_id) REFERENCES test_chat_schema.payments(payment_id) ON DELETE CASCADE;
ALTER TABLE ONLY test_chat_schema.user_contact_links
ADD CONSTRAINT user_contact_links_group_id_fkey FOREIGN KEY (group_id) REFERENCES test_chat_schema.groups(group_id) ON DELETE CASCADE;