feat: org admin can create chapter (tenant) admins
Add POST /org/tenants/:id/admins so org admins can provision the first login for a chapter's admin team. New chapter admins can then sign in at /login with email + password. - OrgService.createTenantAdmin — validates chapter belongs to org, hashes password, creates Admin record - OrgController POST tenants/:id/admins endpoint - BFF route /api/org/tenants/[id]/admins - Add Admin form on /org/tenants/[id] page (email, password, role select) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,15 @@ export class OrgController {
|
||||
return this.orgService.getTenant(admin.organizationId, id);
|
||||
}
|
||||
|
||||
@Post('tenants/:id/admins')
|
||||
createTenantAdmin(
|
||||
@CurrentOrgAdmin() admin: OrgAdminJwtPayload,
|
||||
@Param('id') id: string,
|
||||
@Body() body: { email: string; password: string; role?: string },
|
||||
) {
|
||||
return this.orgService.createTenantAdmin(admin.organizationId, id, body.email, body.password, body.role);
|
||||
}
|
||||
|
||||
@Get('rules')
|
||||
getRules(@CurrentOrgAdmin() admin: OrgAdminJwtPayload) {
|
||||
return this.orgService.getRules(admin.organizationId);
|
||||
|
||||
@@ -162,4 +162,26 @@ export class OrgService {
|
||||
if (!rule) throw new NotFoundException('Rule not found');
|
||||
await this.prisma.orgRule.delete({ where: { id: ruleId } });
|
||||
}
|
||||
|
||||
async createTenantAdmin(
|
||||
organizationId: string,
|
||||
tenantId: string,
|
||||
email: string,
|
||||
password: string,
|
||||
role?: string,
|
||||
) {
|
||||
const tenant = await this.prisma.tenant.findFirst({ where: { id: tenantId, organizationId } });
|
||||
if (!tenant) throw new NotFoundException('Chapter not found or does not belong to this org');
|
||||
|
||||
const existing = await this.prisma.admin.findUnique({
|
||||
where: { tenantId_email: { tenantId, email } },
|
||||
});
|
||||
if (existing) throw new ConflictException('An admin with this email already exists for this chapter');
|
||||
|
||||
const passwordHash = await bcrypt.hash(password, 10);
|
||||
return this.prisma.admin.create({
|
||||
data: { tenantId, email, passwordHash, ...(role ? { role: role as any } : {}) },
|
||||
select: { id: true, email: true, role: true, createdAt: true },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user