دو شکاف که وقتی آدمهای دیگر به پروژه وصل میشوند مهمتر میشوند.
کوکیِ نشستِ پنلِ ادمین و توکنِ CSRF بدونِ پرچمِ secure رد و بدل میشدند.
احرازِ هویتِ خودِ API کوکی نیست و اینها فقط برای ادمیناند — یعنی دقیقاً
همانجایی که اعتبارنامهی واقعی وارد میشود. حالا خارج از DEBUG امناند، و
SECURE_PROXY_SSL_HEADER هم اضافه شد چون TLS روی nginx تمام میشود و بدونش
جنگو درخواست را HTTP میبیند و کوکیِ امن اصلاً ست نمیشود.
SECURE_SSL_REDIRECT و HSTS عمداً روشن نشدند: اولی پشتِ پراکسیِ بدتنظیم
حلقهی ریدایرکت میسازد و کلِ سایت را میخواباند، دومی در مرورگرِ کاربر کش
میشود و عملاً برگشتناپذیر است. هر دو تصمیمِ زیرساختیاند نه کد.
/api/health حالا ترافیک را هم گزارش میدهد: تعدادِ کاربر، فعالهای ۲۴ ساعتِ
اخیر، و زمانِ آخرین فعالیت. تا امروز هیچ راهی نبود از بیرون بفهمیم فرانت
واقعاً به سرور رسیده یا نه — باید منتظر میماندیم کسی بگوید. فقط شمارش و
زمان؛ تست جداگانه بررسی میکند هیچ شماره یا نامی بیرون نرود.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
بازبینیِ کارِ امروز، سه مورد پیدا کرد.
/api/health وقتی مهاجرتِ اعمالنشده وجود داشت میشکست: کدِ فهرستکردنِ
مهاجرتها به migration.key تکیه میکرد که اصلاً وجود ندارد (فیلدها app_label
و name هستند). یعنی دقیقاً در همان حالتی که این بررسی برایش ساخته شده،
بهجای نامِ مهاجرتها فقط AttributeError برمیگرداند. حالا تستی دارد که
مهاجرتِ معلق را شبیهسازی میکند — چیزی که نبودش باعث شد اولین بار غلط بماند.
وارد کردنِ سوال با replace عددِ غلط گزارش میکرد: delete() در جنگو مجموعِ
همهی ردیفهای آبشاری را میدهد، پس «۵ سوال پاک شد» در واقع گزینهها و
پاسخها را هم میشمرد.
deploy.sh بررسیِ متغیرهای محیطیاش با تنظیماتِ جدید ناسازگار شده بود:
متغیرهایی را اجباری میدانست که حالا پیشفرض دارند، و فقط شل را میخواند نه
.env — یعنی روی سرورِ درست هم دیپلوی را رد میکرد. حالا بهجای تکرارِ منطقِ
تنظیمات، از خودِ جنگو میپرسد چه چیزی مؤثر است و گزارش میدهد.
کوچکتر: بررسیِ سلامت یک درخواست میزند نه دو تا، و شکستِ ریاستارت دیگر
اسکریپت را بیصدا تمام نمیکند.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
سوالها از قبل فلهای وارد میشدند ولی دو شکاف مانده بود: افزودنِ تکی عملاً
غیرقابلِ استفاده بود، و خودِ برنامهی درسی هیچ راهی جز ترمینالِ سرور نداشت.
افزودنِ تکیِ سوال: انتخابِ درس یک دراپداونِ ۱۳۰۷تایی بود. حالا autocomplete
است و بر اساسِ عنوانِ درس، فصل و پایه جستجو میشود.
برنامهی درسی (Grade → Unit → Node → Lesson) حالا از /admin/content/grade/
وارد و خارج میشود. تا امروز رساندنش به سرور یعنی اجرای rag_import_collection
و بعد seed_curriculum_from_textbook روی همان سرور — یعنی وابستگی به Qdrant و
به آدمی با دسترسیِ SSH. حالا یکبار لوکال ساخته میشود و فایلش بالا میرود.
همسانسازی با عنوان است نه با id: idها بینِ دو دیتابیس یکی نیستند و تکیه بر
آنها یعنی وارد کردن روی سرور محتوای بیربط را بازنویسی میکند.
وارد کردنِ برنامهی درسی عمداً چیزی پاک نمیکند و idempotent است — یک فایلِ
ناقص نباید محتوای سرور را از بین ببرد، و اجرای دوباره نباید چیزی را دو بار
بسازد. (وارد کردنِ سوالها اما replace دارد، چون جایگزینیِ سوالهای یک درس
کارِ رایجی است.)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
تا الان تنها راهِ گذاشتنِ سوال روی یک سرور، زدنِ دستور در ترمینالِ همان سرور
بود. یعنی هر تغییرِ محتوایی به کسی که SSH دارد وابسته میشد، تاریخچه نداشت و
برگشتپذیر نبود. محتوا داده است نه کد؛ باید با رابطِ کاربری ویرایش شود.
در /admin/content/question/ دکمهی «وارد کردنِ سوالها از فایل» اضافه شد، و
اکشنِ «دریافتِ فایلِ سوالهای انتخابشده» خروجی میدهد. خروجی دقیقاً همان قالبی
است که ورودی میپذیرد، پس چرخهی «بگیر → ویرایش کن → برگردان» بسته است و برای
گرفتنِ نمونه هم لازم نیست کسی مستندات بخواند.
قالب عمداً ساده است (lessonId، prompt، choices، correct) تا کسی که برنامهنویس
نیست هم بتواند در ویرایشگرِ متن درستش کند.
اعتبارسنجی قبل از هر نوشتنی کامل انجام میشود و کلِ فایل در یک تراکنش است:
فایلِ نامعتبر هیچ چیزی نمینویسد. وارد کردنِ نیمهکاره بدترین حالت بود، چون
کسی که فایل را داده فکر میکند کار شده ولی درس نصفه پر است.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>