Skip to content

Comments

Feat/tier enforcement#10

Merged
davidancor merged 10 commits intomainfrom
feat/tier-enforcement
Feb 21, 2026
Merged

Feat/tier enforcement#10
davidancor merged 10 commits intomainfrom
feat/tier-enforcement

Conversation

@davidancor
Copy link
Contributor

Here's the filled-out PR template for the tier enforcement work:


Type:

  • ⚡ Performance improvement
  • 🧪 Test addition or update
  • 🎨 UI/UX improvement
  • 🔧 Configuration change

Related Issues

Closes # (no issue tracked — this came from the pricing spec)

Changes Made

  • Add centralized PLAN_LIMITS config with 10% grace overage (Free=2,750,
    Base=5,500, Plus=unlimited)
  • Add creditsUsed, creditLimit, teamMemberLimit columns to teams schema +
    migration 0007
  • Replace handleSubscriptionChange with per-tier limit assignment derived from
    Stripe product name
  • Add checkAndDeductCredits — Plus bypasses limits, Free/Base enforced with
    atomic race-safe SQL
  • Add team member limit check to inviteTeamMember (Free=2, Base=2,
    Plus=unlimited)
  • Set correct tier limits on checkout success route
  • Add customer.subscription.created webhook event as safety net
  • Remove trial_period_days: 7 — free tier is credit-based, not time-limited
  • Update pricing page: "Free Trial" → "Free", credit-based copy, conditional
    trial text

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • E2E tests added/updated
  • Manual testing completed

Test Steps

  1. Run npx jest --verbose from apps/product-helper
  2. Verify 640/642 pass (2 pre-existing failures from missing ANTHROPIC_API_KEY)
  3. After migration: test checkout flow sets correct creditLimit and
    teamMemberLimit

Test Results

PASS lib/constants/tests/plan-limits.test.ts (9 tests)
PASS lib/payments/tests/stripe-tiers.test.ts (3 tests)
PASS lib/db/tests/credit-enforcement.test.ts (6 tests)
PASS app/(login)/tests/invite-limits.test.ts (6 tests)

Test Suites: 2 failed, 21 passed, 23 total
Tests: 2 failed, 640 passed, 642 total
(2 failures are pre-existing — missing ANTHROPIC_API_KEY in core-tools.test.ts)

Documentation

  • Added code comments for complex logic
  • (No README/API doc/ADR/CHANGELOG changes needed)

Checklist

Code Quality

  • Code follows project style guidelines
  • TypeScript types are properly defined
  • No console.log or debug code left in
  • Error handling is implemented
  • Code is DRY (Don't Repeat Yourself)

Testing

  • All tests pass locally
  • Test coverage maintained or improved
  • Edge cases are covered

Documentation

  • CHANGELOG.md updated (unless skip-changelog label)
  • Comments added for complex logic

Security

  • No sensitive data exposed
  • Input validation implemented
  • Authentication/authorization checked
  • Dependencies are secure (no known vulnerabilities)

Performance

  • Database queries optimized
  • No N+1 query issues
  • (No React re-render or bundle size impact)

Accessibility

  • (Pricing page text changes only — no new interactive elements)

Breaking Changes

Impact: None. New columns have defaults matching existing behavior (free tier
limits). Existing teams unaffected until migration backfill runs.

Migration Path: Apply migration 0007 via Supabase SQL Editor before merge.

Deployment Notes

  • Database migration required — lib/db/migrations/0007_lively_selene.sql via
    Supabase SQL Editor
  • Environment variables added/changed
  • External service configuration needed
  • Other: Verify Stripe product names are exactly "Base" and "Plus"
    (case-sensitive)

Rollback Plan

  1. Revert merge commit on main
  2. Run rollback SQL: ALTER TABLE teams DROP COLUMN IF EXISTS credits_used, DROP
    COLUMN IF EXISTS credit_limit, DROP COLUMN IF EXISTS team_member_limit;
  3. Redeploy — existing code doesn't reference new columns

Agent Team Review

Additional Context

Tier limits: Free (2,500 credits / 2 members), Base CA$19.99 (5,000 credits / 2
members), Plus CA$49.99 (unlimited). Grace period of 10% on credit limits for
soft cap behavior. Stripe prices still placeholder ($8/$12 USD) — not touched
in this PR per David's instruction.

Button: Tangerine bg, Figma shadow via var(), 12px radius, 44px height,
  secondary=black/5, outline=transparent, ghost=hover bg, link=no bg.
Input: bg-black/5, border rgba(13,13,13,0.15), 12px radius, 40px height,
  placeholder opacity via rgba, dark mode white/15.
Card: white bg, subtle border rgba(13,13,13,0.15), shadow 0px 1px 2px.
Badge: 6px radius (rounded-md), bg-black/5, proper dark mode variants.
… accordion, dropdown-menu, avatar to Figma specs

Tabs: container 10px radius with border, active tab 8px radius white bg.
Select: trigger matches input (black/5, 12px radius), content white bg.
Dialog: white bg, rgba border, 12px radius, removed inline style overrides.
Sheet: white bg, rgba border colors for light/dark.
Label: text-base leading-[150%] (Consolas via body inheritance).
Radio-group: 18x18 size, unchecked=black/5 border, checked=solid black/white.
Accordion: border rgba(13,13,13,0.15), text-base trigger.
Dropdown-menu: white bg, rgba border, 12px radius, items rounded-lg text-base.
Avatar: added rgba border for light/dark modes.
Collapsible: no changes needed (inherits tokens correctly).
…ma tokens

Replace inline style={{}} with Tailwind token classes across 5 components:
- explorer-sidebar: bg-sidebar, border-sidebar-border, text-sidebar-foreground
- project-context-card: text-foreground, text-muted-foreground, border-border
- quick-instructions: bg-primary, text-primary-foreground, border-border
- artifact-pipeline: text-foreground, text-muted-foreground, text-green-500
- project-header-compact: bg-background, border-border, text-foreground

All fontFamily inlines removed. Only dynamic layout styles remain as inline.
…tion components

Remove all inline style={{ }} from the 6 heaviest section components
(guidelines, schema, system-overview, api-spec, architecture, user-stories).
Font-family inlines removed (Consolas inherited from body, Space Grotesk
from headings). Color/background/border values replaced with Tailwind
token classes: text-foreground, text-muted-foreground, text-primary,
bg-muted, bg-card, border-border. Total inline styles in these 6 files
reduced from 193 to 0.
…ma tokens

Replace inline style={{}} with Tailwind token classes across 5 components:
- explorer-sidebar: bg-sidebar, border-sidebar-border, text-sidebar-foreground
- project-context-card: text-foreground, text-muted-foreground, border-border
- quick-instructions: bg-primary, text-primary-foreground, border-border
- artifact-pipeline: text-foreground, text-muted-foreground, text-green-500
- project-header-compact: bg-background, border-border, text-foreground

All fontFamily inlines removed. Only dynamic layout styles remain as inline.
…okens

Replace inline style={{ }} with Tailwind utility classes in welcome-onboarding,
pipeline-card, progress-cards, and quick-start-button. Pipeline card uses
bg-card border-border rounded-xl with Tangerine primary buttons. Progress card
step icons use token colors (text-primary, text-destructive). Quick start button
removes all style overrides — inherits from updated shadcn Button component.
Onboarding header uses text-foreground/text-muted-foreground tokens.
- Add PLAN_LIMITS constants with 10% grace period (Free=2750, Base=5500, Plus=unlimited)
- Add creditsUsed, creditLimit, teamMemberLimit columns to teams schema
- Replace handleSubscriptionChange with per-tier limit assignment
- Add checkAndDeductCredits with Base tier enforcement (was bypassing all paid)
- Add team member limit check to inviteTeamMember
- Set tier limits on checkout success route
- Add customer.subscription.created webhook event
- Remove trial_period_days from checkout session
- Update pricing page: Free Trial -> Free, credit-based copy, conditional trial text
- Generate migration 0007 with backfill for existing teams
@vercel
Copy link

vercel bot commented Feb 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
c1v-product-helper-9hdq Ready Ready Preview, Comment Feb 21, 2026 0:42am

Request Review

@davidancor davidancor merged commit c9db010 into main Feb 21, 2026
6 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant