Free/Pro plan limitations

This commit is contained in:
2026-01-28 22:12:32 +00:00
parent c0e06ac8ba
commit 7f3cb7c890
15 changed files with 420 additions and 60 deletions

View File

@@ -1,6 +1,13 @@
import { IssueCreateRequestSchema } from "@sprint/shared";
import type { AuthedRequest } from "../../auth/middleware";
import { createIssue, getOrganisationMemberRole, getProjectByID } from "../../db/queries";
import {
createIssue,
FREE_TIER_LIMITS,
getOrganisationIssueCount,
getOrganisationMemberRole,
getProjectByID,
getUserById,
} from "../../db/queries";
import { errorResponse, parseJsonBody } from "../../validation";
export default async function issueCreate(req: AuthedRequest) {
@@ -26,6 +33,19 @@ export default async function issueCreate(req: AuthedRequest) {
);
}
// check free tier limit
const user = await getUserById(req.userId);
if (user && user.plan !== "pro") {
const issueCount = await getOrganisationIssueCount(project.organisationId);
if (issueCount >= FREE_TIER_LIMITS.issuesPerOrganisation) {
return errorResponse(
`free tier is limited to ${FREE_TIER_LIMITS.issuesPerOrganisation} issues per organisation. upgrade to pro for unlimited issues.`,
"FREE_TIER_ISSUE_LIMIT",
403,
);
}
}
const issue = await createIssue(
project.id,
title,

View File

@@ -2,8 +2,10 @@ import { OrgAddMemberRequestSchema } from "@sprint/shared";
import type { AuthedRequest } from "../../auth/middleware";
import {
createOrganisationMember,
FREE_TIER_LIMITS,
getOrganisationById,
getOrganisationMemberRole,
getOrganisationMembers,
getUserById,
} from "../../db/queries";
import { updateSeatCount } from "../../lib/seats";
@@ -39,6 +41,19 @@ export default async function organisationAddMember(req: AuthedRequest) {
return errorResponse("only owners and admins can add members", "PERMISSION_DENIED", 403);
}
// check free tier member limit
const requester = await getUserById(req.userId);
if (requester && requester.plan !== "pro") {
const members = await getOrganisationMembers(organisationId);
if (members.length >= FREE_TIER_LIMITS.membersPerOrganisation) {
return errorResponse(
`free tier is limited to ${FREE_TIER_LIMITS.membersPerOrganisation} members per organisation. upgrade to pro for unlimited members.`,
"FREE_TIER_MEMBER_LIMIT",
403,
);
}
}
const member = await createOrganisationMember(organisationId, userId, role);
// update seat count if the requester is the owner

View File

@@ -1,6 +1,12 @@
import { OrgCreateRequestSchema } from "@sprint/shared";
import type { AuthedRequest } from "../../auth/middleware";
import { createOrganisationWithOwner, getOrganisationBySlug } from "../../db/queries";
import {
createOrganisationWithOwner,
FREE_TIER_LIMITS,
getOrganisationBySlug,
getUserById,
getUserOrganisationCount,
} from "../../db/queries";
import { errorResponse, parseJsonBody } from "../../validation";
export default async function organisationCreate(req: AuthedRequest) {
@@ -14,6 +20,19 @@ export default async function organisationCreate(req: AuthedRequest) {
return errorResponse(`organisation with slug "${slug}" already exists`, "SLUG_TAKEN", 409);
}
// check free tier limit
const user = await getUserById(req.userId);
if (user && user.plan !== "pro") {
const orgCount = await getUserOrganisationCount(req.userId);
if (orgCount >= FREE_TIER_LIMITS.organisationsPerUser) {
return errorResponse(
`free tier is limited to ${FREE_TIER_LIMITS.organisationsPerUser} organisation. upgrade to pro for unlimited organisations.`,
"FREE_TIER_ORG_LIMIT",
403,
);
}
}
const organisation = await createOrganisationWithOwner(name, slug, req.userId, description);
return Response.json(organisation);

View File

@@ -1,6 +1,13 @@
import { ProjectCreateRequestSchema } from "@sprint/shared";
import type { AuthedRequest } from "../../auth/middleware";
import { createProject, getOrganisationMemberRole, getProjectByKey, getUserById } from "../../db/queries";
import {
createProject,
FREE_TIER_LIMITS,
getOrganisationMemberRole,
getOrganisationProjectCount,
getProjectByKey,
getUserById,
} from "../../db/queries";
import { errorResponse, parseJsonBody } from "../../validation";
export default async function projectCreate(req: AuthedRequest) {
@@ -22,7 +29,19 @@ export default async function projectCreate(req: AuthedRequest) {
return errorResponse("only owners and admins can create projects", "PERMISSION_DENIED", 403);
}
// check free tier limit
const creator = await getUserById(req.userId);
if (creator && creator.plan !== "pro") {
const projectCount = await getOrganisationProjectCount(organisationId);
if (projectCount >= FREE_TIER_LIMITS.projectsPerOrganisation) {
return errorResponse(
`free tier is limited to ${FREE_TIER_LIMITS.projectsPerOrganisation} project per organisation. upgrade to pro for unlimited projects.`,
"FREE_TIER_PROJECT_LIMIT",
403,
);
}
}
if (!creator) {
return errorResponse(`creator not found`, "CREATOR_NOT_FOUND", 404);
}