[ { "id": "T001", "description": "resolveTier() JSDoc no longer references 'basic'", "implemented": false, "featureIds": ["BF1"] }, { "id": "T002", "description": "ResolvedTier interface JSDoc references 'pro' as default", "implemented": false, "featureIds": ["BF1"] }, { "id": "T003", "description": "buildPhaseItems uses pro prices when tenant is on pro tier", "implemented": false, "featureIds": ["BF2"] }, { "id": "T004", "description": "buildPhaseItems uses premium prices when tenant is on premium tier", "implemented": false, "featureIds": ["BF2"] }, { "id": "T005", "description": "saveInvoiceTemplate throws TierAccessError for pro tenant calling visual save", "implemented": false, "featureIds": ["BF3"] }, { "id": "T006", "description": "saveInvoiceTemplate succeeds for premium tenant", "implemented": false, "featureIds": ["BF3"] }, { "id": "T007", "description": "JWT plan-fetch helper returns plan from tenants table", "implemented": false, "featureIds": ["BF4"] }, { "id": "T008", "description": "Both buildAuthOptions and static options use shared plan-fetch helper", "implemented": false, "featureIds": ["BF4"] }, { "id": "T009", "description": "tierFromStripeProduct logs warning for unknown product name", "implemented": false, "featureIds": ["BF5"] }, { "id": "T010", "description": "tierFromStripeProduct still returns 'pro' for unknown products", "implemented": false, "featureIds": ["BF5"] }, { "id": "T011", "description": "TierGate renders skeleton while session is loading", "implemented": false, "featureIds": ["BF6"] }, { "id": "T012", "description": "TierGate renders children when feature is accessible", "implemented": false, "featureIds": ["BF6"] }, { "id": "T013", "description": "TierGate renders FeatureUpgradeNotice when feature is not accessible", "implemented": false, "featureIds": ["BF6"] }, { "id": "T014", "description": "FK migration adds foreign key constraint on stripe_base_price_id", "implemented": false, "featureIds": ["BF7"] }, { "id": "T015", "description": "addOns.ts has JSDoc explaining scaffolding status", "implemented": false, "featureIds": ["BF8"] }, { "id": "T016", "description": "Tier gating guide exists at docs/tier-gating-guide.md", "implemented": false, "featureIds": ["DOC1"] }, { "id": "T017", "description": "Guide documents all 7 steps for adding a new gated feature", "implemented": false, "featureIds": ["DOC1a", "DOC1b", "DOC1c"] }, { "id": "T018", "description": "Annual price env vars present in .env.example", "implemented": false, "featureIds": ["AB1"] }, { "id": "T019", "description": "StripeService config includes annual price ID fields", "implemented": false, "featureIds": ["AB2"] }, { "id": "T020", "description": "billing_interval column exists on stripe_subscriptions with default 'month'", "implemented": false, "featureIds": ["AB3"] }, { "id": "T021", "description": "Subscription creation stores billing_interval from Stripe price", "implemented": false, "featureIds": ["AB4"] }, { "id": "T022", "description": "Checkout session uses annual price when interval='year'", "implemented": false, "featureIds": ["AB5"] }, { "id": "T023", "description": "Checkout session uses monthly price when interval='month'", "implemented": false, "featureIds": ["AB5"] }, { "id": "T024", "description": "Account page shows monthly/annual toggle", "implemented": false, "featureIds": ["AB6"] }, { "id": "T025", "description": "Annual toggle displays '2 months free' savings callout", "implemented": false, "featureIds": ["AB6"] }, { "id": "T026", "description": "Interval switch schedules change at period end, not immediate", "implemented": false, "featureIds": ["AB7"] }, { "id": "T027", "description": "upgradeTier with interval='year' uses annual prices", "implemented": false, "featureIds": ["AB8"] }, { "id": "T028", "description": "getUpgradePreview returns both monthly and annual pricing", "implemented": false, "featureIds": ["AB9"] }, { "id": "T029", "description": "JWT token type includes trial_end and subscription_status fields", "implemented": false, "featureIds": ["TR1"] }, { "id": "T030", "description": "Session.user type includes trial_end and subscription_status fields", "implemented": false, "featureIds": ["TR1"] }, { "id": "T031", "description": "JWT callback fetches trial_end from stripe_subscriptions on sign-in", "implemented": false, "featureIds": ["TR2"] }, { "id": "T032", "description": "JWT callback refreshes trial_end on 5-minute throttle", "implemented": false, "featureIds": ["TR2"] }, { "id": "T033", "description": "Session callback copies trial_end and subscription_status to session", "implemented": false, "featureIds": ["TR3"] }, { "id": "T034", "description": "TierContext provides isTrialing=true when subscription status is 'trialing'", "implemented": false, "featureIds": ["TR4"] }, { "id": "T035", "description": "TierContext provides correct trialDaysLeft countdown", "implemented": false, "featureIds": ["TR4"] }, { "id": "T036", "description": "TierContext trialDaysLeft is null when not trialing", "implemented": false, "featureIds": ["TR4"] }, { "id": "T037", "description": "TierContext isPaymentFailed=true when status is past_due", "implemented": false, "featureIds": ["TR5"] }, { "id": "T038", "description": "TierContext isPaymentFailed=true when status is unpaid", "implemented": false, "featureIds": ["TR5"] }, { "id": "T039", "description": "New Pro checkout session includes trial_period_days: 7", "implemented": false, "featureIds": ["TR6"] }, { "id": "T040", "description": "TrialBanner renders with plan name and days left", "implemented": false, "featureIds": ["TR7"] }, { "id": "T041", "description": "TrialBanner uses warning styling when ≤3 days remaining", "implemented": false, "featureIds": ["TR8"] }, { "id": "T042", "description": "TrialBanner uses info styling when >3 days remaining", "implemented": false, "featureIds": ["TR8"] }, { "id": "T043", "description": "TrialBanner links to /msp/account", "implemented": false, "featureIds": ["TR9"] }, { "id": "T044", "description": "TrialBanner not rendered when not trialing", "implemented": false, "featureIds": ["TR7"] }, { "id": "T045", "description": "PaymentFailedBanner renders when past_due", "implemented": false, "featureIds": ["TR10"] }, { "id": "T046", "description": "PaymentFailedBanner renders when unpaid", "implemented": false, "featureIds": ["TR10"] }, { "id": "T047", "description": "PaymentFailedBanner not rendered when subscription is active", "implemented": false, "featureIds": ["TR10"] }, { "id": "T048", "description": "PaymentFailedBanner replaces TrialBanner when both conditions apply", "implemented": false, "featureIds": ["TR11"] }, { "id": "T049", "description": "Account page shows Trial Status card when trialing", "implemented": false, "featureIds": ["TR12"] }, { "id": "T050", "description": "Trial Status card shows progress bar with correct percentage", "implemented": false, "featureIds": ["TR12"] }, { "id": "T051", "description": "Trial Status card shows upcoming charge amount and date for Pro trial", "implemented": false, "featureIds": ["TR13"] }, { "id": "T052", "description": "Trial Status card shows 'Cancel Premium Trial' option during Premium trial", "implemented": false, "featureIds": ["TR13"] }, { "id": "T053", "description": "Webhook handles trialing → active transition correctly", "implemented": false, "featureIds": ["TR14"] }, { "id": "T054", "description": "Webhook handles trialing → past_due transition (failed charge)", "implemented": false, "featureIds": ["TR15"] }, { "id": "T055", "description": "startPremiumTrialAction rejects non-master-tenant callers", "implemented": false, "featureIds": ["TR16"] }, { "id": "T055a", "description": "startPremiumTrialAction for paying Pro creates Premium subscription with 30-day trial", "implemented": false, "featureIds": ["TR16a"] }, { "id": "T055b", "description": "startPremiumTrialAction for Pro trial: ends trial, charges first Pro month, then creates Premium trial", "implemented": false, "featureIds": ["TR16b"] }, { "id": "T055c", "description": "startPremiumTrialAction for Pro trial: verifies Pro charge succeeded before creating Premium trial", "implemented": false, "featureIds": ["TR16b"] }, { "id": "T056", "description": "startPremiumTrialAction rejects tenants already on Premium or Premium trial", "implemented": false, "featureIds": ["TR17"] }, { "id": "T057", "description": "startPremiumTrialAction sets tenants.plan to 'premium'", "implemented": false, "featureIds": ["TR18"] }, { "id": "T058", "description": "Premium trial end auto-charges: webhook trialing→active keeps plan as 'premium'", "implemented": false, "featureIds": ["TR19"] }, { "id": "T059", "description": "Cancel Premium Trial reverts subscription and sets plan to 'pro'", "implemented": false, "featureIds": ["TR20"] }, { "id": "T060", "description": "Cancel Premium Trial button only shown during active Premium trial", "implemented": false, "featureIds": ["TR20"] }, { "id": "T060a", "description": "Premium trial charge failure: webhook trialing→past_due triggers payment banner", "implemented": false, "featureIds": ["TR20a"] }, { "id": "T061", "description": "Premium trial request form renders textarea for Pro users (paid or trialing)", "implemented": false, "featureIds": ["TR21"] }, { "id": "T062", "description": "Premium trial request form shown for Pro trialing users", "implemented": false, "featureIds": ["TR22"] }, { "id": "T063", "description": "Premium trial request form hidden for Premium users", "implemented": false, "featureIds": ["TR22"] }, { "id": "T064", "description": "sendPremiumTrialRequestAction sends email with tenant info and message", "implemented": false, "featureIds": ["TR23"] }, { "id": "T065", "description": "NineMinds extension shows trial requests list", "implemented": false, "featureIds": ["TR24"] }, { "id": "T066", "description": "NineMinds extension 'Start Premium Trial' button calls correct API", "implemented": false, "featureIds": ["TR25"] }, { "id": "T067", "description": "POST /api/v1/tenant-management/start-premium-trial validates master tenant auth", "implemented": false, "featureIds": ["TR26"] }, { "id": "T068", "description": "POST /api/v1/tenant-management/start-premium-trial rejects non-admin callers", "implemented": false, "featureIds": ["TR26"] }, { "id": "T069", "description": "NineMinds tenant list shows plan, trial status, subscription status columns", "implemented": false, "featureIds": ["TR27"] }, { "id": "T070", "description": "handleSubscriptionUpdated sets local status to past_due when Stripe reports past_due", "implemented": false, "featureIds": ["PE2"] }, { "id": "T071", "description": "handleSubscriptionUpdated sets local status to unpaid when Stripe reports unpaid", "implemented": false, "featureIds": ["PE2"] } ]