From 3e63bd086008418da6a08842b55d9eff37124903 Mon Sep 17 00:00:00 2001 From: Zareian Date: Wed, 7 Oct 2026 13:48:20 +0330 Subject: [PATCH] Docs: 7ecb337 is live; record the Gitea 504 from the server and the bundle deploy Co-Authored-By: Claude Sonnet 5.5 --- CLAUDE.md | 14 ++++++++++---- docs/security-before-production.md | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 657ff8f..f80d091 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 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`), 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 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 island of every unit. Details in `docs/architecture.md`. @@ -827,8 +827,14 @@ migrationها اعمال شدند، سه‌یار و `nextLessonId` از بیر دست‌نخورده است و با `{{ block.super }}` گسترش داده شده. **بکاپ:** `deploy.sh` پیش از `migrate` خودش بکاپ می‌گیرد (`db-before-deploy-*`، ۲ تای آخر، -بی‌بکاپ migrate نمی‌شود)؛ فقط روی لپ‌تاپ آزموده شد و روی سرور هنوز اجرا نشده. بیرون از ماشین بکاپی -نیست. `sqlite3` روی سرور نصب نیست — برای بکاپِ دستی با `venv/bin/python` و +بی‌بکاپ migrate نمی‌شود)؛ روی سرور هم اجرا شد (۲۰۲۶-۱۰-۰۷، `integrity_check: ok`). بیرون از ماشین بکاپی +نیست. + +**⚠️ دیپلو از ۲۰۲۶-۱۰-۰۷ به‌خاطر Gitea:** از روی خودِ سرور `https://gitea.tadrisino2.ir` (حل‌شده به IPهای +ArvanCloud) ۵۰۴ می‌دهد، پس `deploy.sh` در `git fetch` می‌ایستد. آن روز کد با `git bundle` (از لپ‌تاپ، +`scp` به `.deploy-backups/`، `git fetch 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`. بخش‌های تاریخیِ زیر به‌ترتیبِ زمان نگه داشته شده‌اند چون درس‌هایشان هنوز معتبر است؛ diff --git a/docs/security-before-production.md b/docs/security-before-production.md index be178dd..cac4d7d 100644 --- a/docs/security-before-production.md +++ b/docs/security-before-production.md @@ -1,6 +1,6 @@ # پیش از پروداکشنِ واقعی: چیزهایی که عمداً باز مانده‌اند -**آخرین بازبینی با کد: ۲۰۲۶-۱۰-۰۷ (۱۵ مهر ۱۴۰۵)؛ با سرورِ زنده: ۲۰۲۶-۱۰-۰۴.** (تغییرهای ۱۰-۰۷ در کد است و تا دیپلوی روی سرور نیست.) +**آخرین بازبینی با کد: ۲۰۲۶-۱۰-۰۷ (۱۵ مهر ۱۴۰۵)؛ با سرورِ زنده: ۲۰۲۶-۱۰-۰۴؛ موارد دیپلوشده‌ی ۱۰-۰۷ (بک‌اند `7ecb337`، ۱۳:۴۲) فقط در حدِ سقفِ نرخ و سلامت از بیرون سنجیده شد.** این پروژه تا این تاریخ در حالتِ **دمو و ارائه‌ی کارآموزی** است، نه محصولِ نهایی. چند چیز عمداً باز گذاشته شده تا توسعه‌دهنده‌ها، فرانت‌کار و ارائه کار کنند. هر کدام برای یک سرورِ @@ -170,8 +170,8 @@ - **چیست:** SQLite در `~/mathapp-v2/db.sqlite3`، روی دیسکی که بینِ چند سرویس مشترک است و ~۸۳٪ پر است. `transaction_mode: IMMEDIATE` هم‌زمانی را درست ولی سریالی می‌کند. `deploy.sh` پیش از `migrate` بکاپ می‌گیرد (`.deploy-backups/db-before-deploy-*`، ۲ تای آخر؛ اگر بکاپ - نشد، migrate اجرا نمی‌شود)، ولی همه در همان پوشه و روی همان دیسک‌اند. روی لپ‌تاپ آزموده شد - (ساخت، `integrity_check`، حذفِ قدیمی‌ها)؛ روی خودِ سرور هنوز اجرا نشده. دیتابیسِ لپ‌تاپ ۱۲۶ مگابایت + نشد، migrate اجرا نمی‌شود)، ولی همه در همان پوشه و روی همان دیسک‌اند. روی لپ‌تاپ و در دیپلوی ۲۰۲۶-۱۰-۰۷ روی سرور آزموده شد + (ساخت و `integrity_check`؛ حذفِ قدیمی‌ها فقط روی لپ‌تاپ). دیتابیسِ لپ‌تاپ ۱۲۶ مگابایت است و دو بکاپ ~۲۵۰ مگابایت می‌گیرند؛ پیش از اولین دیپلو `df -h /` را ببینید. - **خطر:** از دست رفتنِ کلِ داده با یک خطای دیسک یا یک دستورِ اشتباه؛ پُر شدنِ دیسک سرویس‌های دیگر (Gitea، ایمیل) را هم می‌خواباند. @@ -293,7 +293,7 @@ | OTPِ ۶ رقمی با ۵ حدس برای هر کد؛ خروج از حساب توکن‌های قبلی را باطل می‌کند | `accounts/tests_audit_fixes.py` | | قلبِ صفر جوابِ سوال را می‌بندد؛ چکش داخلِ تراکنش است (بی‌جواب‌ماندن و جزیره‌ی قفل جداگانه در ردیفِ بعدی بسته شده‌اند) | `content/tests_hearts_gate.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` روی سرور باید خطای دسترسی بدهد | | پانزده مسیرِ خواندنی و نوشتنیِ کم‌خطر سقفِ نرخ دارند (بانکِ سوال و intro بی‌ورود، `progress/nodes`، `user/hearts`، اعلان، تیکت، پلن‌ها، وضعیتِ اشتراک، سفارش، پیشنهادها، affiliate، تاریخچه و فیدبکِ دستیار، خروج). با نرخِ ۳ در دقیقه درخواستِ چهارم ۴۲۹ می‌گیرد | `content/tests_read_throttles.py` | | ساختنِ دستیِ `OTPCode` و `Session` در پنل فقط برای ابرکاربر (کارمندِ عادی ۴۰۳) | `accounts/tests_security_review.py` (`StaffCannotMintLoginsTests`) |