# ۱۴ — رفع باگ‌های بازخورد کاربر (۲۰۲۶-۰۹-۲۴)

گزارش کاربر: «۱) حساب والدین ساخته/وارد نمی‌شود ۲) خط خطی حروفِ ناقص را تأیید می‌کند ۳) خطاها نمایش داده نمی‌شوند»

## باگ ۲ — تأیید زودهنگام خط خطی

- **ریشه:** شرط تکمیل فقط «پوشش کلی ≥۷۰٪» با قلم ضخیم ۲۶px بود؛ یک خط از وسط حرف هم به آستانه می‌رسید.
- **رفع:** پوشش **منطقه‌محور** — `buildRegions` حرف را به گرید ۳×۳ تقسیم می‌کند؛ تکمیل = هر منطقه‌ی معتبر ≥۵۵٪ **و** کلی ≥۷۰٪ (`TRACE` در `games/traceLetter.js`). قلم → ۱۸px. نوار پیشرفت = ضعیف‌ترین منطقه.
- تست: `tests/trace.test.js` (۶ تست، از جمله خودِ سناریوی باگ).

## باگ ۱ — حساب والدین (سه لایه!)

1. **UX:** بعد از ثبت‌نام موفق فرم همان‌جا می‌ماند و بخش اتصال کودک پایینِ دید بود → کارت ✅ + `scrollIntoView`؛ خطای ۴۰۹ → پیام دوستانه + سوییچ به ورود. (`SafeSession` به‌جای sessionStorage خام، `showConfirm` به‌جای `window.confirm`، `parseNum` برای ارقام فارسی.)
2. **باگ خودساخته:** در 1.0.2 استفاده از `Diagnostics/APP_VERSION` بدون import → `ReferenceError` بعد از گیت → «گیت کلاً غیرفعال». رفع + تست جدید `tests/imports.test.js` که «استفاده بدون import» را در کل ۴۷ ماژول برای همیشه شکار می‌کند.
3. **ریشه‌ی اصلی — HTTP 429:** rate limiter سرور (۶۰/دقیقه/IP) روی «همه‌ی» مسیرها از جمله فایل‌های استاتیک اعمال می‌شد؛ بار اول اپ ~۶۰ ماژول ES را همزمان می‌خواست → ماژول‌ها ۴۲۹ می‌خوردند → گراف import می‌شکست → صفحات تصادفی «مرده» بودند و ثبت‌نام/ورود هم در همان دقیقه‌ها 429 می‌گرفت. **رفع:** محدودیت فقط روی API (`/api` ۲۴۰/دقیقه، `/api/v1/auth` ۱۲/دقیقه ضد brute-force؛ `Retry-After`) — استاتیک آزاد. (`server/rateLimit.js`)

## باگ ۳ — نمایش خطاها

- `core/diagnostics.js`: تله‌ی سراسری `error`/`unhandledrejection`، حافظه‌ی ۳۰ خطای آخر، `checkServer()` با زمان پاسخ، `APP_VERSION`.
- کارت «🖥️ اطلاعات سیستم» (`ui/components/sysInfoCard.js`) — **دو جا:** صفحه‌ی والدین و مودال تنظیمات (بدون گیت!): نسخه / آنلاین‌بودن / سرور / آخرین خطاها + آزمون دوباره.
- خطاهای بحرانی (js/promise/game) → توست ⚠️؛ خطاهای api/server فقط در کارت (کودک با پیام فنی اذیت نشود).
- `RestRepo` همه‌ی خطاهای API را در Diagnostics ثبت می‌کند.

## باگ ۴ — «کودک جدید روی حساب کار نمی‌کند» (لاگ سرور: login→200 بعدش GET /children→401)

- **ریشه‌ی رفتاری:** هندلر دکمه‌ی «➕ کودک جدید» فقط بعد از موفقیت `listChildren` نصب می‌شد؛ اگر لیست به هر دلیلی خطا بدهد (در لاگِ کاربر: 401 بلافاصله بعد از login موفق — علت دقیق در محیط پروکسی در دسترس نبود) دکمه **مرده** می‌ماند.
- **رفع چندلایه:**
  1. هندلر دکمه مستقل از نتیجه‌ی لیست نصب می‌شود.
  2. هر 401 → `sessionExpired`: توکن پاک + پیام «جلسه‌ی ورود منقضی شد — دوباره وارد شو» + فرم ورود دوباره (خودترمیمی).
  3. `maybeRestore`: بعد از رفت‌وآمد/رفرش در همان تب، اگر توکن والد معتبر باشد کارت ✅ بدون login دوباره می‌آید (ایمیل هم در SafeSession ذخیره می‌شود).
  4. سرور: `authMiddleware`/`requireParent` دلیل دقیق 401 را لاگ می‌کنند (توکن ارسال‌نشده / امضای نامعتبر / منقضی / scope غلط) — اگر تکرار شد، ریشه قطعی معلوم است.
- E2E: دو استپ جدید «بازیابی جلسه بدون login» و «ساخت کودک جدید → اتصال → نقشه» → مجموع ۱۲ استپ.

## سخت‌سازی کش (درس «کاربر نسخه‌ی کهنه می‌بیند»)

- SW: `skipWaiting` + `clients.claim` در نصب/فعال‌سازی + استراتژی **شبکه-اول** برای همه‌ی دارایی‌ها (کش فقط fallback آفلاین) → هر رفرش = نسخه‌ی تازه؛ دیگر لازم نیست چند بار رفرش کنی.
- سرور: `Cache-Control: no-cache` برای html/js/css/json + cache-bust `?v=` در index.html.

## E2E واقعی (دستاورد اصلی این دور)

`tests/e2e.mjs` + Playwright/Chromium — **همان مسیر کاربر**: بارگذاری → زبان → ساخت کودک → ⚙️ → گیت → فرم → ثبت‌نام → کارت ✅؛ هر «خطای کنسول/صفحه» = شکست تست. این تست بود که 429 را شکار کرد (و باگ import را قبلاً شکار می‌کرد — کلاس خطاهایی که تست واحد نمی‌بیند).

```bash
npm run test:e2e   # نیازمند: سرور روی 8080 + npx playwright install chromium
```

## وضعیت نهایی

- واحد: **۸۰/۸۰** (engine 18 · sync 10 · api 21 · packs 13 · pwa 10 · trace 6 · imports 2)
- E2E (نسخه 1.0.5): **۱۲/۱۲** — شامل بازیابی جلسه و ساخت کودک جدید
- E2E: **۱۰/۱۰** بدون خطای کنسول
- نسخه: **1.0.6**

## باگ ۵ — «کودک جدید» همچنان کار نمی‌کند (نسخه 1.0.6 — ریشه‌ی قطعی)

لاگ سرور (با توضیحات جدید auth): `login → 200` و بلافاصله `GET /children → 401 (توکن والد ارسال نشده)` — یعنی درخواستِ بعد از ورودِ موفق، **اصلاً هدر Authorization نداشته**. کلاینت و سرور هر دو سالم بودند؛ جمع‌بندی: **پروکسی پیش‌نمایش e2b روی درخواست‌های کش‌شده‌ی GET، هدر استاندارد Authorization را حذف می‌کند** (رفتار شناخته‌شده‌ی کش‌های مشترک — RFC 7234). شاهد: هدر سفارشی `X-Child-Session` (کودک) هرگز از همین پروکسی حذف نشده و همه‌ی فلوی کودک همیشه کار کرده.

### رفع

- **کلاینت** (`api/restRepo.js`): توکن والد در «دو» هدر فرستاده می‌شود — `Authorization: Bearer` (استاندارد) + `X-Parent-Token` (سفارشی، ضد پروکسی)؛ + fallback خواندن توکن از SafeSession اگر state ماژول خالی بود.
- **سرور** (`auth.js`): `authMiddleware` هر دو هدر را می‌پذیرد.
- **سرور** (`app.js`): `Cache-Control: no-store` روی همه‌ی پاسخ‌های `/api` — هیچ کشی (مرورگر/پروکسی) دیگر پاسخ API را نگه نمی‌دارد؛ خدشه‌ی ۳۰۴های عجیب روی GET /children هم رفع شد.
- تست: `api.test.js` +۱ (فقط X-Parent-Token → 200 + no-store) → مجموع ۸۱.

نسخه: **1.0.7** · واحد ۸۲/۸۲ · E2E ۱۲/۱۲

## باگ ۶ — «کودک جدید» هنوز کار نکرد (نسخه 1.0.7 — دو ریشه‌ی همزمان)

لاگ سرور 1.0.6 باز هم نشان داد: `login → 200` سپس `GET /children → 401 (توکن ارسال نشده)` — با وجود هدر دومی که کلاینت 1.0.6 می‌فرستاد. نتیجه: **مرورگر کاربر هنوز کد قدیمی را اجرا می‌کرد** (هدر X-Parent-Token در کد قدیمی وجود ندارد) و هم‌زمان **رفتار واقعی پروکسی e2b نسبت به هدرهای سفارشی قابل مشاهده از داخل سندباکس نیست**.

### رفع قطعی — «توکن در کوئری» + «نگهبان نسخه»

1. **سه کانال توکن:** کلاینت توکن والد را هم‌زمان در `Authorization` + `X-Parent-Token` + **`?pt=` در query string** می‌فرستد (و جلسه‌ی کودک در `X-Child-Session` + `?cs=`). هیچ پروکسی/کشی در جهان query string را حذف نمی‌کند — این کانال ضدگلوله است. سرور هر سه را می‌پذیرد (`auth.js`).
2. **نگهبان نسخه (`main.js` + `index.html`):** صفحه نسخه‌ی خود را در `window.__APP_VERSION` (درون‌خطی، همیشه تازه) دارد؛ اگر با نسخه‌ی ماژول‌ها فرق کند → یک reload خودکار با `?fresh=<v>` (حفظ hash، بدون لوپ). ترکیب «html تازه + ماژول کهنه از کش پروکسی» دیگر ممکن نیست بی‌سرگردان بماند.
3. **لاگ استاتیک:** سرور از این پس هر فایل js/html را با کد وضعیت لاگ می‌کند — بار بعدی دقیقاً معلوم است مرورگر کاربر چه نسخه‌ای گرفته.

تست: `api.test.js` +۱ (`?pt=` تنها → 200) → مجموع **۸۲**. نسخه: **1.0.7**.
