Files
tehran_taj/docs/ADMIN-TABLE-SPLIT.md
T
s.esmaeiliandClaude Sonnet 5.5 06c8a5f434 feat(auth): split panel admins out of AdminUser into their own Admin table
AdminUser held both panel staff and sales experts, so one mobile could not be
both. Staff now live in "Admin" (panel only); sales experts stay in "AdminUser"
untouched. Uniqueness is per table.

- migration 20261026120000_split_admin_table: additive only. Creates "Admin",
  copies non-expert rows with their ids, re-points the "who did this" foreign
  keys (ledger, order status, sms, notification, upload, allocation, workshop,
  admin session) to "Admin" without moving data. Never writes to "AdminUser".
- login, JWT, SSO, branch/workshop supervisors and the users grid use "Admin";
  SALES_EXPERT create/edit still goes through admin/users into "AdminUser".
- an admin cannot be turned into an expert or the reverse (different tables).
- manual/: optional phase-2 script to drop the dormant admin copies from
  "AdminUser", and a read-only expert-login diagnostic.
- docs/ADMIN-TABLE-SPLIT.md: what changed, deploy checklist, rollback.

Tested on a copy with 12,000 experts: expert rows byte-identical (md5) before
and after; full migration chain applies and matches schema.prisma.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 23:52:33 +03:30

5.6 KiB

جدا شدن جدول ادمین‌ها از کارشناسان فروش

چه چیزی عوض شد

قبل بعد
پرسنل پنل (مدیر ارشد، تأییدکننده، سرپرست کارگاه، حسابدار) جدول AdminUser جدول جدید Admin
کارشناس فروش جدول AdminUser جدول AdminUser (بدون هیچ تغییری)
یکتایی شماره موبایل یک شماره = فقط یک نقش یکتا در هر جدول جدا؛ یک شماره می‌تواند هم ادمین باشد هم کارشناس

ادمین فقط برای پنل است. کارشناس فقط برای اپ‌ها. توکن اپ کارشناس هیچ‌وقت به پنل دسترسی نمی‌دهد (JwtStrategy فقط در Admin می‌گردد).

مایگریشن — 20261026120000_split_admin_table

فقط افزودنی است. به AdminUser (کارشناس‌ها) چیزی نمی‌نویسد، حذف نمی‌کند و قفل نمی‌کند.

  1. جدول Admin را می‌سازد.
  2. ردیف‌های غیرکارشناس AdminUser را با همان id در Admin کپی می‌کند (توکن‌های صادرشده و همهٔ ستون‌های «چه کسی انجام داد» معتبر می‌مانند).
  3. کلید خارجی‌های «ثبت‌کننده» را از AdminUser به Admin منتقل می‌کند. نام ستون‌ها و دیتا عوض نمی‌شود، فقط مقصد constraint: LedgerEntry.postedByAdminUserId، OrderStatusEvent و PreOrderStatusEvent.actorAdminUserId، BranchAllocation.allocatorAdminUserId، SmsMessage و Notification.sentByAdminUserId، UploadedFile.uploadedByAdminUserId، Workshop.supervisorId، AdminSession.adminUserId.
  4. به‌صورت NOT VALID اضافه و بعد validate می‌شوند؛ اگر ردیف قدیمی‌ای به id غیرادمین اشاره کند، deploy شکست نمی‌خورد و فقط یک NOTICE چاپ می‌شود.

بدون تغییر ماندند (چون دربارهٔ کارشناس‌اند): Order.salesAgentId، Customer.referredByAgentId، SalesExpertProfile.adminUserId.

قابل اجرای مجدد است (idempotent).

آزمایش‌شده روی

کپی دیتابیس با ۱۲۰۰۰ کارشناس: چک‌سام (md5) تمام ردیف‌های SALES_EXPERT قبل و بعد از مایگریشن یکسان بود. زنجیرهٔ کامل مایگریشن‌ها روی دیتابیس خالی اجرا شد و prisma migrate diff هیچ اختلافی بین schema.prisma و دیتابیس نشان نداد.

قبل از دیپلوی روی سرور اصلی

  1. از دیتابیس بکاپ بگیرید.
  2. (اختیاری، فقط‌خواندنی) ببینید ردیفی هست که به id غیرادمین اشاره کند؛ برای هر جدول:
-- نمونه برای دفتر حساب؛ برای بقیهٔ جدول‌ها/ستون‌ها همین الگو
SELECT count(*) FROM "LedgerEntry" l
WHERE l."postedByAdminUserId" IS NOT NULL
  AND NOT EXISTS (SELECT 1 FROM "Admin" a WHERE a."id" = l."postedByAdminUserId");

قبل از اجرای مایگریشن Admin هنوز وجود ندارد؛ این کوئری را بعد از دیپلوی بزنید. جواب 0 یعنی همه چیز سالم است. 3. ابتدا مایگریشن (با بوت شدن API جدید خودکار اجرا می‌شود)، سپس همان کد. چون additive است، کد قدیمی در فاصله هم کار می‌کند.

یک محدودیت تا «فاز ۲»

ردیف‌های قدیمی ادمین‌ها در AdminUser باقی می‌مانند (غیرفعال، بدون استفاده در کد). شمارهٔ آن‌ها هنوز در AdminUser قفل است، پس برای ادمین‌های موجود ساختن کارشناس با همان شماره خطای «قبلاً ثبت شده» می‌دهد. (ادمین‌های تازه‌ساخته و شماره‌های جدید مشکلی ندارند.)

برای آزاد کردن آن شماره‌ها، بعد از اطمینان از درستی کار: apps/api/prisma/manual/20261026_remove_dormant_admin_rows.sql — دستی است، عمداً داخل migrations/ نیست، فقط ردیف‌های غیرکارشناس را که در Admin کپی دارند حذف می‌کند، و اگر تعداد کارشناس‌ها یک عدد هم تغییر کند خودش rollback می‌کند.

برگشت (Rollback)

کد قبلی را دوباره deploy کنید. چیزی حذف نشده، پس کد قدیمی همهٔ ادمین‌های پیشین را در AdminUser پیدا می‌کند. ادمین‌هایی که بعد از جدا شدن ساخته شده‌اند فقط در Admin هستند و باید دوباره ساخته شوند.

تغییر رفتار پنل

  • جدول «کاربران» فقط ادمین‌ها را نشان می‌دهد؛ کارشناس‌ها از بخش کارشناسان.
  • نقش «کارشناس فروش» از لیست نقش‌های فرم ادمین حذف شد؛ فرم کارشناس همان POST admin/users را با role: SALES_EXPERT می‌زند و در AdminUser ساخته می‌شود.
  • نقش یک ادمین به کارشناس (و برعکس) قابل تغییر نیست، چون دو جدول جدا هستند.
  • کارشناس دیگر نمی‌تواند با رمز خودش وارد پنل شود (قبلاً چون در همان جدول بود، می‌توانست).