diff --git a/CLAUDE.md b/CLAUDE.md index f59cc4e..52f90bc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -446,6 +446,39 @@ preferred setup, because there is then no key to leak. **Never let the server ru `django-insecure-…` fallback from `config/settings.py`: that string is committed here, so anyone who can read this repo can forge a token for any user.** +## شکلِ ثابتِ درس‌ها (`Lesson.figures`) و کشِ فرانت — روی سرور از ۲۰۲۶-۱۰-۰۷ ۱۶:۴۸ (`b93f43e`) + +**شکلِ درس یک بار ساخته و تأیید می‌شود و بعد ثابت است؛ هنگامِ نمایش هیچ فراخوانیِ مدلی نیست.** +`Lesson.figures` فهرستِ `{where: intro|example|step, index?, diagram}` است (`index` برای step از صفر). +`GET /api/lessons/{id}/intro` آن را برمی‌گرداند و فرانت (`LessonScreen`) با همان `Diagram` دستیار می‌کشد. +شکل در `content/seed/curriculum.json` هم می‌رود (`figures`)، و `seed_content` آن را **فقط در خانه‌ی خالی** می‌نشاند +(مثلِ `example`/`steps`). پس برای عوض‌کردنِ شکلِ درسی که روی سرور هست باید `figures` آن درس را خالی کرد و دوباره دیپلو کرد؛ +**شناسه‌ی درس روی سرور با لپ‌تاپ فرق دارد** (۳۰۰۳..۳۰۰۶ محلی = ۲۲۹۸..۲۳۰۱ سرور)، پس با شناسه‌ی محلی روی سرور کار نکن. + +- **ساخت:** `python manage.py gen_lesson_figures --grade 12 --limit 4 [--lesson ID] [--redo] [--dry-run]`. + همان مدلِ چت و کاتالوگِ `` و اعتبارسنجِ `rag.services.diagram.validate` (مسیرِ ارزانِ دستیار). + مدل می‌تواند `[]` بدهد؛ همه‌ی درس‌ها شکل نمی‌خواهند. شماره‌ی قدم‌ها در پرامپت ۱‌به‌بعد است (همان شماره‌ای که کاربر می‌بیند) + و کد یکی کم می‌کند؛ با شمارش از صفر شکل زیرِ قدمِ اشتباه می‌نشست. +- **هزینه (سنجیده ۲۰۲۶-۱۰-۰۷):** هر درس ≈ ۳٫۵ هزار توکنِ ورودی و ۰٫۱ تا ۰٫۶ هزار خروجی. صورتحسابِ GapGPT برای یک فراخوانی + ≈ ۰٫۰۳ سنت داد و فرمولِ رسمیِ `gpt-4.1-mini` ≈ ۰٫۱۵ سنت؛ این دو نمی‌خوانند و علتش پیدا نشد. برآوردِ ۳۰۰۰ درس ۱ تا ۴٫۵ دلار. +- **باید با چشم دید.** در همین چهار درس مدل خط‌شکسته را با `line` (بی‌پایان) کشید، یک بار فقط نقطه بی‌خط داد، نمودارِ تابع را با + بازه‌ی بزرگ له کرد، و برای قدمِ ۳ شکل را زیرِ قدمِ ۲ گذاشت. چهار درسِ اولِ حسابانِ ۱۲ (فصل «تابع») بازبینی شدند؛ + هیچ درسِ دیگری شکل ندارد. برچسب‌هایی مثلِ «A۲» و «g(x)=f(x)+۲» کنارِ لبه کمی ناجورند و رفع نشدند. +- **ایرادِ محتوا، نه شکل:** مثال و قدم‌های درسِ «تابع درجه سوم، توابع یک‌نوا…» کپیِ مثالِ «تبدیل نمودار توابع» است و با عنوانش + نمی‌خواند (از `fill_lesson_texts`). شکل‌هایش با همان متن می‌خوانند. +- **بازبینیِ زنده بی‌پیامک:** با یک `OTPCode` که خودت برای یکی از دموها (مثلاً `09120000105`، پایه‌ی ۱۲، کاربر ۱۴) در دیتابیسِ سرور + می‌سازی (کدِ تصادفی، ۵ دقیقه، از stdin نه از argv) وارد شو، توکن را در `localStorage['tadrisino.tokens']` (`{token, refreshToken}`) + بگذار و با `puppeteer-core` (در scratchpad، نه ریپو) از «نقشه ← فصل ← جزیره ← اول درس‌هاش رو بخونم» برو. آخرش `POST /api/auth/logout`. + توکنِ دسترسی را چاپ نکن (یک بار چاپ شد). + +**کشِ مرورگر:** سینیور شکلِ درس‌ها را در یک مرورگر نمی‌دید و در مرورگرِ دیگر می‌دید؛ API و bundleِ زنده درست بودند. علتِ احتمالی +(مستقیم دیده نشد): `index.html` فقط `etag` داشت و بی `Cache-Control` از کش بالا می‌آمد. در `/etc/nginx/sites-available/mathapp-front` +(فقط سایتِ ما؛ بکاپ کنارش `…bak-20261007`) حالا `Cache-Control: no-cache` برای همه و `immutable, max-age=1y` برای `/assets/` هست +(`nginx -t` و `reload`، نه restart). از بیرون `index.html` و مسیرهای اپ `no-cache` دادند؛ هدرِ `/assets/` را نشد دید چون +ArvanCloud فایل‌های js را خودش نگه می‌دارد (`x-cache: HIT`). **`config.js` هم از کشِ آروان می‌آید**؛ با عوض‌شدنِ دامنه‌ی API +کشِ آن را در پنلِ آروان پاک کن (نه فقط `index.html`). مرورگری که پیش از این تغییر `index.html` را کش کرده یک بار باید +«Clear site data» بزند. بارِ هم‌زمانِ هزار نفر آزموده نشد؛ استدلال این است که فایل‌های سنگین از CDN می‌آیند و `index.html` ۳۰۴ می‌گیرد. + ## وضعیت ۲۰۲۶-۱۰-۰۷ — روی سرور (`2779270`، ری‌استارت ۱۴:۱۶) بکاپ‌های همان روز در `.deploy-backups/`: `env-before-secretkey-redis-20261007-135850`،