# Pre-Registration Feature

## هدف
پیاده‌سازی سیستم پیش ثبت‌نام برای دکتر و کلینیک:
- روی صفحه اصلی (`/`) دو دکمه باشد:
  - **ورود به پنل** → `/admin` (برای کسانی که قبلاً ثبت‌نام شده‌اند)
  - **ثبت نام** → فرم پیش ثبت‌نام (فقط برای دکتر و کلینیک)
- دکتر/کلینیک فرم را پر می‌کند
- ادمین در پنل درخواست‌ها را می‌بیند و تأیید یا رد می‌کند
- پس از تأیید: کاربر و entity مربوطه ساخته می‌شود و نام‌کاربری+پسورد از طریق SMS ارسال می‌شود

---

## قابلیت‌ها

### قابلیت ۱ — Entity و Migration: PreRegistration

ایجاد Entity جدید `src/Auth/Entity/PreRegistration.php` با فیلدهای:
- `id` (int, PK)
- `uuid` (string, unique)
- `type` (string: `independent_doctor` | `doctor_with_clinic` | `clinic_manager`) — نوع حساب (توضیح در پایین)
- `name` (string, 255) — نام کامل
- `mobile` (string, 20) — شماره موبایل
- `info` (text, nullable) — توضیحات / اطلاعات اضافه (تخصص، سابقه، ...)
- `status` (string: `pending` | `approved` | `rejected`) — default: `pending`
- `adminNote` (text, nullable) — یادداشت ادمین هنگام رد کردن
- `createdAt` (int) — Unix timestamp
- `updatedAt` (int) — Unix timestamp

بعد از ایجاد Entity: حتماً `doctrine:migrations:diff` و `doctrine:migrations:migrate` اجرا شود.

---

### قابلیت ۲ — Backend: Public Pre-Registration Endpoint

**`POST /api/v1/pre-registration`** — endpoint عمومی (بدون auth)

فایل: `src/Auth/Controller/PreRegistrationController.php` (class جدید، extends BaseController)

Request body:
```json
{
  "type": "independent_doctor",  // independent_doctor | doctor_with_clinic | clinic_manager — الزامی
  "name": "دکتر احمدی",          // الزامی
  "mobile": "09121234567",       // الزامی
  "info": "متخصص داخلی، ۱۰ سال سابقه"  // اختیاری
}
```

مفهوم `type` و نقش‌های دریافتی پس از تأیید:

| مقدار | متن نمایشی در فرم | نقش‌ها | entity ساخته می‌شود |
|-------|-------------------|--------|---------------------|
| `independent_doctor` | «دکتر هستم» | `ROLE_DOCTOR` | Doctor |
| `doctor_with_clinic` | «دکتر هستم و کلینیک دارم و با چند دکتر همکاری می‌کنم» | `ROLE_DOCTOR` + `ROLE_CLINIC` | Doctor + Clinic |
| `clinic_manager` | «تنها مدیر کلینیک هستم» | `ROLE_CLINIC` | Clinic |

Validation:
- `type` باید یکی از `independent_doctor`، `doctor_with_clinic`، یا `clinic_manager` باشد
- `mobile` باید ۱۰ تا ۱۵ کاراکتر باشد
- اگر همین موبایل با status=pending در جدول وجود داشت → خطا: `DUPLICATE_REQUEST` با پیام "درخواست ثبت‌نام شما در حال بررسی است"

Response موفق:
```json
{ "success": true, "data": { "uuid": "...", "status": "pending" } }
```

امنیت: این endpoint باید در `security.yaml` به عنوان عمومی (public) تعریف شود.

---

### قابلیت ۳ — Backend: Admin Pre-Registration Management Endpoints

در فایل `src/Auth/Controller/PreRegistrationController.php` متدهای زیر اضافه شوند:

**`GET /api/v1/admin/pre-registrations`** — لیست درخواست‌ها
- `#[IsGranted('ROLE_ADMIN')]`
- Query params: `page`, `limit`, `status` (pending|approved|rejected|all — default: pending)
- DQL array hydration، برگرداندن: uuid, type, name, mobile, info, status, admin_note, created_at
- Return: `$this->paginated(...)`

**`POST /api/v1/admin/pre-registrations/{uuid}/approve`** — تأیید درخواست
- `#[IsGranted('ROLE_ADMIN')]`
- اقدامات هنگام تأیید:
  1. بررسی اینکه status=pending باشد (در غیر این صورت خطا: `ALREADY_PROCESSED`)
  2. یک پسورد تصادفی ۸ کاراکتری بسازید (حروف+عدد)
  3. اگر user با این mobile وجود ندارد → User جدید بسازید با این mobile و پسورد
  4. اگر user وجود دارد → پسورد را reset کنید
  5. بر اساس `type` entity و نقش‌ها را بساز:
     - `independent_doctor`:
       - Doctor entity بساز (firstName/lastName از split نام؛ اگر یک کلمه بود همه firstName)
       - به user بده: `ROLE_DOCTOR`
     - `doctor_with_clinic`:
       - Doctor entity بساز (مانند بالا)
       - Clinic entity بساز با `name`=نام درخواست
       - به user بده: `ROLE_DOCTOR` + `ROLE_CLINIC`
     - `clinic_manager`:
       - Clinic entity بساز با `name`=نام درخواست
       - به user بده: `ROLE_CLINIC`
     در همه حالت‌ها قبل از ساخت entity بررسی کن که قبلاً وجود نداشته باشد (جلوگیری از duplicate)
  7. `status` را روی `approved` و `updatedAt` را update کنید
  8. یک SMS بفرستید از طریق سرویس SMS موجود در پروژه (کلاس `App\Sms\`) با متن: "به کلینیک پرو خوش آمدید! شماره‌کاربری: {mobile} | رمز عبور: {password} | لینک ورود: https://clinic-pro.ddev.site/admin"
- Response: `$this->success(['message' => 'تأیید شد و اطلاعات ورود ارسال گردید'])`

**`POST /api/v1/admin/pre-registrations/{uuid}/reject`** — رد درخواست
- `#[IsGranted('ROLE_ADMIN')]`
- Request body: `{ "note": "توضیح دلیل رد" }` — اختیاری
- `status` را `rejected` کن، `adminNote` را ذخیره کن
- Response: `$this->success(['message' => 'درخواست رد شد'])`

---

### قابلیت ۴ — Frontend Homepage: دو دکمه در header و hero

فایل: `templates/public/home.html.twig`

**۴الف — جایگزینی کامل `<div class="nav-right">`:**
کل بلوک زیر را حذف کن:
```html
<div class="nav-right">
  <button class="nav-ico search" ...>...</button>
  <button class="nav-burger nav-toggle" id="navToggle" ...>...</button>
  <a href="#download" class="nav-burger" ...>...</a>
</div>
```
و به جای آن این بلوک را قرار بده:
```html
<div class="nav-right">
  <button class="nav-burger nav-toggle" id="navToggle" aria-label="منو">
    <svg viewBox="0 0 24 24" fill="none"><path d="M4 7h16M4 12h16M4 17h16" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
  </button>
  <button class="btn btn-ghost" id="openRegModal" style="font-size:13px;padding:8px 20px">ثبت نام</button>
  <a href="/admin" class="btn btn-blue" style="font-size:13px;padding:8px 20px;text-decoration:none">ورود به پنل</a>
</div>
```
توجه: دکمه hamburger (navToggle) را نگه دار چون JS موبایل به آن وابسته است. دکمه search و لینک download را حذف کن.

**۴ب — دکمه ثبت نام در hero:**
در `<div class="hero-actions reveal d2">` دکمه "دانلود رایگان" را به "ثبت نام" تغییر بده.
توجه: از `class="btn btn-coral"` با `id="openRegModal2"` استفاده کن (id متفاوت از header) و در JS هر دو را به modal وصل کن:
```html
<button class="btn btn-coral" id="openRegModal2">ثبت نام دکتر / کلینیک</button>
<a href="#contact" class="btn btn-blue">تماس با ما</a>
```

**۴ج — Modal پیش ثبت‌نام:**
یک modal HTML در انتهای `<main>` اضافه کن (قبل از `</main>`) با:
- overlay با id=`regOverlay`
- modal box با فرم شامل:
  - **انتخاب نوع حساب** — سه کارت قابل کلیک (radio-style) با آیکون و توضیح، به صورت عمودی (stacked):
    - `independent_doctor` → عنوان: «دکتر هستم» — زیرعنوان: «مطب شخصی دارم، به تنهایی کار می‌کنم»
    - `doctor_with_clinic` → عنوان: «دکتر هستم و کلینیک دارم» — زیرعنوان: «با چند دکتر در یک کلینیک همکاری می‌کنم»
    - `clinic_manager` → عنوان: «مدیر کلینیک هستم» — زیرعنوان: «مدیریت کلینیک را دارم، خودم دکتر نیستم»
    کارت انتخاب‌شده با border رنگی و پس‌زمینه روشن هایلایت شود
  - input: نام کامل
  - input: شماره موبایل (dir=ltr)
  - textarea: توضیحات اختیاری (تخصص، آدرس، ...)
  - دکمه ارسال (disable تا زمانی که type انتخاب نشده)
- CSS inline برای modal (همانند استایل‌های موجود در صفحه: رنگ‌ها `--blue`, `--coral`, border-radius مشابه)
- JS inline:
  - باز/بسته شدن modal با کلیک روی هر دو دکمه (`openRegModal` در header و `openRegModal2` در hero) و کلیک روی overlay
  - ارسال فرم با `fetch('/api/v1/pre-registration', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({...}) })`
  - نمایش پیام موفقیت یا خطا
  - بعد از موفقیت: بستن modal و نمایش پیام "درخواست شما ثبت شد. پس از بررسی، اطلاعات ورود از طریق SMS ارسال می‌شود."

---

### قابلیت ۵ — Frontend Admin Panel: صفحه مدیریت درخواست‌ها

**۵الف — ایجاد `assets/admin/pages/PreRegistrationsPage.tsx`:**
- `useQuery` با `queryKey: ['pre-registrations', page, statusFilter]`
- API: `GET /api/v1/admin/pre-registrations?page=...&status=...`
- جدول با ستون‌ها: نام، موبایل، نوع (badge با رنگ‌بندی: «دکتر» آبی برای `independent_doctor` / «دکتر + کلینیک» بنفش برای `doctor_with_clinic` / «مدیر کلینیک» نارنجی برای `clinic_manager`)، وضعیت badge، تاریخ درخواست، ستون اقدامات
- Filter tabs: همه | در انتظار | تأیید شده | رد شده
- برای هر ردیف با status=pending: دکمه‌های تأیید (سبز) و رد (قرمز)
- کلیک تأیید → mutation به `POST /api/v1/admin/pre-registrations/{uuid}/approve` → toast موفقیت
- کلیک رد → یک prompt کوچک (یا یک inline textarea در row) برای وارد کردن دلیل → mutation به `POST /api/v1/admin/pre-registrations/{uuid}/reject` → toast
- بعد از هر mutation: `invalidateQueries(['pre-registrations'])`

**۵ب — اضافه کردن به Sidebar.tsx:**
در بخش admin داخل `buildSections`، در section «مدیریت» یک آیتم اضافه کن:
```
{ to: '/admin/pre-registrations', icon: ClipboardDocumentCheckIcon, label: 'درخواست‌های ثبت‌نام' }
```
(import `ClipboardDocumentCheckIcon` از `@heroicons/react/24/outline`)

**۵ج — اضافه کردن route به App.tsx:**
```tsx
import PreRegistrationsPage from './pages/PreRegistrationsPage';
// ...
<Route path="pre-registrations" element={<RoleRoute roles={['admin']}><PreRegistrationsPage /></RoleRoute>} />
```

---

## نکات اجرایی

### امنیت
- endpoint عمومی `POST /api/v1/pre-registration` را در `config/packages/security.yaml` داخل `public_endpoints` firewall اضافه کن
- endpoint های admin با `#[IsGranted('ROLE_ADMIN')]` محافظت شوند

### SMS
- کلاس SMS موجود را در پروژه پیدا کن (`src/Sms/`) و از آن استفاده کن
- اگر ارسال SMS با خطا مواجه شد، عملیات approve کامل شود (rollback نشود) — فقط یک log warning بزن

### پسورد تصادفی
از `bin2hex(random_bytes(4))` برای تولید پسورد ۸ کاراکتری hex استفاده کن.

### مستندسازی
بعد از اتمام هر قابلیت:
- `docs/api/auth.md` را برای endpoint های جدید pre-registration به‌روزرسانی کن
- `docs/api/admin.md` را برای endpoint های admin به‌روزرسانی کن
