# 11 — گزارش پیاده‌سازی فاز ۲ (بک‌اند و سینک)

> وضعیت: ✅ تکمیل · تاریخ: ۲۰۲۶-۰۹-۲۴ · مطابق نقشه‌ی راه سند 09

## آنچه ساخته شد

### سرور — `server/` (Express 4 + SQLite)
| فایل | نقش |
|---|---|
| `index.js` / `app.js` | بوت + ساخت اپ؛ یک پورت: `/api/v1` + کلاینت استاتیک + `/healthz` |
| `db.js` | SQLite (better-sqlite3, WAL, FK ON) — ۶ جدول دقیقاً مطابق ERD سند 03 |
| `auth.js` | JWT والد (۲۴h) + جلسه‌ی کودک (توکن 30 روزه، sha256 ذخیره می‌شود) |
| `validate.js` / `rateLimit.js` | اعتبارسنجی الگوی سند 04 + سقف 60 req/min/IP |
| `routes/auth.js` | ثبت‌نام/ورود والد (bcrypt، ایمیل تکراری → 409) |
| `routes/children.js` | CRUD کودک · جلسه‌ی آواتاری · `progress:batch` با merge · events · badges · گزارش والدین |
| `routes/packs.js` | فهرست/جزئیات پک‌ها از همان JSONهای کلاینت (تک‌منبع حقیقت) |

### کلاینت — لایه‌ی داده (فاز ۲)
| ماژول | نقش |
|---|---|
| `api/restRepo.js` | کلاینت AJAX: timeout (AbortController) + ApiError قراردادی + توکن‌های دو scope |
| `api/syncQueue.js` | صف ۵۰۰تایی LRU؛ `drain()` آخرین اسنپ‌شات هر حرف را می‌سازد؛ removeByIds دقیق |
| `api/syncService.js` | pull (ابر→local قبل از بوت موتور) + flush (local→ابر) + backoff نمایی (۵s→۶۰s) + رویداد `sync:status` |

### اتصال تجربه — UI
- **صفحه‌ی والدین** (`#/parents`): گیت ریاضی → ورود/ثبت‌نام → اتصال دستگاه به کودک (یا ساخت کودک روی حساب) → pull+flush فوری
- **گزارش یادگیری** والدین: حروف شروع‌شده/قهرمان، مرور امروز، حروف ضعیف، نمودار ستاره‌های ۷ روز
- **چیپ سینک** در هدر نقشه (⏳/✅/📴/⚠️) + دکمه‌ی «حساب والدین» در تنظیمات
- رویدادهای موتور (`progress:changed`, `game:attempt`, `letter:mastered`, `game:complete`) → SyncQueue

## استراتژی ادغام (پیاده‌سازی‌شده)

```
mastery / correct / wrong / stars → max          (هر دو سمت فقط «به جلو» می‌روند)
box / dueAt                      → رکورد با تلاش بیشتر (اطلاعات تازه‌تر)
```
نیم‌شبکه‌ای (semilattice) → **idempotent** → retry پس از خطای شبکه امن است (تست‌شده).

## کیفیت

| بررسی | نتیجه |
|---|---|
| تست واحد موتور (`tests/engine.test.js`) | ✅ 18/18 |
| تست واحد سینک (`tests/sync.test.js`) — merge/queue/flush/backoff/offline | ✅ 10/10 |
| تست یکپارچه‌ی API (`tests/api.test.js`) — سرور واقعی، DB ایزوله | ✅ 20/20 |
| شبیه‌سازی معیار پذیرش (قطع اینترنت وسط بازی → بازگشت → سینک) | ✅ بدون از‌دست‌رفتن پیشرفت |
| E2E روی سرور زنده (register→child→session→batch→events→report) | ✅ |
| کل مجموعه | **۴۸/۴۸** ✅ |

معیار پذیرش فاز (سند 09): «قطع اینترنت وسط بازی → ادامه بازی → بازگشت شبکه → سینک بدون خطا و بدون از دست رفتن پیشرفت» — با تست واحد + شبیه‌سازی + تست دستی مرورگر (DevTools → Offline) پوشش داده شد.

## انحرافات آگاهانه از طراحی (و دلیل)

| انحراف | دلیل | تصمیم |
|---|---|---|
| bcryptjs به‌جای argon2 | pure-JS، بدون کامپایل native؛ استقرار ساده‌تر | مهاجرت به argon2 در فاز استقرار production |
| merge با max به‌جای «تجمعی» برای شمارنده‌ها | تجمعی بدون delta = دوباره‌شماری در retry؛ max با monotonic بودن شمارنده‌ها هم‌ارز و idempotent است | ثبت‌شده در این سند؛ docs/04 هم‌راستا شد |
| ستون `children.stars_total` (جدید در schema) | تداوم ستاره‌ها بین دستگاه‌ها (پیش‌نیاز نشان «۲۵ ستاره») | docs/03 به‌روز شد |
| `badges` داخل `progress:batch` (به‌جای endpoint جدا) | کلایست منبع حقیقت نشان‌هاست (تعریف در پک)؛ کاهش یک رفت‌وبرگشت | docs/04 به‌روز شد |
| rate-limit در حافظه | مقیاس فعلی تک‌پروسه | Redis در production |

## اجرا

```bash
npm install                        # فقط بار اول (node_modules در snapshot نمی‌ماند)
npm test                           # ۴۸ تست (engine + sync + api)
npm run server                     # http://localhost:8080 — بازی + API با هم
```

## مسیر دستی تست سینک در مرورگر

1. بازی کن (چند حرف) → تنظیمات ⚙️ → «حساب والدین و سینک ابری» → گیت ریاضی
2. ثبت‌نام والد → «کودک جدید روی حساب» → متصل می‌شود (☁️ سبز در نقشه)
3. DevTools → Network → Offline → بازی کن → Online → چند ثانیه بعد سینک خودکار
4. پنل والدین → «سینک همین حالا» → گزارش با ستاره‌های امروز
