Files
nobat724_front/.claude/prompt/adapt-backend-audit-api.md
T

9.3 KiB

تطبیق سایت عمومی با تغییرات API برنچ backend-audit

حل‌شده (Path A) — هیچ تغییری در nobat724_front لازم نیست. مشکل rotation با نرم‌کردن backend حل شد: در clinicpro (commit روی backend-audit) چرخش/باطل‌سازی single-use از /oauth/token/refresh برداشته شد و توکن refresh دوباره قابل‌استفاده شد (فقط چک کاربر معلق status!=1 باقی ماند). پس lib/serverToken.js بدون تغییر کار می‌کند. تنها نکته‌ی باقی‌مانده اختیاری است: ۵۰-cap نظرات (وظیفه ۲ پایین) — اگر ۵۰ نظر کافی است، کاری لازم نیست.

پروژه

nobat724_front (سایت عمومی). پرامپت همتا برای Admin SPA: clinicpro/.claude/prompt/admin-spa-adapt-backend-audit.md. منبع تغییرات: برنچ backend-audit در clinicpro (۳۳ commit).

زمینه

ممیزی بک‌اند چند endpoint را تغییر داد. مقدارهای wire کدهای خطا حفظ شده‌اند، ولی یک تغییر رفتارِ شکننده برای سایت عمومی وجود دارد (rotation توکن refresh) و یک تغییر کم‌اهمیت (صفحه‌بندی نظرات). این پرامپت مصرف‌کننده‌های nobat724_front را اصلاح می‌کند.

جدول تغییرات API مرتبط با سایت عمومی

Endpoint تغییر مصرف در nobat724 شدت
POST /oauth/token/refresh refresh_token اکنون یک‌بارمصرف است و در هر فراخوانی چرخش می‌کند؛ کاربر معلق 401 lib/serverToken.js 🔴 شکننده
GET /api/v1/comments/{uuid} data.meta افزوده شد، پیش‌فرض ۵۰ نظر (قبلاً همه) app/doctor/[slug]/page.js, services/response.js getDoctorComments 🟡 کم
GET /api/v1/insurance/{id}, GET /clinic-pro/doctor-address/{id}, appointment-settings/{...} حالا owner/admin (403) مصرف نمی‌شود بدون اثر
کدهای خطای legacy (M21) مقدار wire بدون تغییر بدون اثر

🔴 مشکل اصلی: rotation توکن refresh (POST /oauth/token/refresh)

رفتار جدید backend

هر فراخوانی /oauth/token/refresh:

  1. توکن ارائه‌شده را باطل می‌کند (single-use)،
  2. یک جفت access_token + refresh_token جدید صادر می‌کند،
  3. کاربر با status != 1401.

پاسخ:

{ "access_token": "…", "refresh_token": "<توکن جدید — با قبلی فرق دارد>", "token_type": "Bearer", "expires_in": 900, "refresh_token_expires_in": 2592000 }

وضعیت فعلی nobat724 (کد واقعی — lib/serverToken.js)

export async function getServerAccessToken() {
  const cookieStore = await cookies();
  const refreshToken = cookieStore.get("refresh_token")?.value;
  if (!refreshToken) return null;
  try {
    const res = await axiosInstance.post(
      `${process.env.NEXT_PUBLIC_API_URL}/oauth/token/refresh`,
      { refresh_token: refreshToken },
      { headers: { "Content-Type": "application/json", Authorization: "" } }
    );
    return res.data?.access_token ?? null;   // ⚠️ فقط access_token خوانده می‌شود
  } catch { return null; }
}

چرا می‌شکند

  • این تابع در هر بار رندر صفحه صدا زده می‌شود (مثلاً app/dashboard/page.js).
  • refresh_token چرخش‌یافته‌ی جدید را ذخیره نمی‌کند و توکن قدیمیِ کوکی پس از اولین refresh باطل شده است.
  • نتیجه: refresh اول OK → ناوبری بعدی همان کوکی باطل را می‌فرستد → 401nullredirect به login (خروج عملی کاربر).
  • محدودیت Next.js: getServerAccessToken() از یک Server Component صدا زده می‌شود؛ Server Componentها نمی‌توانند کوکی ست کنند (فقط Server Action / Route Handler / middleware می‌توانند). پس ذخیره‌ی توکن چرخش‌یافته در همین تابع ممکن نیست.

وظیفه ۱ — حل rotation (یکی از دو مسیر؛ مسیر A توصیه می‌شود)

این یک تصمیم cross-repo است. قبل از پیاده‌سازی، با تیم بک‌اند هماهنگ کن.

مسیر A (توصیه‌شده — تغییر در backend): چون سایت در هر رندر refresh می‌زند، single-use rotation با این معماری ناسازگار است. بهترین کار: در clinicpro AuthController::refreshToken بخشِ چرخش/باطل‌سازی را بردار و فقط چک status (کاربر معلق 401) را نگه‌دار. در این حالت serverToken.js نیازی به تغییر ندارد. (یک پرامپت backend جدا برای این کار بساز.)

مسیر B (تغییر در nobat724 — اگر rotation باید بماند): refresh را به جایی منتقل کن که اجازه‌ی ست‌کردن کوکی دارد:

  • یک Route Handler (app/api/refresh/route.js) یا middleware که /oauth/token/refresh را صدا بزند و res.data.refresh_token و access_token جدید را در کوکی بنویسد، سپس صفحات به‌جای فراخوانی مستقیم، از این مسیر استفاده کنند.
  • نمونه (Route Handler):
// app/api/refresh/route.js
import { cookies } from "next/headers";
export async function POST() {
  const jar = await cookies();
  const rt = jar.get("refresh_token")?.value;
  if (!rt) return Response.json({ ok: false }, { status: 401 });
  const r = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/oauth/token/refresh`, {
    method: "POST", headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ refresh_token: rt }),
  });
  if (!r.ok) return Response.json({ ok: false }, { status: 401 });
  const d = await r.json();
  jar.set("access_token", d.access_token, { httpOnly: true, secure: true, sameSite: "lax", maxAge: d.expires_in });
  jar.set("refresh_token", d.refresh_token, { httpOnly: true, secure: true, sameSite: "lax", maxAge: d.refresh_token_expires_in }); // ← توکن چرخش‌یافته
  return Response.json({ ok: true, access_token: d.access_token });
}
  • بعد getServerAccessToken (در Server Component، read-only) فقط کوکی access_token معتبر فعلی را بخواند؛ تجدید توسط middleware/route قبل از رندر انجام شود.

مهم: هر کجای دیگر nobat724 که توکن refresh ذخیره/استفاده می‌شود را هم بررسی کن (مثلاً جریان login که کوکی‌ها را ست می‌کند) تا توکن چرخش‌یافته‌ی جدید همیشه جایگزین قدیمی شود.

🟡 وظیفه ۲ — صفحه‌بندی نظرات (GET /api/v1/comments/{uuid})

وضعیت فعلی (app/doctor/[slug]/page.js)

const resComments = await fetch(`${API_URL}/api/v1/comments/${doctor.uuid}`, { cache: "no-store" });
const jsonComments = resComments.ok ? await resComments.json() : null;
comments = jsonComments?.data?.data;   // آرایه — هنوز کار می‌کند

تغییر

پاسخ حالا { data: { data: [...], meta: { totalRecords, totalPages, currentPage } } } است و پیش‌فرض ۵۰ نظر برمی‌گرداند (قبلاً همه). data.data (آرایه) دست‌نخورده → کد فعلی نمی‌شکند، فقط حداکثر ۵۰ نظر نشان می‌دهد.

وظیفه

  • اگر برای صفحه‌ی پزشک ۵۰ نظر کافی است (به‌علاوه‌ی schema/Review)، هیچ تغییری لازم نیست (فقط آگاه باش).
  • اگر همه‌ی نظرات لازم است: یا ?limit=100 بفرست، یا «نمایش بیشتر»/صفحه‌بندی با data.meta.totalPages اضافه کن. getDoctorComments در services/response.js را هم در صورت نیاز با پارامتر page/limit تطبیق بده.
  • اگر برای SEO/Review schema از تعداد کل نظر استفاده می‌کنی، آن را از data.meta.totalRecords بخوان (نه length آرایه‌ی ۵۰‌تایی).

نکات مهم

  • lib/serverToken.js در Server Component اجرا می‌شود → نمی‌تواند کوکی ست کند؛ ست‌کردن کوکی فقط در Route Handler/Server Action/middleware. (مسیر A این مشکل را کلاً حذف می‌کند.)
  • clinic-pro-tauri تحت تأثیر rotation نیست چون از /oauth/token (grant_type=refresh_token، OAuth bundle) استفاده می‌کند نه /oauth/token/refresh.
  • کدهای خطا (M21) مقدار wire ثابت دارند؛ هر منطقی که روی رشته‌ی code switch می‌کند سالم است.
  • endpointهای owner-only جدید (insurance/{id}, doctor-address/{id}, appointment-settings/*) توسط سایت عمومی مصرف نمی‌شوند → بدون اثر.
  • بعد از تغییر: npm run lint و npm run build.