داستان خیلی ساده نقش‌ها و دسترسی‌ها

این صفحه عمداً فنی نوشته نشده. هدفش این است که مدیر محصول، فرانت‌اند و حتی کسی که تازه پروژه را دیده، دقیقاً بفهمد چه اتفاقی می‌افتد.


داستان از کجا شروع شد؟

ما در اتوماسیون، فقط یک «منشی» ثابت نمی‌خواستیم. چون در دنیای واقعی دفتر املاک، آدم‌ها شغل‌های مختلف دارند: منشی، CRM، پشتیبانی، مدیر داخلی و هر نقش دیگری که بعداً ممکن است اضافه شود.

پس سیستم را این‌طور ساختیم: اول «نوع کاربر» را مشخص می‌کنیم، بعد اگر کاربر از نوع staff بود، یک «نقش سازمانی» به او می‌دهیم، و آن نقش تعیین می‌کند چه بخش‌هایی را ببیند یا تغییر بدهد.

خلاصه خیلی کوتاه:
ادمین همه‌چیز را می‌بیند.
کارمند/مشاور فقط چیزهایی را می‌بیند که نقشش اجازه داده.
مشاور مثل قبل با منطق ملک‌های خودش کار می‌کند.
سه تکه اصلی سیستم
اسم سادهدر سیستم چیست؟مثال
نوع کاربر User.role admin، staff، agent
نقش سازمانی StaffRole منشی، CRM، پشتیبانی
دسترسی AccessPermission دیدن لیست ملک، مدیریت شهر، حذف ملک

یعنی در عمل این اتفاق می‌افتد:

کاربر = staff
    ↓
نقش سازمانی = مثلاً "منشی"
    ↓
دسترسی‌های این نقش = مثلاً:
  - دیدن لیست ملک
  - ثبت ملک
  - دیدن مشاوران
  - نداشتن دسترسی حذف ملک
یک مثال واقعی

فرض کنید «مریم» کارمند جدید دفتر است. شما در پنل مدیریت برایش نقش «منشی» را انتخاب می‌کنید. نقش منشی از قبل چند دسترسی دارد: دیدن لیست ملک، ثبت ملک، دیدن مشاوران و مثلاً دیدن شهرها.

حالا وقتی مریم وارد فرانت می‌شود، فرانت از بک‌اند می‌پرسد: «این کاربر کیست و چه اجازه‌هایی دارد؟»

بک‌اند جواب می‌دهد:

{
  "role": "staff",
  "staff_role": {
    "id": 1,
    "code": "secretary",
    "title": "منشی"
  },
  "permissions": [
    "properties.list.view",
    "properties.create",
    "agents.view"
  ]
}

فرانت این را می‌خواند و تصمیم می‌گیرد: منوی «لیست املاک» را نشان بده، دکمه «ثبت ملک» را نشان بده، اما دکمه «حذف ملک» را نشان نده.

پس فرانت باید چه فکری بکند؟

فرانت نباید با خودش بگوید «اگر user منشی بود این دکمه را نشان بدهم». فرانت باید بگوید: «اگر این permission را داشت، این دکمه را نشان می‌دهم».

این مهم‌ترین نکته برای فرانت است:
UI را بر اساس permissions[] بسازید، نه فقط بر اساس اسم نقش.
روایت خیلی ساده استفاده در فرانت
  1. کاربر لاگین می‌کند.
  2. فرانت بلافاصله GET /auth/me/ را صدا می‌زند.
  3. پاسخ شامل role، staff_role و permissions است.
  4. فرانت این اطلاعات را در state/context نگه می‌دارد.
  5. هر صفحه و هر دکمه قبل از نمایش، permission لازم خودش را چک می‌کند.
  6. اگر permission نبود، یا آیتم را مخفی می‌کند یا disabled نشان می‌دهد.
  7. اگر کاربر با زور URL رفت، بک‌اند باز هم چک می‌کند و در صورت نداشتن دسترسی، 403 می‌دهد.
صفحه مدیریت نقش‌ها در فرانت باید چطور باشد؟

دقیقاً همان چیزی که گفتی: کاملاً گرافیکی. یعنی مدیر سیستم نباید کد بنویسد یا با اسم‌های سخت درگیر شود.

فرانت می‌تواند یک فرم خیلی ساده داشته باشد:

  1. نام نقش: مثلاً «منشی شیفت صبح»
  2. کد نقش: مثلاً morning_secretary
  3. لیست دسته‌بندی‌شده دسترسی‌ها
  4. کنار هر دسترسی یک checkbox
  5. دکمه ذخیره

مثلاً در UI:

بخشدسترسی‌ها
املاک مشاهده لیست
ثبت ملک
حذف ملک
شهرها مشاهده شهرها
مدیریت شهرها

البته این checkboxها در داک فقط برای تصویر ذهنی هستند. در فرانت واقعی باید داده‌ها را از GET /auth/permissions/ بگیرید و group-by ماژول نمایش دهید.

فرانت برای ساخت نقش چه می‌کند؟

وقتی مدیر سیستم در UI چند checkbox را تیک زد، فرانت لیست permissionهای انتخاب‌شده را جمع می‌کند و به بک‌اند می‌فرستد.

{
  "code": "support",
  "title": "پشتیبانی",
  "description": "پاسخگویی تلفنی",
  "permission_codes": [
    "properties.list.view",
    "properties.detail.view",
    "properties.owners.view"
  ]
}

این درخواست به این endpoint می‌رود:

POST /auth/roles/
فرانت برای دادن نقش به کارمند چه می‌کند؟

در فرم ساخت یا ویرایش کارمند، یک select برای نقش سازمانی می‌گذاری. گزینه‌های این select از GET /auth/roles/ می‌آید.

بعد موقع ذخیره کارمند:

{
  "phonenumber": "09123334455",
  "password": "Pass12345",
  "first_name": "مریم",
  "last_name": "کریمی",
  "personnel_code": "S-12",
  "organizational_role_id": 1
}

یعنی به زبان ساده: «این کارمند، نقش منشی را دارد».

ساده‌ترین الگوی کدنویسی در فرانت
function can(user, permissionCode) {
  if (user?.is_system_admin) return true;
  return (user?.permissions || []).includes(permissionCode);
}

const me = await fetch('/auth/me/', {
  headers: { Authorization: `Bearer ${accessToken}` },
}).then((r) => r.json());

if (can(me, 'properties.create')) {
  // دکمه ثبت ملک را نشان بده
}

if (can(me, 'properties.cities.manage')) {
  // منوی مدیریت شهرها را نشان بده
}
الان دقیقاً چه چیزهایی آماده شده؟
  • مدل نقش سازمانی برای staff ساخته شده.
  • مدل دسترسی‌های ریزدانه‌ای ساخته شده.
  • دو نقش پیش‌فرض secretary و crm ساخته می‌شوند.
  • API برای لیست دسترسی‌ها و ساخت/ویرایش نقش‌ها آماده است.
  • /auth/me/ حالا دسترسی‌های موثر کاربر را برمی‌گرداند.
  • بخش‌هایی از املاک، staff و agents به این RBAC وصل شده‌اند.
سفر مدیر سیستم در یک نگاه
  1. مدیر سیستم وارد پنل مدیریت فرانت می‌شود.
  2. یک نقش جدید می‌سازد: مثلاً «پشتیبانی».
  3. در صفحه نقش‌ها، چند دسترسی را با checkbox انتخاب می‌کند.
  4. نقش را ذخیره می‌کند.
  5. وارد صفحه کارمندان یا مشاوران می‌شود.
  6. برای یک نفر، نقش «پشتیبانی» را انتخاب می‌کند.
  7. آن کاربر از این لحظه فقط همان بخش‌ها را می‌بیند.
کاتالوگ فعلی دسترسی‌ها
کدمعنی ساده
properties.list.viewدیدن لیست املاک
properties.detail.viewدیدن جزئیات ملک
properties.createثبت ملک
properties.editویرایش ملک
properties.deleteحذف ملک
properties.cities.viewدیدن شهرها
properties.cities.manageمدیریت شهرها
properties.locations.viewدیدن مناطق
properties.locations.manageمدیریت مناطق
properties.types.viewدیدن انواع ملک
properties.types.manageمدیریت انواع ملک
properties.owners.viewدیدن مالک‌ها
properties.owners.manageمدیریت مالک‌ها
agents.viewدیدن مشاوران
agents.manageمدیریت مشاوران
staff.viewدیدن کارمندان
staff.manageمدیریت کارمندان
roles.viewدیدن نقش‌ها
roles.manageمدیریت نقش‌ها
crm.viewدیدن CRM
crm.manageمدیریت CRM
APIهای مهم برای فرانت
کارآدرسچه زمانی استفاده می‌شود؟
تشخیص کاربر جاریGET /auth/me/بعد از login
لیست همه دسترسی‌هاGET /auth/permissions/صفحه ساخت/ویرایش نقش
لیست نقش‌هاGET /auth/roles/صفحه کارمندان و صفحه نقش‌ها
ساخت نقشPOST /auth/roles/وقتی مدیر نقش جدید می‌سازد
ویرایش نقشPATCH /auth/roles/<id>/وقتی تیک‌ها تغییر می‌کنند
ساخت کارمند با نقشPOST /staff/وقتی ادمین کارمند جدید می‌سازد
ساخت مشاور با نقشPOST /agents/وقتی ادمین مشاور جدید می‌سازد
نقش‌های پیش‌فرض موجود
کدعنوانتوضیح ساده
secretary منشی می‌تواند لیست ملک را ببیند، ملک ثبت کند، بعضی اطلاعات پایه را ببیند و مشاوران را ببیند.
crm کارشناس CRM برای بخش CRM آماده شده و فعلاً دسترسی‌های مرتبط اولیه را دارد.
اگر خواستی کاتالوگ و نقش‌های پیش‌فرض را دوباره بسازی
python manage.py sync_rbac --roles
اگر بعداً ماژول جدید اضافه شد چه؟

مثلاً فردا ماژول «گزارش‌ها» یا «مالی» اضافه شد. لازم نیست سیستم را از نو بنویسیم. فقط permissionهای جدید را تعریف می‌کنیم، در صفحه نقش‌ها checkboxهای جدید ظاهر می‌شوند، و مدیر سیستم تصمیم می‌گیرد چه نقشی آن‌ها را داشته باشد.

یعنی کل سیستم برای توسعه آینده طراحی شده، نه فقط برای منشی و CRM امروز.

اگر کاربر دسترسی نداشت چه می‌شود؟
  • در فرانت بهتر است آیتم را نشان ندهید یا غیرفعال کنید.
  • اگر کاربر با URL مستقیم یا درخواست دستی جلو برود، بک‌اند 403 می‌دهد.
  • اگر توکن نداشته باشد، 401 می‌گیرد.
جمع‌بندی یک‌خطی

در این سیستم، مدیر با چند checkbox نقش می‌سازد، نقش را به کارمند می‌دهد، و فرانت هم فقط با نگاه کردن به permissions[] می‌فهمد چه چیزی را باید نشان بدهد.