Files
clinicpro/.claude/prompt/admin-spa-adapt-backend-audit.md
T
hamedandClaude Opus 4.8 2f3f25f48e fix(admin): paginate claims & settlement lists for backend-audit 50-cap
GET /billing/claims and GET /settlement now return only the first 50 rows by
default (data.data unchanged, data.meta added). ClaimsPage and
RepresentationSettlementPage read the full array with no pager, so rows beyond 50
were unreachable. Add page state + ?page/limit + the existing <Pagination>
(reading data.meta.totalRecords).

No change needed for: 422 on claim approve/pay (api.ts already surfaces the
backend message via toast; the admin UI sends no amount so it's unreachable),
the owner-only appointment-settings endpoints (admin user bypasses), and refresh
rotation (authStore.refresh already persists the rotated refresh_token).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:49:44 +03:30

8.6 KiB
Raw Blame History

تطبیق Admin SPA با تغییرات API برنچ backend-audit

پروژه

clinicpro (Admin SPA — assets/admin/). پرامپت همتا برای سایت عمومی: nobat724_front/.claude/prompt/adapt-backend-audit-api.md.

زمینه

برنچ backend-audit (۳۳ commit) چند endpoint را تغییر داد. مقدارهای wire خطاها حفظ شده‌اند (M21)، ولی چند لیست حالا صفحه‌بندی شده‌اند (پیش‌فرض ۵۰ ردیف، قبلاً همه) و یک data.meta افزوده‌اند، و تعدادی مسیر سخت‌گیری امنیتی جدید دارند. این پرامپت فقط مصرف‌کننده‌های Admin SPA را اصلاح می‌کند.

پاکت پاسخ این لیست‌ها ($this->success(['data' => $rows, 'meta' => ...])) به این شکل است:

{ "success": true, "data": { "data": [ /* ردیف‌ها */ ], "meta": { "totalRecords": 124, "totalPages": 3, "currentPage": 1 } } }

یعنی data.data (آرایه) دست‌نخورده است — خواندن فعلی نمی‌شکند — اما حالا فقط ۵۰ ردیف اول برمی‌گردد مگر اینکه ?page/?limit بفرستی. بدون اصلاح، کاربر ادمین بقیه‌ی ردیف‌ها را نمی‌بیند.

جدول کامل تغییرات API (همه‌ی endpointهای تغییریافته)

Endpoint تغییر مصرف در Admin SPA اقدام
GET /api/v1/billing/claims صفحه‌بندی + data.meta، پیش‌فرض ۵۰ pages/ClaimsPage.tsx صفحه‌بندی اضافه شود
GET /api/v1/settlement صفحه‌بندی + data.meta، پیش‌فرض ۵۰ pages/RepresentationSettlementPage.tsx صفحه‌بندی اضافه شود
GET /api/v1/wallet/transactions صفحه‌بندی + ?page + data.meta، پیش‌فرض ۵۰ مصرف نمی‌شود (فقط tauri)
GET /api/v1/admin/comments/pending صفحه‌بندی + data.meta، پیش‌فرض ۵۰ مصرف نشد (تأیید کن) اگر صفحه‌ای دارد، صفحه‌بندی اضافه شود
`POST /api/v1/billing/claims/{uuid}/{approve pay}` اگر approved_rials/paid_rials خارج بازه باشد → 422 (field در پاسخ) ClaimsPage.tsx transitionMut
GET /api/v1/appointment-settings/available-locations/{uuid} حالا فقط owner doctor یا ROLE_ADMIN (وگرنه 403) pages/DoctorDetailPage.tsx بدون اصلاح — کاربر ادمین bypass دارد (مستند شود)
GET /api/v1/appointment-settings/date-override/list/{uuid} همان — owner/admin DoctorDetailPage.tsx بدون اصلاح (admin bypass)
GET /api/v1/appointment-settings/holidays/list/{uuid} همان — owner/admin DoctorDetailPage.tsx بدون اصلاح (admin bypass)
GET /api/v1/insurance/{id} حالا owner/admin (403) مصرف نشد
GET /api/v1/clinic-pro/doctor-address/{id} حالا owner/admin (403) مصرف نشد (تأیید کن)
POST /api/v1/pre-registration 200 → 201 اگر مصرف دارد، چک کن res.ok/2xx باشد نه === 200 تأیید
کدهای خطای legacy (M21) مقدار wire بدون تغییر (SLOT_TAKEN, VALIDATION, …) بدون اصلاح

همه‌ی اصلاح‌های دیگر برنچ (N+1، unique، integrity) خروجی API را تغییر نداده‌اند.

فایل‌های مرتبط

فایل نقش
assets/admin/pages/ClaimsPage.tsx لیست مطالبات بیمه — اکنون ۵۰-cap
assets/admin/pages/RepresentationSettlementPage.tsx لیست تسویه‌ها — اکنون ۵۰-cap
assets/admin/pages/DoctorDetailPage.tsx فقط مستندسازی (admin bypass)
assets/admin/lib/api.ts ApiResponse/PaginatedResponse types
assets/admin/components/ui/Pagination کامپوننت صفحه‌بندی موجود

وضعیت فعلی (کد واقعی)

ClaimsPage.tsx — بدون صفحه‌بندی، فقط data.data.data

const claimsQuery = useQuery<{ data: { data: Claim[] } }>({
  queryKey: ['claims', queryString],
  queryFn: () => api.get(`/api/v1/billing/claims${queryString}`),
});
// ...
const claims = (claimsQuery.data as any)?.data?.data ?? [];

const transitionMut = useMutation({
  mutationFn: ({ uuid, action, body }) =>
    api.post(`/api/v1/billing/claims/${uuid}/${action}`, body ?? {}),
  onError: (e: Error) => toast.error(e.message),   // ۴۲۲ جدید اینجا نمایش داده می‌شود
});

queryString از فیلترهای موجود (status, insurance_id, from, to, q) ساخته می‌شود ولی page/limit ندارد.

RepresentationSettlementPage.tsx — بدون صفحه‌بندی

const { data } = useQuery({
  queryKey: ['settlements'],
  queryFn: () => api.get<ApiResponse<SettlementRow[]>>('/api/v1/settlement'),
});
// data.data خوانده می‌شود به‌عنوان آرایه

وظایف

۱. ClaimsPage — افزودن صفحه‌بندی

  • یک page state اضافه کن (پیش‌فرض ۱) و آن را به queryString تزریق کن (p.set('page', String(page))). page را در queryKey بگذار تا refetch شود.
  • total را از پاسخ بخوان: const total = (claimsQuery.data as any)?.data?.meta?.totalRecords ?? 0;
  • کامپوننت <Pagination> موجود را زیر جدول مطالبات با total/page/onPageChange رندر کن (الگوی بقیه‌ی صفحه‌های لیست admin).
  • وقتی فیلترها عوض شد، page را به ۱ برگردان.
const [page, setPage] = useState(1);
// queryString: const s = p.toString(); p.set('page', String(page)); ...
const total = (claimsQuery.data as any)?.data?.meta?.totalRecords ?? 0;
// <Pagination currentPage={page} totalRecords={total} onPageChange={setPage} />

۲. ClaimsPage — هندل خطای ۴۲۲ روی approve/pay

اکنون اگر approved_rials > total_claimed_rials یا paid_rials > total_approved_rials (یا منفی) باشد، پاسخ 422 با errors[0].field (approved_rials/paid_rials) است. onError فعلی فقط e.message را toast می‌کند — کافی است، ولی مطمئن شو پیام فارسی backend («مبلغ تأییدشده باید بین ۰ و مبلغ مطالبه‌شده باشد») به کاربر نشان داده می‌شود (نه «خطای ناشناخته»). اگر فرم مبلغ دارد، خطا را کنار فیلد مربوطه با استفاده از field نشان بده.

۳. RepresentationSettlementPage — افزودن صفحه‌بندی

مثل ClaimsPage: page state + ?page= در URL + خواندن data.meta.totalRecords + <Pagination>. خواندن data.data به‌عنوان آرایه دست‌نخورده می‌ماند.

۴. تأیید عدم مصرف

با grep تأیید کن Admin SPA این‌ها را مصرف نمی‌کند (اگر می‌کند، همان الگوی صفحه‌بندی را اعمال کن): /api/v1/wallet/transactions، /api/v1/admin/comments/pending، /api/v1/clinic-pro/doctor-address/، /api/v1/insurance/{id} (GET تکی).

۵. مستندسازی (بدون تغییر کد)

در صفحه‌ی DoctorDetailPage.tsx این سه endpoint حالا owner-or-admin‌اند: available-locations، date-override/list، holidays/list. چون کاربر Admin SPA همیشه ROLE_ADMIN است، bypass دارد و چیزی نمی‌شکند — فقط در صورت اضافه‌شدن نقش‌های غیرادمین به این صفحه در آینده حواست باشد.

نکات مهم

  • پاکت پاسخ این لیست‌ها double-nest است: آرایه در data.data، متادیتا در data.meta. (نه PaginatedResponse<T> که data را آرایه‌ی تخت می‌گیرد — این endpointها از success(['data'=>..., 'meta'=>...]) استفاده می‌کنند، نه paginated().)
  • پیش‌فرض limit سمت backend ۵۰، حداکثر ۱۰۰ است؛ page ۱-based.
  • از کامپوننت <Pagination> و <DataTable> موجود استفاده کن؛ کتابخانه‌ی جدید اضافه نکن؛ RTL.
  • تاریخ‌ها Unix timestamp؛ نمایش با formatDate() شمسی.
  • بعد از تغییر، با ddev exec yarn dev بیلد را چک کن (خطاهای TS فقط در خروجی tsc ظاهر می‌شوند).