From d98b29ec765b4511e4ffdcca4b2d923281856b85 Mon Sep 17 00:00:00 2001 From: metatroncubeswdev Date: Fri, 4 Sep 2026 02:13:49 -0400 Subject: [PATCH] chore: add UNLOCK_ALL_FEATURES env flag to bypass plan gating for testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getShopTier() returns "pro" when UNLOCK_ALL_FEATURES=true, so every plan-gated screen (Zones, Rates, Product rules, Dashboard) and the per-tier location cap open up regardless of the shop's real subscription. Single choke point — every tierAtLeast()/locationLimitFor() call derives from getShopTier(). Default off; documented in .env.example as production-unsafe. Co-Authored-By: Claude Sonnet 5 --- .env.example | 6 ++++++ app/services/billing.server.ts | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/.env.example b/.env.example index 916b740..be739ec 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,9 @@ REDIS_URL=redis://127.0.0.1:6380 # Google Maps (Phase 5 — geocoding, radius/distance eligibility, map display). GOOGLE_MAPS_API_KEY= + +# Test/dev only: when "true", every shop resolves as the top tier so all +# plan-gated features (Zones, Rates, Product rules, Dashboard, unlimited +# locations) are open regardless of subscription. Bypasses billing — leave +# unset / "false" in production. +UNLOCK_ALL_FEATURES=false diff --git a/app/services/billing.server.ts b/app/services/billing.server.ts index 0ec342c..5ddb451 100644 --- a/app/services/billing.server.ts +++ b/app/services/billing.server.ts @@ -4,7 +4,15 @@ import { locationLimitFor, type Tier } from "../lib/billing-plans"; export type { Tier }; export { tierAtLeast, tierFromPlanName, locationLimitFor, LOCATION_LIMITS, PLAN_PRICING } from "../lib/billing-plans"; +// Test/dev escape hatch: set UNLOCK_ALL_FEATURES=true in .env to make every +// shop resolve as the top tier, so plan-gated screens (Zones, Rates, +// Product rules, Dashboard) and the per-tier location cap are all open +// regardless of the shop's real subscription. MUST stay off in production — +// it bypasses billing entirely. +const UNLOCK_ALL_FEATURES = process.env.UNLOCK_ALL_FEATURES === "true"; + export async function getShopTier(shopDomain: string): Promise { + if (UNLOCK_ALL_FEATURES) return "pro"; const shop = await db.shop.findUnique({ where: { shopDomain }, select: { tier: true } }); return (shop?.tier as Tier | undefined) ?? "free"; }