Skip to content

Authorization & Permissions

ระบบสิทธิ์ใช้โมเดล 3-tier role + per-module permission overlay

3-Tier Role Hierarchy

จาก User.role (default operator):

superadmin                    ← bypass ทุกอย่าง


admin                         ← bypass ทุกอย่าง


manager / supervisor /        ← role-based + per-module (สำหรับ admin portal)
operator / viewer
Roleคำอธิบายขอบเขต
superadminผู้ดูแลระบบสูงสุดทุก action ทุก tenant
adminผู้ดูแล tenantทุก action ใน tenant ตัวเอง
managerผู้จัดการคลังapproval, override, settings (จำกัด)
supervisorหัวหน้างานสร้าง/แก้ไข operation records
operatorพนักงานคลังบันทึก task ที่ assign (pick/putaway)
viewerผู้อ่านอย่างเดียวview dashboard + reports

Per-Module Permissions

นอกเหนือจาก role — User มี 2 columns พิเศษ:

prisma
adminModules       String[] @default([]) @map("admin_modules")        // READ
adminModulesWrite  String[] @default([]) @map("admin_modules_write")  // WRITE

Write implies Read — ถ้ามี write access จะอ่านได้อัตโนมัติ

ตัวอย่างผู้ใช้:

json
{
  "role": "manager",
  "adminModules": ["users", "audit", "reports.inventory"],
  "adminModulesWrite": ["users"]
}

→ manager คนนี้:

  • Read+Write users
  • Read audit, reports.inventory
  • ไม่มีสิทธิ์เปิด module อื่น ๆ ใน Admin Portal

RolesGuard Logic

จาก apps/api/src/modules/auth/guards/roles.guard.ts:

typescript
canActivate(context): boolean {
  const requiredRoles = reflector.getAllAndOverride(ROLES_KEY, ...);
  const requiredModule = reflector.getAllAndOverride(REQUIRE_MODULE_KEY, ...);

  // 1. No metadata → allow
  if (!requiredRoles?.length && !requiredModule) return true;

  const { user } = request;
  if (!user) throw new ForbiddenException();

  // 2. Admin / superadmin → bypass
  if (user.role === 'admin' || user.role === 'superadmin') return true;

  // 3. @Roles check
  if (requiredRoles?.includes(user.role)) return true;

  // 4. @RequireModule check
  if (requiredModule) {
    const reads = user.adminModules || [];
    const writes = user.adminModulesWrite || [];

    if (requiredModule.level === 'write') {
      if (writes.includes(requiredModule.moduleName)) return true;
    } else { // 'read'
      if (reads.includes(requiredModule.moduleName) ||
          writes.includes(requiredModule.moduleName)) return true;
    }
  }

  throw new ForbiddenException('Access denied. Required: ...');
}

ลำดับสำคัญ — admin role ชนะทุกอย่าง ไม่ต้องเช็ค modules

Decorators

@Roles('manager', 'supervisor')

อนุญาตเฉพาะ role ที่ระบุ (+ admin/superadmin โดยอัตโนมัติ)

typescript
@Get('approvals')
@Roles('manager', 'admin')
findPending() { ... }

@RequireModule(moduleName, level)

ต้องการ permission key — level คือ 'read' หรือ 'write'

typescript
@Post()
@RequireModule('users', 'write')
create(@Body() dto: CreateUserDto) { ... }

@Get()
@RequireModule('users', 'read')
list() { ... }

ใช้ได้ทั้ง class-level (ทุก endpoint ของ controller) หรือ method-level

@Public()

bypass JwtAuthGuard — สำหรับ /auth/login, /health/*

@CurrentUser() (param decorator)

extract request.user:

typescript
@Get('me')
me(@CurrentUser() user) { return user; }

@ApiKey() + @ApiKeyScopes('write')

สำหรับ integration controller — extract request.apiKey + enforce scope

API Key Scopes

จาก ApiKey.scopes: String[]:

Scopeสิทธิ์
readGET endpoints (inquiry)
writePOST / PATCH (upsert master, สร้าง orders)
adminsuper-scope — ผ่านทุก scope check

ตั้งตอนสร้าง key ใน Admin Portal → API Keys

Admin Management Protection

UsersService.assertCanManageTarget(actor, target) — ป้องกัน:

  • Non-admin แก้ admin
  • Admin tenant A แก้ user ของ tenant B
  • ใครก็ตามทำ self-demotion สุดท้าย admin คนเดียวออก

(เช็คใน service layer ก่อน update/delete)

Module Catalog

รายการ module keys ทั้งหมดที่ใช้ใน adminModules / adminModulesWrite:

Core

Keyหน้า Admin
dashboardDashboard
usersUsers
rolesRoles
warehousesWarehouses

Master Data

Keyหน้า
master-data.itemsItems
master-data.locationsLocations
master-data.uomsUoMs
master-data.partnersPartners

Operations

Keyหน้า
inbound.asnASN
inbound.grnGRN
inbound.putaway-rulesPutaway Rules
outbound.ordersOrders
outbound.wavesWaves
outbound.pick-tasksPick Tasks
outbound.shipmentsShipments
inventory.stockStock
inventory.movementsMovements
inventory.adjustmentsAdjustments
inventory.cycle-countsCycle Counts
returns.rmaRMA
lpnLicense Plates
replenishment.rulesReplenishment Rules
replenishment.tasksReplenishment Tasks
approvalsApprovals

System

Keyหน้า
auditAudit Logs
announcementsAnnouncements
api-keysAPI Keys
webhooksWebhooks
wms-settingsWMS Settings (8 tabs)
global-configGlobal Config
healthSystem Health

Reports

Keyหน้า
reports.inventoryInventory Reports
reports.receivingReceiving Reports
reports.outboundOutbound Reports
reports.deliveryDelivery Reports
reports.usersUser Reports

ดู workflow การตั้ง permission: Per-Module Permissions

เผยแพร่ภายใต้ Digital Outsourcing