# پایگاه داده — تسک ۰۲: ماژول احراز هویت ## جدول: users _(از بخش ۲.۱ مستند + بررسی DB backup Drupal)_ | ستون | نوع | نام Drupal | توضیح | |------|-----|-----------|-------| | id | INT AUTO_INCREMENT PK | id | شناسه داخلی | | uuid | CHAR(36) UNIQUE NOT NULL | uuid | شناسه عمومی UUID | | uid | INT FK → users.id NOT NULL | uid | ارجاع به خود جدول (self-reference — در Drupal الزامی) | | mobile_number | VARCHAR(20) UNIQUE NOT NULL | name | شماره موبایل — به عنوان username استفاده می‌شود | | password | VARCHAR(255) NOT NULL | pass | رمز عبور هش‌شده با bcrypt | | realname | VARCHAR(255) NULL | field_realname | نام و نام‌خانوادگی کامل (نه first_name/last_name!) | | picture | VARCHAR(500) NULL | user_picture | آدرس تصویر پروفایل | | email | VARCHAR(180) UNIQUE NULL | mail | ایمیل (اختیاری) | | status | TINYINT(1) DEFAULT 1 | status | ۱=فعال، ۰=غیرفعال | | roles | JSON NOT NULL | — | نقش‌ها — مثال: `{"0":"authenticated","2":"doctor"}` | | created_at | INT NOT NULL | created | Unix timestamp — زمان ایجاد | | updated_at | INT NOT NULL | changed | Unix timestamp — آخرین ویرایش | > **⚠ مهم:** > - Drupal از `realname` (یک فیلد) استفاده می‌کند، **نه** `first_name` + `last_name`! > - timestamp‌ها نوع **INT** هستند (Unix timestamp)، نه DATETIME > - `status` نوع **TINYINT** است (نه ENUM) > - `uid` self-reference است — در Drupal هر user به خودش اشاره می‌کند ## ایندکس‌ها ```sql CREATE UNIQUE INDEX idx_users_uuid ON users(uuid); CREATE UNIQUE INDEX idx_users_mobile ON users(mobile_number); CREATE UNIQUE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_status ON users(status); ``` ## ذخیره‌سازی OTP در Redis (نه پایگاه داده) ``` کلید: otp:{uuid} ← UUID از /api/v1/user/send-code برگردانده می‌شود (نه mobile!) مقدار: {"code": "12345", "attempts": 0} TTL: 1200 ثانیه (20 دقیقه) ``` ## جریان OTP (MobileGrant) ``` 1. POST /api/v1/user/send-code → {mobile, captcha_token} → UUID تولید + کد OTP ذخیره در Redis با کلید otp:{uuid} → UUID برگردانده می‌شود 2. POST /api/v1/user/verify-code → {mobile, captcha_token} → کد از Redis با کلید otp:{uuid} تأیید می‌شود 3. POST /oauth/token → grant_type=mobile (MobileGrant) → JWT token صادر می‌شود 4. GET /oauth/userinfo → Bearer token → اطلاعات کاربر + شیء clinic_pro برگردانده می‌شود ``` ## نمونه پاسخ GET /oauth/userinfo (واقعی از Drupal) ```json { "email": null, "email_verified": true, "username": "09120671710", "id": "22", "uuid": "d200f5c5-d717-4526-b263-d3bb7d0228d6", "created": "1762262151", "changed": "1762262267", "status": "1", "roles": { "0": "authenticated", "2": "doctor" }, "realName": "single doctor", "picture": [], "clinic_pro": { "base_role": "doctor", "db_uuid": "61be915b-595a-42e5-bca5-f80d22f4f14a", "db_key": "22bea8c1dc64d9b0c744810722519efe7290276ecd82d9bc650482aa4539bf0d", "my_doctors_uuid": { "uuid": "61be915b-595a-42e5-bca5-f80d22f4f14a", "id": "29", "name": "single doctor" } } } ``` > **نکات `/oauth/userinfo`:** > - `realName` با حرف بزرگ N (camelCase) > - `roles` یک object است، نه array: `{"0":"authenticated","2":"doctor"}` > - `clinic_pro.base_role` → نقش اصلی: `doctor`, `clinic`, `doctor_s_secretary` > - `clinic_pro.db_uuid` → UUID موجودیت doctor/clinic در جدول clinic_pro > - فقط نقش‌های `doctor`, `clinic`, `doctor_s_secretary` می‌توانند با پسورد لاگین کنند ## روابط با سایر جداول ``` users → user_profiles (OneToOne) : تسک ۰۳ users → doctors (OneToOne) : تسک ۰۵ users → clinics (OneToOne) : تسک ۰۶ users → appointments (OneToMany) : تسک ۱۰ users → payments (OneToMany) : تسک ۱۵ users → representations (OneToOne): تسک ۱۶ ```