# جریان کاربری — تسک ۰۲: ماژول احراز هویت

## جریان کامل ورود با OTP (جریان واقعی از Drupal)

```
کاربر موبایل را وارد می‌کند
          │
          ▼
POST /api/v1/user/send-code
  { mobile: "09120671713", captcha_token: "" }
          │
          ├─► اعتبارسنجی فرمت موبایل (/^(\+98|0)?9\d{9}$/)
          ├─► بررسی rate limit IP (max 50/hour)
          ├─► بررسی rate limit Mobile (max 30/hour)
          ├─► تولید UUID + کد OTP
          ├─► ذخیره در Redis: otp:{uuid} = {code, mobile} (TTL=1200s)
          └─► ارسال SMS
          │
          ▼
Response: { uuid: "a1b2c3d4-...", message: "..." }
          │
          ▼
کاربر کد را وارد می‌کند
          │
          ▼
POST /api/v1/user/verify-code
  { uuid: "a1b2c3d4-...", code: "12345" }
          │
          ├─► بررسی وجود uuid در Redis
          ├─► مقایسه code
          │       ├─► نادرست: خطا
          │       └─► درست: حذف از Redis
          └─► Response: { message: "کد با موفقیت تایید شد.", success: true }

          ⚠️ verify-code در Drupal JWT صادر نمی‌کند!
          JWT در مرحله بعد با /oauth/token صادر می‌شود.
          │
          ▼
POST /oauth/token  (MobileGrant)
  grant_type=mobile
  uuid=a1b2c3d4-...  ← همان uuid
  code=12345          ← همان code
  client_id=clinic-pro
  client_secret=...
  registration=true   ← اگر false باشد، فقط کاربر موجود می‌تواند وارد شود
          │
          ├─► OtpService::verify(uuid, code)
          ├─► OtpService::getMobileByUuid(uuid)
          ├─► بررسی وجود کاربر با این موبایل
          │       ├─► وجود دارد: ادامه
          │       └─► جدید + registration=true: ایجاد user با status=pending
          └─► صدور JWT
          │
          ▼
Response: { access_token, refresh_token, token_type: "Bearer", expires_in: 3600 }
```

## جریان تمدید Token

```
POST /oauth/token
  grant_type=refresh_token
  client_id=clinic-pro
  client_secret=...
  refresh_token=eyJ...
          │
          └─► بررسی refresh_token → صدور access_token جدید
```

## جریان دریافت اطلاعات کاربر

```
GET /oauth/userinfo
  Authorization: Bearer {access_token}
          │
          └─► decode JWT → بازگشت: sub, uuid, name, email, phone_number, scope
```
