fix(entitlements): trial seeding grants every paid capability, not the launch four (#1698)
seed_trial_capability_grants() still hardcoded ai/bank_sync/skatteverket/ email_send while PAID_CAPABILITIES grew to seven keys. Payers got all seven via the Stripe webhook; every company created since 2026-07-12 was trialing without stripe_payments (and later woocommerce_sync/shopify_sync). Redefine the trigger with the full set, backfill existing trial grants by mirroring bank_sync, and pin the pg test to PAID_CAPABILITIES so the lists cannot drift again. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
43cde6deb9
commit
b07a4a4bca
@@ -0,0 +1,60 @@
|
||||
-- Trial seeding must grant every PAID capability, not the 2026-06-29 four.
|
||||
--
|
||||
-- lib/entitlements/keys.ts PAID_CAPABILITIES grew to seven keys
|
||||
-- (stripe_payments 2026-07-12, woocommerce_sync 2026-08-06, shopify_sync
|
||||
-- 2026-08-08). The Stripe webhook writes grants from that constant, so
|
||||
-- payers have all seven; the trial trigger seed_trial_capability_grants()
|
||||
-- (20260629120000) still hardcodes ('ai','bank_sync','skatteverket',
|
||||
-- 'email_send'), and each key's backfill only mirrored the grants that
|
||||
-- existed on its day. Every company created since is trialing without the
|
||||
-- newer keys: on 2026-08-18, 226 of 230 active trialers lacked
|
||||
-- stripe_payments, 146 woocommerce_sync, 131 shopify_sync.
|
||||
--
|
||||
-- 1. Redefine the trigger function with the full PAID set. Keep this VALUES
|
||||
-- list in step with PAID_CAPABILITIES whenever a key is added (and add a
|
||||
-- backfill like part 2 for the companies already seeded).
|
||||
-- 2. Backfill: mirror every existing trial bank_sync grant (same company,
|
||||
-- same expiry) for the three missing keys. Idempotent via the unique
|
||||
-- index; expired trials are mirrored too so state stays aligned, exactly
|
||||
-- as the earlier backfills did.
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.seed_trial_capability_grants()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.capability_grants (company_id, capability_key, source, expires_at)
|
||||
SELECT NEW.id, k.key, 'trial', NEW.created_at + interval '30 days'
|
||||
FROM (VALUES
|
||||
('ai'),
|
||||
('bank_sync'),
|
||||
('skatteverket'),
|
||||
('email_send'),
|
||||
('stripe_payments'),
|
||||
('woocommerce_sync'),
|
||||
('shopify_sync')
|
||||
) AS k(key)
|
||||
ON CONFLICT (company_id, team_id, capability_key, source) DO NOTHING;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
INSERT INTO public.capability_grants
|
||||
(company_id, team_id, capability_key, source, granted_at, expires_at, metadata)
|
||||
SELECT
|
||||
g.company_id,
|
||||
g.team_id,
|
||||
k.key,
|
||||
g.source,
|
||||
g.granted_at,
|
||||
g.expires_at,
|
||||
jsonb_build_object(
|
||||
'backfilled_from', 'bank_sync',
|
||||
'backfill_migration', '20260818170000'
|
||||
)
|
||||
FROM public.capability_grants g
|
||||
CROSS JOIN (VALUES ('stripe_payments'), ('woocommerce_sync'), ('shopify_sync')) AS k(key)
|
||||
WHERE g.capability_key = 'bank_sync' AND g.source = 'trial'
|
||||
ON CONFLICT (company_id, team_id, capability_key, source) DO NOTHING;
|
||||
Reference in New Issue
Block a user