SERVICE
service.ts
Business logic, ownership checks, typed errors.
StarkWHAT THIS PATTERN TEACHES
How to encapsulate business logic in services that own their errors and enforce data access rules.
WHEN TO USE THIS
Any business logic that goes beyond simple CRUD. Services are the heart of the application.
AT A GLANCE
export class ProjectService {
async create(data: CreateInput): Promise<Project> {
// ownership check, validation, persist
}
}FRAMEWORK IMPLEMENTATIONS
TypeScript
import { db } from "@/lib/db";
import { ApiError } from "@/lib/errors";
interface CreateProjectInput {
name: string;
description?: string;
workspaceId: string;
}
export const projectService = {
async create(data: CreateProjectInput, userId: string) {
// Ownership check: user must belong to workspace
const membership = await db.workspaceMember.findFirst({
where: { workspaceId: data.workspaceId, userId },
});
if (!membership) {
throw new ApiError("NOT_FOUND", "Workspace not found", 404);
}
// Business rule: max 50 projects per workspace