Add opt-in roll_call business module gate.

Keeps Roll Call off by default and blocks the API until super-admin enables it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-10-07 14:15:43 +03:30
co-authored by Cursor
parent a6c2d4764e
commit 3558c441b9
2 changed files with 27 additions and 1 deletions
@@ -245,6 +245,7 @@ export const BUSINESS_DASHBOARD_MODULE_IDS = [
'workshops',
'finance',
'multilanguage_data',
'roll_call',
] as const;
/** Optional customer-dashboard modules. Always-on: home, profile, addresses, orders, favorites. */
@@ -352,7 +353,8 @@ export const DEFAULT_ENABLED_BUSINESS_MODULES: BusinessModuleId[] =
(id) =>
id !== 'workshops' &&
id !== 'multilanguage_data' &&
id !== 'store_installments',
id !== 'store_installments' &&
id !== 'roll_call',
);
export const DEFAULT_HOME_CHARTS: [HomeChartId, HomeChartId] = [
+24
View File
@@ -8,6 +8,7 @@ import {
import { Prisma, RollCall, RollCallTask } from '@prisma/client';
import { AuthUser } from '../auth/auth.types';
import { PermissionsService } from '../auth/permissions.service';
import { normalizeBusinessSettings } from '../business-settings/business-settings.util';
import { PrismaService } from '../prisma/prisma.service';
import {
CreateRollCallDto,
@@ -26,6 +27,7 @@ export class RollCallsService {
async list(businessIdRaw: string, query: ListRollCallsDto, actor: AuthUser) {
const businessId = BigInt(businessIdRaw);
await this.assertModuleEnabled(businessId);
await this.assertPermission(businessId, actor.id, 'roll_calls.read');
const page = query.page ?? 1;
@@ -83,6 +85,7 @@ export class RollCallsService {
actor: AuthUser,
) {
const businessId = BigInt(businessIdRaw);
await this.assertModuleEnabled(businessId);
await this.assertPermission(businessId, actor.id, 'roll_calls.read');
const rollCall = await this.findOwnedOrThrow(
businessId,
@@ -98,6 +101,7 @@ export class RollCallsService {
actor: AuthUser,
) {
const businessId = BigInt(businessIdRaw);
await this.assertModuleEnabled(businessId);
await this.assertPermission(businessId, actor.id, 'roll_calls.create');
const workDate = this.parseWorkDate(dto.workDate);
@@ -147,6 +151,7 @@ export class RollCallsService {
actor: AuthUser,
) {
const businessId = BigInt(businessIdRaw);
await this.assertModuleEnabled(businessId);
await this.assertPermission(businessId, actor.id, 'roll_calls.update');
const rollCallId = BigInt(rollCallIdRaw);
await this.findOwnedOrThrow(businessId, actor.id, rollCallId);
@@ -213,6 +218,7 @@ export class RollCallsService {
actor: AuthUser,
) {
const businessId = BigInt(businessIdRaw);
await this.assertModuleEnabled(businessId);
await this.assertPermission(businessId, actor.id, 'roll_calls.delete');
const rollCallId = BigInt(rollCallIdRaw);
await this.findOwnedOrThrow(businessId, actor.id, rollCallId);
@@ -321,6 +327,24 @@ export class RollCallsService {
};
}
private async assertModuleEnabled(businessId: bigint) {
const business = await this.prisma.business.findFirst({
where: { id: businessId },
select: { settings: true },
});
if (!business) {
throw new NotFoundException('Business not found');
}
const settings = normalizeBusinessSettings(business.settings);
if (!settings.modules.enabled.includes('roll_call')) {
throw new ForbiddenException(
'Roll call module is not enabled for this business',
);
}
}
private async assertPermission(
businessId: bigint,
userId: bigint,