MembershipService Reference
Version: 2.0 Last Updated: 2025-12-26
Overview
MembershipService provides unified team membership context by combining data from multiple sources into a single TeamMembership object.
Import
import { MembershipService, TeamMembership } from '@/core/lib/services'
MembershipService
get(userId, teamId)
Builds complete membership context for a user in a team.
static async get(userId: string, teamId: string): Promise<TeamMembership>
Parameters:
userId- User IDteamId- Team ID
Returns: TeamMembership object
Example:
const membership = await MembershipService.get(userId, teamId)
if (!membership.role) {
// User is not a member
return Response.json({ error: 'Not a member' }, { status: 403 })
}
Data Sources:
TeamMemberService- role, joinedAtSubscriptionService- plan, status, featuresPermissionService- permissions arrayAPP_CONFIG_MERGED- hierarchy levelsUsageService- quota states
TeamMembership Class
Properties
| Property | Type | Description |
|---|---|---|
userId |
string |
User ID |
teamId |
string |
Team ID |
role |
string | null |
Team role (null if not member) |
hierarchy |
number |
Role hierarchy level |
permissions |
Permission[] |
Array of permissions |
subscription |
MembershipSubscription | null |
Subscription info |
features |
string[] |
Plan features |
quotas |
Record<string, QuotaState> |
Quota states by limit |
Methods
hasMinHierarchy(level)
Check if user has minimum hierarchy level.
hasMinHierarchy(level: number): boolean
Example:
// Check if admin or higher (hierarchy >= 50)
if (membership.hasMinHierarchy(50)) {
// Can perform admin actions
}
// Hierarchy levels:
// owner: 100, admin: 50, member: 10, viewer: 1
hasRole(role)
Check if user has specific role.
hasRole(role: string): boolean
Example:
if (membership.hasRole('owner')) {
// User is the team owner
}
hasAnyRole(roles)
Check if user has any of the specified roles.
hasAnyRole(roles: string[]): boolean
Example:
if (membership.hasAnyRole(['owner', 'admin'])) {
// User is owner OR admin
}
hasPermission(permission)
Check if user has specific permission.
hasPermission(permission: Permission): boolean
Example:
if (membership.hasPermission('customers.delete')) {
// User can delete customers
}
hasFeature(feature)
Check if plan includes specific feature.
hasFeature(feature: string): boolean
Example:
if (membership.hasFeature('advanced_analytics')) {
// Plan includes advanced analytics
}
checkQuota(limitSlug, increment?)
Check quota for a specific limit.
checkQuota(limitSlug: string, increment?: number): {
allowed: boolean
remaining: number
}
Example:
const quota = membership.checkQuota('projects', 1)
if (!quota.allowed) {
// Quota would be exceeded
console.log(`Only ${quota.remaining} projects remaining`)
}
canPerformAction(action, options?)
Comprehensive authorization check.
canPerformAction(
action: string,
options?: { incrementQuota?: number }
): ActionResult
Checks performed (in order):
- Membership - user has a role
- Subscription status - active or trialing
- Permission - RBAC check
- Feature - plan-based (if mapped)
- Quota - usage limits (if mapped)
Example:
const result = membership.canPerformAction('customers.create')
if (!result.allowed) {
return Response.json({
error: result.message,
reason: result.reason,
meta: result.meta,
}, { status: 403 })
}
// Proceed with action
Types
MembershipSubscription
interface MembershipSubscription {
id: string
planSlug: string
planName: string
status: 'active' | 'trialing' | 'past_due' | 'canceled' | 'paused' | 'expired'
trialEndsAt: Date | null
currentPeriodEnd: Date | null
}
QuotaState
interface QuotaState {
used: number
limit: number
unlimited: boolean
remaining: number
}
ActionResult
type ActionResult =
| { allowed: true }
| {
allowed: false
reason: ActionDeniedReason
message: string
meta?: Record<string, unknown>
}
type ActionDeniedReason =
| 'not_member'
| 'permission_denied'
| 'feature_disabled'
| 'quota_exceeded'
| 'subscription_inactive'
Complete Example
import { MembershipService } from '@/core/lib/services'
export async function POST(req: Request) {
const { userId, teamId } = await getAuthContext(req)
// Get membership context
const membership = await MembershipService.get(userId, teamId)
// Check if action is allowed
const result = membership.canPerformAction('customers.create')
if (!result.allowed) {
return Response.json({
success: false,
error: result.message,
reason: result.reason,
meta: result.meta,
}, { status: 403 })
}
// Check specific quota (optional)
const quota = membership.checkQuota('customers', 1)
if (!quota.allowed) {
return Response.json({
success: false,
error: 'Customer limit reached',
reason: 'quota_exceeded',
meta: { remaining: quota.remaining },
}, { status: 403 })
}
// Proceed with creation
const customer = await createCustomer(data)
return Response.json({ success: true, data: customer })
}