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

## ساختار فایل‌ها
```
src/Module/Auth/
├── Controller/
│   ├── OtpController.php          ← send-code, verify-code
│   ├── AuthController.php         ← register, session/token
│   ├── OAuthController.php        ← /oauth/token, /oauth/userinfo
│   └── UserController.php         ← delete, patch user
├── Service/
│   ├── OtpService.php             ← تولید، ذخیره و تأیید OTP در Redis
│   ├── JwtService.php             ← صدور و تمدید JWT
│   ├── CaptchaService.php         ← اعتبارسنجی captcha_token
│   └── UserService.php            ← ایجاد، ویرایش، حذف کاربر
├── Repository/
│   └── UserRepository.php
├── Entity/
│   └── User.php
├── DTO/
│   ├── Request/
│   │   ├── SendCodeRequest.php
│   │   ├── VerifyCodeRequest.php
│   │   ├── RegisterRequest.php
│   │   ├── RefreshTokenRequest.php
│   │   └── UpdateUserRequest.php
│   └── Response/
│       ├── TokenResponse.php
│       └── UserInfoResponse.php
└── Voter/
    └── UserVoter.php              ← فقط owner یا admin می‌تواند ویرایش/حذف کند
```

## نمودار جریان احراز هویت
```
کاربر
  │
  ├─► POST /send-code
  │     └─► OtpService: تولید کد ۵ رقمی
  │           └─► Redis: ذخیره با کلید otp:{mobile} (TTL=120s)
  │           └─► SmsService: ارسال پیامک
  │
  ├─► POST /verify-code
  │     └─► OtpService: تأیید کد از Redis
  │           ├─► اگر کاربر جدید: ایجاد User با وضعیت pending
  │           └─► JwtService: صدور access_token + refresh_token
  │
  └─► POST /register (با X-CSRF-Token)
        └─► UserService: تکمیل اطلاعات کاربر
```

## Entity: User
```php
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
class User implements UserInterface
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private int $id;

    #[ORM\Column(type: UuidType::NAME, unique: true)]
    private Uuid $uuid;

    #[ORM\Column(length: 20, unique: true)]
    private string $mobile;

    #[ORM\Column(length: 100, nullable: true)]
    private ?string $firstName;

    #[ORM\Column(length: 100, nullable: true)]
    private ?string $lastName;

    #[ORM\Column(length: 180, nullable: true, unique: true)]
    private ?string $email;

    #[ORM\Column(length: 50)]
    private string $status = 'pending'; // pending, active, blocked

    #[ORM\Column(type: 'json')]
    private array $roles = ['ROLE_USER'];

    // TimestampableTrait
}
```
