Docs: 7ecb337 is live; record the Gitea 504 from the server and the bundle deploy

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 13:48:20 +03:30
parent 7ecb337263
commit 3e63bd0860
2 changed files with 14 additions and 8 deletions

View File

@@ -298,12 +298,12 @@ grades 8–12 does; the 39 that fall short are all in grades 3/6/7.
Finishing the quiz finishes the island: `POST /api/nodes/{id}/quiz/complete` marks the node Finishing the quiz finishes the island: `POST /api/nodes/{id}/quiz/complete` marks the node
completed whatever the score (the owner's call on 2026-09-24: keep it simple) and returns completed whatever the score (the owner's call on 2026-09-24: keep it simple) and returns
`nextNodeId`. Since 2026-10-07 it refuses (in code; deployed only after the next release) a node `nextNodeId`. Since 2026-10-07 13:42 (live, `7ecb337`) it refuses a node
that is locked on the map (403 `node_locked`, same rule as `/api/home`, `content.views.node_is_unlocked`), that is locked on the map (403 `node_locked`, same rule as `/api/home`, `content.views.node_is_unlocked`),
and a user who has not answered every quiz question (409 `answers_missing`; and a user who has not answered every quiz question (409 `answers_missing`;
the required count is `max(client totalQuestions, min(4, questions in node))`, so the client cannot the required count is `max(client totalQuestions, min(4, questions in node))`, so the client cannot
understate it). A node or lesson with no questions has nothing to answer: it passes when unlocked (no stars, no XP) so it does not block the chain, and is still refused when locked. `POST /api/lessons/{id}/complete` has the same lock and answer rules. Before that, understate it). A node or lesson with no questions has nothing to answer: it passes when unlocked (no stars, no XP) so it does not block the chain, and is still refused when locked. `POST /api/lessons/{id}/complete` has the same lock and answer rules. Before that,
only a user with zero hearts and no answers was refused; anyone else finished any island, locked or not. Before it existed, a node only completed when every one of its 8–13 lessons only a user with zero hearts and no answers was refused; anyone else finished any island, locked or not. Verified by 860 local tests and by outside probes (health, 401s, throttle); **not** verified by a real login on the server, so do one manual quiz after the next deploy. Before it existed, a node only completed when every one of its 8–13 lessons
was completed one by one, so a student playing node quizzes was stuck after the first was completed one by one, so a student playing node quizzes was stuck after the first
island of every unit. Details in `docs/architecture.md`. island of every unit. Details in `docs/architecture.md`.
@@ -827,8 +827,14 @@ migrationها اعمال شدند، سه‌یار و `nextLessonId` از بیر
دست‌نخورده است و با `{{ block.super }}` گسترش داده شده. دست‌نخورده است و با `{{ block.super }}` گسترش داده شده.
**بکاپ:** `deploy.sh` پیش از `migrate` خودش بکاپ می‌گیرد (`db-before-deploy-*`، ۲ تای آخر، **بکاپ:** `deploy.sh` پیش از `migrate` خودش بکاپ می‌گیرد (`db-before-deploy-*`، ۲ تای آخر،
بی‌بکاپ migrate نمی‌شود)؛ فقط روی لپ‌تاپ آزموده شد و روی سرور هنوز اجرا نشده. بیرون از ماشین بکاپی بی‌بکاپ migrate نمی‌شود)؛ روی سرور هم اجرا شد (۲۰۲۶-۱۰-۰۷، `integrity_check: ok`). بیرون از ماشین بکاپی
نیست. `sqlite3` روی سرور نصب نیست — برای بکاپِ دستی با `venv/bin/python` و نیست.
**⚠️ دیپلو از ۲۰۲۶-۱۰-۰۷ به‌خاطر Gitea:** از روی خودِ سرور `https://gitea.tadrisino2.ir` (حل‌شده به IPهای
ArvanCloud) ۵۰۴ می‌دهد، پس `deploy.sh` در `git fetch` می‌ایستد. آن روز کد با `git bundle` (از لپ‌تاپ،
`scp` به `.deploy-backups/`، `git fetch <bundle> main:refs/remotes/origin/main`، هشِ کامیت مقایسه شد،
`git reset --hard origin/main`، `SKIP_PULL=1 ./deploy.sh`) رسید. علتِ ۵۰۴ پیدا نشد (مسیرِ آروان↔سرور؛ از لپ‌تاپ ۲۰۰)؛
مرحله‌ی «بررسیِ سلامت»ِ `deploy.sh` هم از داخلِ سرور همیشه شکست می‌خورد (همان مسیر). سلامت را از بیرون بسنجید. `sqlite3` روی سرور نصب نیست — برای بکاپِ دستی با `venv/bin/python` و
`sqlite3.Connection.backup()` بگیر، نه با `cp`. `sqlite3.Connection.backup()` بگیر، نه با `cp`.
بخش‌های تاریخیِ زیر به‌ترتیبِ زمان نگه داشته شده‌اند چون درس‌هایشان هنوز معتبر است؛ بخش‌های تاریخیِ زیر به‌ترتیبِ زمان نگه داشته شده‌اند چون درس‌هایشان هنوز معتبر است؛

View File

@@ -1,6 +1,6 @@
# پیش از پروداکشنِ واقعی: چیزهایی که عمداً باز مانده‌اند # پیش از پروداکشنِ واقعی: چیزهایی که عمداً باز مانده‌اند
**آخرین بازبینی با کد: ۲۰۲۶-۱۰-۰۷ (۱۵ مهر ۱۴۰۵)؛ با سرورِ زنده: ۲۰۲۶-۱۰-۰۴.** (تغییرهای ۱۰-۰۷ در کد است و تا دیپلوی روی سرور نیست.) **آخرین بازبینی با کد: ۲۰۲۶-۱۰-۰۷ (۱۵ مهر ۱۴۰۵)؛ با سرورِ زنده: ۲۰۲۶-۱۰-۰۴؛ موارد دیپلوشده‌ی ۱۰-۰۷ (بک‌اند `7ecb337`، ۱۳:۴۲) فقط در حدِ سقفِ نرخ و سلامت از بیرون سنجیده شد.**
این پروژه تا این تاریخ در حالتِ **دمو و ارائه‌ی کارآموزی** است، نه محصولِ نهایی. چند چیز این پروژه تا این تاریخ در حالتِ **دمو و ارائه‌ی کارآموزی** است، نه محصولِ نهایی. چند چیز
عمداً باز گذاشته شده تا توسعه‌دهنده‌ها، فرانت‌کار و ارائه کار کنند. هر کدام برای یک سرورِ عمداً باز گذاشته شده تا توسعه‌دهنده‌ها، فرانت‌کار و ارائه کار کنند. هر کدام برای یک سرورِ
@@ -170,8 +170,8 @@
- **چیست:** SQLite در `~/mathapp-v2/db.sqlite3`، روی دیسکی که بینِ چند سرویس مشترک است و - **چیست:** SQLite در `~/mathapp-v2/db.sqlite3`، روی دیسکی که بینِ چند سرویس مشترک است و
~۸۳٪ پر است. `transaction_mode: IMMEDIATE` هم‌زمانی را درست ولی سریالی می‌کند. `deploy.sh` ~۸۳٪ پر است. `transaction_mode: IMMEDIATE` هم‌زمانی را درست ولی سریالی می‌کند. `deploy.sh`
پیش از `migrate` بکاپ می‌گیرد (`.deploy-backups/db-before-deploy-*`، ۲ تای آخر؛ اگر بکاپ پیش از `migrate` بکاپ می‌گیرد (`.deploy-backups/db-before-deploy-*`، ۲ تای آخر؛ اگر بکاپ
نشد، migrate اجرا نمی‌شود)، ولی همه در همان پوشه و روی همان دیسک‌اند. روی لپ‌تاپ آزموده شد نشد، migrate اجرا نمی‌شود)، ولی همه در همان پوشه و روی همان دیسک‌اند. روی لپ‌تاپ و در دیپلوی ۲۰۲۶-۱۰-۰۷ روی سرور آزموده شد
(ساخت، `integrity_check`، حذفِ قدیمی‌ها)؛ روی خودِ سرور هنوز اجرا نشده. دیتابیسِ لپ‌تاپ ۱۲۶ مگابایت (ساخت و `integrity_check`؛ حذفِ قدیمی‌ها فقط روی لپ‌تاپ). دیتابیسِ لپ‌تاپ ۱۲۶ مگابایت
است و دو بکاپ ~۲۵۰ مگابایت می‌گیرند؛ پیش از اولین دیپلو `df -h /` را ببینید. است و دو بکاپ ~۲۵۰ مگابایت می‌گیرند؛ پیش از اولین دیپلو `df -h /` را ببینید.
- **خطر:** از دست رفتنِ کلِ داده با یک خطای دیسک یا یک دستورِ اشتباه؛ پُر شدنِ دیسک - **خطر:** از دست رفتنِ کلِ داده با یک خطای دیسک یا یک دستورِ اشتباه؛ پُر شدنِ دیسک
سرویس‌های دیگر (Gitea، ایمیل) را هم می‌خواباند. سرویس‌های دیگر (Gitea، ایمیل) را هم می‌خواباند.
@@ -293,7 +293,7 @@
| OTPِ ۶ رقمی با ۵ حدس برای هر کد؛ خروج از حساب توکن‌های قبلی را باطل می‌کند | `accounts/tests_audit_fixes.py` | | OTPِ ۶ رقمی با ۵ حدس برای هر کد؛ خروج از حساب توکن‌های قبلی را باطل می‌کند | `accounts/tests_audit_fixes.py` |
| قلبِ صفر جوابِ سوال را می‌بندد؛ چکش داخلِ تراکنش است (بی‌جواب‌ماندن و جزیره‌ی قفل جداگانه در ردیفِ بعدی بسته شده‌اند) | `content/tests_hearts_gate.py` | | قلبِ صفر جوابِ سوال را می‌بندد؛ چکش داخلِ تراکنش است (بی‌جواب‌ماندن و جزیره‌ی قفل جداگانه در ردیفِ بعدی بسته شده‌اند) | `content/tests_hearts_gate.py` |
| `select_for_update` مؤثر با `transaction_mode: IMMEDIATE`؛ مقایسه‌ی زمان‌ثابتِ `X-Internal-Key` | `payment/tests_audit_fixes.py` | | `select_for_update` مؤثر با `transaction_mode: IMMEDIATE`؛ مقایسه‌ی زمان‌ثابتِ `X-Internal-Key` | `payment/tests_audit_fixes.py` |
| `deploy.sh` پیش از `migrate` بکاپِ `db-before-deploy-*` می‌گیرد، `integrity_check` می‌کند و اگر نشد migrate را اجرا نمی‌کند | فقط دستی آزموده شد: مرحله‌ی «بکاپِ دیتابیس» روی دیتابیسِ لپ‌تاپ، ۷ بار پشتِ هم | | `deploy.sh` پیش از `migrate` بکاپِ `db-before-deploy-*` می‌گیرد، `integrity_check` می‌کند و اگر نشد migrate را اجرا نمی‌کند | مرحله‌ی «بکاپِ دیتابیس»: ۷ بار روی لپ‌تاپ و یک بار روی سرور (۶ مگابایت، `integrity_check: ok`) |
| دیتابیس و بکاپ‌ها فقط برای صاحبِ سرویس خواندنی‌اند (مرحله‌ی «مجوزِ فایل‌های داده» در `deploy.sh`) | با `sudo -u nobody head -c 15 ~/mathapp-v2/db.sqlite3` روی سرور باید خطای دسترسی بدهد | | دیتابیس و بکاپ‌ها فقط برای صاحبِ سرویس خواندنی‌اند (مرحله‌ی «مجوزِ فایل‌های داده» در `deploy.sh`) | با `sudo -u nobody head -c 15 ~/mathapp-v2/db.sqlite3` روی سرور باید خطای دسترسی بدهد |
| پانزده مسیرِ خواندنی و نوشتنیِ کم‌خطر سقفِ نرخ دارند (بانکِ سوال و intro بی‌ورود، `progress/nodes`، `user/hearts`، اعلان، تیکت، پلن‌ها، وضعیتِ اشتراک، سفارش، پیشنهادها، affiliate، تاریخچه و فیدبکِ دستیار، خروج). با نرخِ ۳ در دقیقه درخواستِ چهارم ۴۲۹ می‌گیرد | `content/tests_read_throttles.py` | | پانزده مسیرِ خواندنی و نوشتنیِ کم‌خطر سقفِ نرخ دارند (بانکِ سوال و intro بی‌ورود، `progress/nodes`، `user/hearts`، اعلان، تیکت، پلن‌ها، وضعیتِ اشتراک، سفارش، پیشنهادها، affiliate، تاریخچه و فیدبکِ دستیار، خروج). با نرخِ ۳ در دقیقه درخواستِ چهارم ۴۲۹ می‌گیرد | `content/tests_read_throttles.py` |
| ساختنِ دستیِ `OTPCode` و `Session` در پنل فقط برای ابرکاربر (کارمندِ عادی ۴۰۳) | `accounts/tests_security_review.py` (`StaffCannotMintLoginsTests`) | | ساختنِ دستیِ `OTPCode` و `Session` در پنل فقط برای ابرکاربر (کارمندِ عادی ۴۰۳) | `accounts/tests_security_review.py` (`StaffCannotMintLoginsTests`) |