Skip to content

Phase 5 — Organization Management & Subscription Gating

Goal: Full multi-user org support. Hard usage limits enforced. Subscription management via Stripe.


5.1 Backend — Organization Management

GET  /v1/orgs/:id
PATCH /v1/orgs/:id                 — update name, logo, billingEmail
GET  /v1/orgs/:id/members
POST /v1/orgs/:id/members/invite   — invite a recruiter by email
PATCH /v1/orgs/:id/members/:userId — change member role
DELETE /v1/orgs/:id/members/:userId
GET  /v1/orgs/:id/features         — current featureSnapshot

5.2 Backend — Plan Management + featureSnapshot Sync

GET  /v1/plans                     — list all active plans (public, no auth)
POST /v1/orgs/:id/plan             — change plan (admin only)

On plan change:

typescript
const plan = await Plan.findOne({ key: newPlanKey });
await Organization.findByIdAndUpdate(orgId, {
  planKey: newPlanKey,
  featureSnapshot: {
    maxActiveJobs: plan.features.maxActiveJobs,
    maxCandidatesPerJob: plan.features.maxCandidatesPerJob,
    maxInterviewsPerMonth: plan.features.maxInterviewsPerMonth,
    advancedAnalytics: plan.features.advancedAnalytics,
    customBranding: plan.features.customBranding,
    apiAccess: plan.features.apiAccess,
  },
});

All stage types remain available — only usage limits change.


5.3 Backend — Hard Usage-Limit Enforcement

Usage limit checks added to all three enforcement points (already scaffolded in Phase 0):

typescript
// POST /v1/jobs — active job limit
// POST /v1/interviews — monthly interview count
// POST /v1/interviews — first candidate for a job (maxCandidatesPerJob)

See Usage Cap Enforcement deep dive for implementation details.


5.4 Backend — Stripe Webhooks

POST /v1/webhooks/stripe:

  • customer.subscription.updated → sync plan → update Organization.planKey + featureSnapshot
  • customer.subscription.deleted → downgrade to free

5.5 Frontend — Org Settings Page

Route: /settings/organization

src/pages/settings/OrganizationSettings.tsx:

  • Org name, logo upload, billing email
  • Members table: list, invite, remove, role change
  • Current plan display + "Upgrade Plan" CTA

5.6 Frontend — Billing Page

Route: /settings/billing

src/pages/settings/BillingSettings.tsx:

  • List plans from GET /v1/plans (dynamic — no hardcoded plan names)
  • Show current plan, feature comparison table
  • Stripe Checkout integration

Phase 5 — Acceptance Criteria

  • [ ] Org admin can invite team members by email; invited users appear in Organization.members
  • [ ] GET /v1/stage-types returns all 6 stage types regardless of plan
  • [ ] Job creation returns 403 when maxActiveJobs limit is reached
  • [ ] Interview creation returns 403 when maxInterviewsPerMonth limit is reached
  • [ ] Candidate addition returns 403 when maxCandidatesPerJob limit is reached
  • [ ] Plan upgrade via Stripe updates featureSnapshot; higher limits take effect immediately
  • [ ] advancedAnalytics, customBranding flags gate premium features correctly
  • [ ] Billing page reads plan names from GET /v1/plans — no hardcoded plan comparison table