# ورود و اتصال حساب بازینس

> بازیکن چطور هویت بازینس می‌گیرد، از اسپلش یا تنظیمات وارد می‌شود، و بازی چطور حساب‌ها را بی‌خطر جابه‌جا می‌کند.

## مدل هویت
بازی شما **حساب‌های بازیکن خودش** را دارد، مثلاً با کلید شناسه‌ی دستگاهی که در اولین اجرا ساخته می‌شود. بازینس **روی** همین حساب سوار می‌شود:

1. اولین باری که پلتفرم روشن است، سرور شما یک **کاربر ناشناس بازینس** برای بازیکن می‌سازد ([`create-user`](platform-api.md#step-2-create-a-baziness-user-for-a-player)) و `userId` آن را روی رکورد بازیکن ذخیره می‌کند.
2. بازیکن تا وقتی با شماره موبایلش در یکی از صفحه‌های بازینس وارد نشود **ناشناس** می‌ماند (`isLinkedToAccount: false`). بعد از ورود حساب **متصل** است.
3. اگر حساب بازینسی که بازیکن واردش می‌شود **از قبل مال بازیکن دیگری از بازیکنان شما باشد** (همان شخص روی گوشی دیگر)، بازی به آن بازیکن **جابه‌جا می‌شود** و حساب را دو بار وصل نمی‌کند.

| وضعیت | `userId` بازینس ذخیره شده؟ | `isLinkedToAccount` | چیزی که بازیکن می‌بیند |
| --- | --- | --- | --- |
| بازینس خاموش | — | — | هیچ بخش بازینسی |
| مهمان | بله (کاربر ناشناس) | `false` | موجودی سکه و دکمه‌ی جایزه کار می‌کنند؛ «اتصال حساب» در تنظیمات |
| وارد شده | بله | `true` | همه‌چیز، از جمله دریافت جایزه‌های گیتا کوین |

## کل جریان
```mermaid
sequenceDiagram
  autonumber
  participant C as Game client
  participant S as Game server
  participant K as Platform API
  participant W as Baziness page (sheet)
  C->>S: GET /api/platform/config
  S-->>C: { enabled, webBase, apiBase, packageName }
  Note over C: Splash: Sign in with Baziness / Continue as guest
  C->>S: POST /api/platform/token { deviceId, linkedToken? }
  S->>K: create-user (first time) / get-user-token
  K-->>S: { userId, token, isLinkedToAccount }
  S-->>C: { token, bazinessUserId, isLinked, switchToDeviceId? }
  C->>W: open login page (sdkType=js, linkedToken, allowGuest=false)
  W-->>C: postMessage { type: "login", data: "<token>" }
  C->>S: POST /api/platform/login { deviceId, token }
  S->>K: validate-user-token
  K-->>S: { isValid, userId }
  S-->>C: { ok } — or { ok, switchToDeviceId }
  C->>C: close sheet, or switch device id + reload
```

## چیزهایی که سرور شما فراهم می‌کند
کلاینت شما هیچ‌وقت خودش API سرور پلتفرم را صدا نمی‌زند. **سه endpoint از سرور خودتان** را صدا می‌زند:

| endpoint شما | کلاینت می‌فرستد | سرور شما | پاسخ |
| --- | --- | --- | --- |
| `GET /api/platform/config` | — | کاری نمی‌کند، فقط تنظیمات را می‌گوید | `{ enabled, webBase, apiBase, packageName, gameName, gameOfferUrl }` یا `{ enabled: false }` |
| `POST /api/platform/token` | شناسه‌ی دستگاه، و `linkedToken` اگر هست | اگر هنوز کاربر بازینس ندارد ← `create-user`؛ وگرنه ← `get-user-token`. اگر `userId` حاصل مال بازیکن دیگری باشد وصل **نمی‌کند** | `{ token, userId, isLinkedToAccount }` یا `{ switchToDeviceId }` |
| `POST /api/platform/login` | شناسه‌ی دستگاه، توکنی که صفحه‌ی ورود داده | `validate-user-token` ← این حساب مال کیست؟ مال بازیکن دیگری ← جابه‌جایی؛ وگرنه ← وصل به همین بازیکن | `{ ok: true }` یا `{ ok: true, switchToDeviceId }` یا `{ ok: false }` |

اگر پلتفرم در دسترس نباشد، `/token` پاسخ `{ enabled: true, error: "platform_unavailable" }` را بدون توکن می‌دهد و بازی به هر حال بالا می‌آید.

## اجرای اول: مهمان یا ورود
وقتی بازینس روشن است و بازیکن نه هنوز انتخابی کرده و نه وارد شده، اسپلش به جای نوار بارگذاری دو دکمه نشان می‌دهد:

- **«ورود با حساب بازینس»**: صفحه‌ی ورود را باز می‌کند و منتظر می‌ماند.
- **«ادامه به عنوان مهمان»**: انتخاب را به خاطر می‌سپارد و ادامه می‌دهد.

ترتیب بالا آمدن بازی:

1. بازیکن را در سیستم حساب **خود بازی** وارد کنید.
2. از سرور `/api/platform/config` را بپرسید. اگر بازینس خاموش بود، از همه‌ی قدم‌های بعد بگذرید.
3. اگر انتخابی نشده و بازیکن وارد نیست، دو دکمه را نشان دهید و منتظر بمانید.
4. `/api/platform/token` را صدا بزنید. اگر `switchToDeviceId` برگشت، آن شناسه را بپذیرید و از اول شروع کنید.
5. اگر بازیکن همین الان وارد شد، پروفایلش را دوباره بخوانید تا صفحه حساب وارد شده را نشان دهد.

اگر بازیکن صفحه‌ی ورود را بدون وارد شدن بست، دو دکمه را دوباره نشان دهید.

## جابه‌جایی حساب، قدم‌به‌قدم
جابه‌جایی وقتی پیش می‌آید که حساب بازینسی که بازیکن واردش می‌شود از قبل به بازیکن **دیگری** از بازیکنان شما وصل باشد، مثلاً بعد از نصب دوباره یا روی گوشی جدید:

1. سرور پاسخ می‌دهد `switchToDeviceId: "<شناسه‌ی دستگاه آن بازیکن>"`.
2. کلاینت آن شناسه را به‌عنوان شناسه‌ی خودش ذخیره می‌کند و توکن بازینس ذخیره‌شده را فراموش می‌کند.
3. بازی را از اول اجرا می‌کند، بدون `linkedToken` در آدرس.
4. اجرای بعدی بازیکن دیگر را با همه‌ی پیشرفتش بالا می‌آورد.

## باز شدن بازی از اپ بازینس
> [!IMPORTANT]
> اپ بازینس حالا `?linkCode=` (یک‌بارمصرف) را هم می‌فرستد. به‌جای `linkedToken` آن را به سرورتان بدهید. [مهاجرت توکن](token-migration.md#client-steps) را ببینید.

اپ بازینس بازی‌ها را با `?linkedToken=<توکن>` در آدرس باز می‌کند:

- آن توکن را به‌عنوان `linkedToken` به `/api/platform/token` بفرستید تا بازیکن در حساب درست بازینس قرار بگیرد. در اجرای بعدی آن را از آدرس پاک کنید.
- اگر دستگاه از قبل توکن **دیگری** دارد، حساب بازینس دیگری دارد می‌آید: پیش از ادامه داده‌های محلی را پاک کنید و از اول شروع کنید.
- ورود تعیین می‌کند **کدام** حساب بازی کند، هیچ‌وقت تعیین نمی‌کند **بازیکن جدید است یا نه**. بازیکن تازه‌واردی که این‌طور می‌آید هم باید آموزش و هدیه‌های خوش‌آمد شما را ببیند.

## ورود در آینده، از تنظیمات
مهمان هر وقت بخواهد می‌تواند حسابش را وصل کند: تنظیمات ← باز کردن **صفحه‌ی پروفایل** ([پارامترها](pages.md#the-pages)). وقتی نما بسته شد، دوباره `/api/platform/token` را بپرسید و موجودی سکه را تازه کنید.

## خروج
وقتی صفحه `logout` می‌فرستد، نما را ببندید، **هر چه بازی به‌صورت محلی ذخیره کرده پاک کنید** (هویت، توکن، انتخاب‌ها، پیشرفت آموزش) و مثل یک بازدیدکننده‌ی کاملاً جدید از اول شروع کنید.

## تست ورود روی پلتفرم توسعه
> [!TIP]
> روی **پلتفرم توسعه** (همان جایی که بازی‌های تستی به آن وصل‌اند) با **هر شماره موبایلی** و کد **`111111`** می‌توانید وارد شوید. هیچ پیامکی فرستاده نمی‌شود. با شماره‌های ساختگی هر چند حساب تستی که لازم دارید بسازید: یکی برای تست جابه‌جایی حساب، یکی برای یک مهمان تازه و غیره. محیط اصلی کد واقعی را پیامک می‌کند.

## اشتباه‌های رایج
| اشتباه | نتیجه | راه‌حل |
| --- | --- | --- |
| پیام `token` صفحه ورود حساب شود | فروشگاه جایزه به محض باز شدن بسته می‌شود؛ ورود اول پیش از وارد شدن بازیکن تمام می‌شود | فقط `login` ورود است |
| وصل کردن توکن بدون `validate-user-token` | هر کسی می‌تواند هر حسابی را مال خودش کند | همیشه در سرور بررسی کنید |
| باز کردن صفحه‌ی ورود بدون توکن بازیکن | ورود اول از اسپلش کاربر ناشناسی ندارد که به آن وصل شود | مطمئن شوید `/api/platform/token` قبلاً اجرا شده و توکنش را به‌عنوان `linkedToken` بفرستید |
| نبودن `allowGuest=false` روی صفحه‌ی ورود | بازیکن یک «ادامه به عنوان مهمان» دوم می‌بیند | روی صفحه‌های ورود، پروفایل و پیشنهاد اضافه‌اش کنید |
| پاداش اتصال حساب بیش از یک بار | خروج و ورود دوباره، پاداش را تکرار می‌کند | هدیه‌ی «حساب وصل شد» را از سرور و یک بار برای هر بازیکن بدهید |

کد آماده: [endpointهای سرور](samples-server.md#login-endpoints)، [کنترلر و پیام‌های کلاینت](samples-client.md#platform-controller).
