- JWT authentication with Supabase integration - Role-based access control (Admin, Owner, Staff, Auditor) - Universal database adapter (Prisma/Supabase/MongoDB support) - User management with hierarchical permissions - Redis caching service (configured but optional) - Comprehensive API documentation - Production-ready NestJS architecture - Migration scripts for provider switching - Swagger/OpenAPI documentation
3.3 KiB
3.3 KiB
Adding a MANAGER Role - Complete Example
1. Update Types
// src/shared/types/index.ts
export enum UserRole {
SYSTEM_ADMIN = 'SYSTEM_ADMIN',
BUSINESS_OWNER = 'BUSINESS_OWNER',
MANAGER = 'MANAGER', // ← NEW
STAFF = 'STAFF',
AUDITOR = 'AUDITOR',
}
2. Update Role Constants
// src/shared/constants/roles.ts
export const ROLE_HIERARCHY = {
[UserRole.SYSTEM_ADMIN]: 4,
[UserRole.BUSINESS_OWNER]: 3,
[UserRole.MANAGER]: 2.5, // ← NEW (between business owner and staff)
[UserRole.STAFF]: 2,
[UserRole.AUDITOR]: 1,
};
export const ROLE_PERMISSIONS = {
// ... existing roles
[UserRole.MANAGER]: [
'manage_team_receipts',
'view_team_reports',
'verify_receipts',
'manage_staff_schedules', // ← NEW PERMISSIONS
],
};
3. Update Database Schema
// prisma/schema.prisma
enum UserRole {
SYSTEM_ADMIN
BUSINESS_OWNER
MANAGER // ← ADD
STAFF
AUDITOR
}
4. Add Manager-Specific Endpoints
// src/features/users/users.controller.ts
@Get('my-team')
@Roles(UserRole.MANAGER, UserRole.BUSINESS_OWNER, UserRole.SYSTEM_ADMIN)
@ApiOperation({ summary: 'Get team members (Manager access)' })
async getMyTeam(@CurrentUser() user: any) {
return this.usersService.getTeamByManager(user.id);
}
@Post('assign-staff')
@Roles(UserRole.MANAGER, UserRole.BUSINESS_OWNER)
@ApiOperation({ summary: 'Assign staff to manager' })
async assignStaff(@Body() assignDto: AssignStaffDto) {
return this.usersService.assignStaffToManager(assignDto);
}
5. Update Service Logic
// src/features/users/users.service.ts
async getUsers(currentUserId: string, currentUserRole: UserRole) {
// ... existing logic
if (currentUserRole === UserRole.MANAGER) {
// Managers see their assigned team
const teamMembers = await this.supabaseDb.getUsersByManager(currentUserId);
const currentUser = await this.supabaseDb.findUserById(currentUserId);
return currentUser ? [currentUser, ...teamMembers] : teamMembers;
}
// ... rest of logic
}
async getTeamByManager(managerId: string): Promise<User[]> {
return this.supabaseDb.findUsers({
manager_id: managerId,
is_active: true
});
}
6. Database Migration
-- Add new role to enum
ALTER TYPE "UserRole" ADD VALUE 'MANAGER';
-- Add manager_id column to users table (optional)
ALTER TABLE users ADD COLUMN manager_id UUID REFERENCES users(id);
-- Create index for manager relationships
CREATE INDEX idx_users_manager_id ON users(manager_id);
7. Update DTOs
// src/features/users/dto/user.dto.ts
export class CreateStaffDto {
@ApiProperty({
description: 'Staff role',
enum: [UserRole.STAFF, UserRole.AUDITOR, UserRole.MANAGER], // ← ADD MANAGER
example: UserRole.STAFF,
})
@IsEnum([UserRole.STAFF, UserRole.AUDITOR, UserRole.MANAGER])
role: UserRole.STAFF | UserRole.AUDITOR | UserRole.MANAGER;
@ApiPropertyOptional({
description: 'Manager ID (for staff assignments)',
})
@IsOptional()
@IsUUID()
managerId?: string;
}
Result: Fully Functional Manager Role
- ✅ Hierarchical permissions (can access staff endpoints)
- ✅ Manager-specific endpoints
- ✅ Team management capabilities
- ✅ Database relationships
- ✅ Type safety maintained
- ✅ API documentation updated