Implement the ux-first-run change: a state-derived setup checklist on /operator/setup with a landing region that recedes once required steps are done, and empty states that distinguish blocked from empty across operator and member surfaces. Also add production deployment and environment reference docs, plus a config-key completeness test.
54 lines
2.1 KiB
SQL
54 lines
2.1 KiB
SQL
-- name: GetPrice :one
|
|
SELECT * FROM core.prices
|
|
WHERE price_id = $1;
|
|
|
|
-- name: ListPricesByProduct :many
|
|
SELECT * FROM core.prices
|
|
WHERE product_id = $1 AND is_active = TRUE
|
|
ORDER BY created_at ASC, price_id ASC;
|
|
|
|
-- name: GetDefaultPriceByProduct :one
|
|
SELECT * FROM core.prices
|
|
WHERE product_id = $1 AND is_default = TRUE;
|
|
|
|
-- name: CreatePrice :one
|
|
-- The first price a product gets becomes its default automatically (there is
|
|
-- nothing else to offer members); subsequent prices are created non-default
|
|
-- and promoted explicitly via Clear/MarkDefaultPrice. The NOT EXISTS probe
|
|
-- also self-heals a product that somehow lost its default: the next price
|
|
-- created becomes it. The partial unique index
|
|
-- (idx_prices_one_default_per_product) backstops concurrent creation races.
|
|
INSERT INTO core.prices (product_id, currency, unit_amount, recurring_interval, trial_period_days, is_active, is_default)
|
|
VALUES ($1, $2, $3, $4, $5, TRUE,
|
|
NOT EXISTS (SELECT 1 FROM core.prices p WHERE p.product_id = $1 AND p.is_default))
|
|
RETURNING *;
|
|
|
|
-- name: ClearDefaultPrice :exec
|
|
-- First half of the make-default handshake; run in the same transaction as
|
|
-- MarkDefaultPrice (clear before set, so the partial unique index never sees
|
|
-- two defaults for one product).
|
|
UPDATE core.prices
|
|
SET is_default = FALSE
|
|
WHERE product_id = $1 AND is_default;
|
|
|
|
-- name: MarkDefaultPrice :one
|
|
-- Second half of the make-default handshake. Scoped to (price_id, product_id)
|
|
-- so a stale/forged price ID from another product cannot be promoted; the
|
|
-- is_active guard keeps a deactivated price from becoming the default.
|
|
UPDATE core.prices
|
|
SET is_default = TRUE
|
|
WHERE price_id = $1 AND product_id = $2 AND is_active = TRUE
|
|
RETURNING *;
|
|
|
|
-- name: DeactivatePrice :one
|
|
-- Handlers must refuse to deactivate the default price (members would lose
|
|
-- the purchase path); the is_default guard here backstops that rule.
|
|
UPDATE core.prices
|
|
SET is_active = FALSE
|
|
WHERE price_id = $1 AND is_default = FALSE
|
|
RETURNING *;
|
|
|
|
-- name: AnyActivePrice :one
|
|
-- Setup-checklist existence probe.
|
|
SELECT EXISTS(SELECT 1 FROM core.prices WHERE is_active = TRUE);
|