- فونت قبلی (Pinar) از fontcdn.ir دانلود میشد که از کار افتاده و گوگلفونت هم در ایران مسدود است؛ در نتیجه هر بار فونت دانلود میشد و در نهایت Tahoma نمایش داده میشد
- فایلهای woff2 (Light/Regular/Bold) یک بار در public/fonts ذخیره شده و از همان سرور سرو میشوند — مرورگر کش میکند و هیچ وابستگی خارجی ندارد
- کلاس font-pinar برای سازگاری با کامپوننتها نگه داشته شد
- vite.config.ts دوباره /api و /media را به Traefik (پورت 5173) پروکسی میکند
- compose: بدون پورت مستقیم 8000/9000 — بکاند لوکال اینجا روی 8001 است و پورت 8000 متعلق به استک دیگر
- docker-compose.yml همه مقادیر محرمانه را با ${VAR:?} از .env میخواند — بدون .env استک بالا نمیآید
- docker-compose.prod.yml: ورودی 443 + ریدایرکت HTTP به HTTPS + گواهی Let's Encrypt و قواعد Host برای همه روترها
- healthcheck بکاند (api/health) و فرانت (wget) + سوار کردن frontend/dist در بکاند برای تزریق متا + روتر سئو (robots/sitemap/blog/projects) با اولویت 50
- سرویس mc با پروفایل tools + scripts/backup.sh (pg_dump + آینه MinIO با نگهداری ۱۴ روزه)
- .env.example ریشه + بروزرسانی READMEها
- مقالهها ستون status (draft/published) گرفتند — GET /api/site و همه انتهای عمومی فقط منتشرشده را برمیگردانند؛ autosave دیگر پیشنویس نیمهکاره را زنده نمیکند
- کلمه کلیدی هدف چکلیست سئو فیلد seo_keyphrase شد (قبلاً localStorage بود)
- robots.txt و sitemap.xml از بکاند + سرو /blog و /projects با تزریق title/description/OG/JSON-LD از دیتابیس برای خزندههای بدون JS (app/seo_pages.py)
- فرانت: applySeo در seo.ts (OG/توییتر/canonical/JSON-LD)، ادغام پیشنویس برای ادمین، برچسب پیشنویس در وبلاگ، حالت خالی وبلاگ، دکمه انتشار در صفحه نوشتن
- تغییر رمز ادمین POST /api/auth/change-password + دیالوگ «رمز» در نوار مدیریت
- محدودسازی ورود: ۵ تلاش ناموفق در ۱۵ دقیقه از هر IP → 429
- ساخت دکمه + برای ردیف سئوی صفحههای بدون ردیف (SingletonPill)
- تستهای pytest (۱۵ مورد) + پینکردن requirements + حذف package.json سرگردان فرانت
- پنل «بررسی سئو» در صفحه نوشتن مقاله — سبز/نارنجی/قرمز سازگار با فارسی:
طول عنوان، کلمه کلیدی هدف (در عنوان/پاراگراف اول/تیتر H2)، طول چکیده،
تعداد واژه، تیتربندی، متن جایگزین تصاویر، پیوندها و slug.
کلمه کلیدی در localStorage نگه داشته میشود (راهنمای ویرایشگر است، نه محتوا)
- جدول seo_meta: عنوان و توضیح متای هر صفحه (page_key برای هر ۸ صفحه،
seed خودکار، CRUD در /api/admin/seo-meta، خواندن در GET /api/site)
- تزریق عنوان/توضیح متا در فرانتاند: صفحههای فهرست از دیتابیس؛ صفحه
مقاله و پروژه از محتوای خودشان (بدون تداخل با اثر سطح والد)
- دکمه سئو روی هیرو هر صفحه و کنار هیرو صفحه اصلی (فقط حالت ویرایش)
- /admin/write (مقاله جدید) و /admin/write/:id (ویرایش) — صفحه کامل
بدون چرخه سایت: نوار بالا (بازگشت، وضعیت ذخیره، ذخیره، دیدن در سایت،
حذف)، عنوان بزرگ، تصویر شاخص، ویرایشگر TipTap تمامارتفاع و بخش
جزئیات انتشار (چکیده، دسته، تاریخ، زمان مطالعه، slug)
- ذخیره خودکار با debounce + flush هنگام خروج؛ اولین ذخیره مقاله را
منتشر میکند و مسیر به /admin/write/:id تغییر میکند
- قلمویژه مقالهها (مداد روی کارت) ادمین را به همین صفحه میبرد
(editHref روی EditableItem)؛ لینکهای data-admin-link در حالت ویرایش
کار میکنند
- رفع: create-on-unmount حذف شد (با draft قدیمی مقاله سرگردانی
میساخت) — unmount فقط برای مقاله ساختهشده PATCH میزند
- دکمه پررنگ «نوشتن مقاله جدید» بالای صفحه وبلاگ (فقط در حالت ویرایش) —
ساخت مقاله جدید و باز شدن مستقیم کشوی نوشتن
- ترتیب فیلدهای کشوی مقاله: عنوان، سپس ویرایشگر WYSIWYG — نوشتن اول،
متادیتا (دسته/تاریخ/اسلاگ و...) بعد
- رفع باگ: ساخت رکورد قبلاً کل درخت را reload میکرد و کشوی
تازهساختهشده بیدرنگ بسته میشد؛ حالا آیتم ساختهشده بهصورت
خوشبینانه به لیست اضافه میشود و کشو باز میماند
- Dockerfile فرانتاند: npm ci داخل کانتینر بیلد بهدلیل محدودیت شبکه
(registry.npmjs.org از داخل VM داکر در دسترس نیست) غیرقابلاعتماد بود؛
ایمیج حالا فقط Caddy است و خروجی بیلد هاست (npm run build → dist/) را
سرو میکند — بیلد ایمیج از چند دقیقه آویزان به چند ثانیه رسید
- docker-compose.yml: حذف build args از سرویس frontend
- config.ts: پیشفرض VITE_API_URL خالی است (درخواست هممبدأ از طریق
Traefik) — مقدار قبلی http://localhost:8000 میراث معماری قبل بود و
بیلد هاست را خراب میکرد
- README ریشه: بخش وبلاگ (ویرایشگر WYSIWYG، فرمت سند JSON، مهاجرت
خودکار مقالات قدیمی) + یادداشت بیلد هاست برای فرانتاند
- body مقاله از لیست پاراگراف به سند ProseMirror تغییر کرد:
{"type": "doc", "content": [...]} — در In/Out/Patch schemas
- اعتبارسنجی ساختاری (type=doc + content لیست) با field_validator —
امنیت رندر بر عهده رندر استاتیک TipTap در فرانتاند است
- app/migrations.py: مهاجرتهای DDL و داده در یکجا؛ migrate_article_bodies
ردیفهای قدیمی (لیست پاراگراف) را idempotent به سند تبدیل میکند —
در startup و seed اجرا میشود، دیتابیس موجود بدون از دست رفتن داده ارتقا مییابد
- seed بدنههای لیستی را قبل از درج به سند تبدیل میکند
- README بکاند: فرمت بدنه و رفتار مهاجرت مستند شد
- README ریشه: بخش «ویرایش زنده سایت» — ورود از /admin/login، حالت
ویرایش، ذخیره خودکار هر فیلد، ویرایش/حذف/ترتیب مجموعهها، آپلود تصویر
و نامرئی بودن لایه برای بازدیدکنندگان
- README بکاند: افزودن PATCH (ویرایش جزئی) و reorder به جدول
انتهاینقطهها + فهرست منابع دارای ستون position و نحوه مهاجرت سبک
لایه ویرایش بصری روی سایت واقعی (بدون داشبورد جدا):
- ورود ادمین از مسیر پنهان /admin/login با توکن JWT (localStorage) و
AdminContext شامل isEditMode و وضعیت ذخیره (همگام/در حال ذخیره/خطا)
- AdminBar شناور پایین صفحه (فقط برای کاربر واردشده): کلید حالت ویرایش،
وضعیت ذخیره، خروج — حالت ویرایش در sessionStorage میماند
- InlineEdit: در حالت عادی دقیقاً همان HTML قبلی (بدون تغییر چیدمان)؛
در حالت ویرایش کادرخطچین + contentEditable با ذخیره خودکار در blur
(Enter ذخیره، Esc لغو) — وایرایششده روی همه متنهای سایت: هیرو،
تیتر بخشها، هیرو صفحات، داستان، فرم تماس، خبرنامه، فوتر، منو،
برچسبهای وضعیت پروژه و...
- کشوی عمومی EntityDrawer با پیکربندی متمرکز برای ۱۴ مجموعه (خدمات،
پروژهها، مقالات، نظرات، سوالات، تیم، تایملاین، آمار، چرا آرامش،
مدلهای سرمایهگذاری، مراحل کار، دفاتر، گالری، منو): ویرایش چندفیلدی،
افزودن، حذف و جابهجایی ترتیب (▲▼) با ذخیره خودکار هر فیلد
- دکمههای شناور ویرایش/حذف/ترتیب فقط در حالت ویرایش روی آیتمها
- کشوهای یگانه: برند و لوگو، تنظیمات هیرو، فرم تماس، خبرنامه، فوتر،
قبل/بعد و نقلقول داستان — آپلود تصویر به MinIO از همانجا
- بهروزرسانی خوشبینانه SiteContext (updateSite) پس از هر PATCH؛
مسیرها در حالت ویرایش کلیک نمیشوند؛ breadcrumb محافظ beforeunload
- PATCH /api/admin/{resource}/{id} — ویرایش جزئی؛ فقط فیلدهای ارسالشده
بهروزرسانی میشوند (PUT قبلاً کل رکورد را جایگزین میکرد و برای
ویرایش زنده قابل استفاده نبود). اسکیماهای Patch بهصورت خودکار از
اسکیماهای In با create_model ساخته میشوند (هر ۲۴ منبع).
- ستون position برای ۱۴ جدول مجموعهای (خدمات، پروژهها، مقالات، نظرات،
سوالات، تیم، تایملاین، آمار، چرا آرامش، مدلهای سرمایهگذاری، مراحل کار،
دفاتر، گالری، منو) — مهاجرت سبک idempotent در startup و seed
(ALTER TABLE ADD COLUMN IF NOT EXISTS) تا دیتابیسهای موجود هم ارتقا یابند
- POST /api/admin/{resource}/reorder — ذخیره ترتیب جدید بر اساس لیست id
- خواندن عمومی بر اساس (position, id) مرتب میشود؛ رکورد جدید در انتهای لیست
- seed فقط جدولهای خالی را با position صحیح پر میکند
- سرویس traefik:v3 روی پورت ۵۱۷۳ (پورت هاست) — تنها نقطه ورود استک:
/ → frontend (فایلهای استاتیک SPA)
/api → backend:8000
/media → MinIO:9000 با rewrite به باکت aramesh-media
مسیریابی با Docker labels در docker-compose.yml
- حذف کامل nginx: Caddy فقط فایلهای استاتیک را سرو میکند
(fallback به index.html برای SPA، کش یکساله immutable برای assets/)
- سرویس minio + minio-setup (ساخت خودکار باکت و دسترسی عمومی خواندن —
یکبار در اولین اجرا)؛ کنسول MinIO روی پورت ۹۰۰۱
- وابستگی backend به سلامت db و minio
- vite dev: پروکسی /api و /media به Traefik برای هممبدأ بودن در توسعه
- main.py: عنوان و توضیحات اپ FastAPI و نام اپ در پاسخ سلامت (ArameshPlaza API به Aramesh Building Group API)
- api/public.py: نام اپ در پاسخ سلامت
- seed.py و seed_data.py: توضیحات اسکریپت و دادههای اولیه (نام برند، ایمیل، تایملاین، تستیمونیال، FAQ)
- README و README بکاند: متنهای مرتبط با برند
شناسههای داخلی دیتابیس (نام دیتابیس arameshplaza) بدون تغییر باقی ماندهاند.
- data/site.ts: نام برند، ایمیل تماس (info@arameshplaza.com به info@arameshbuildinggroup.com)، تیتر تایملاین، نقلقول تستیمونیال و سؤال FAQ
- کامپوننتها: کپی فوتر و کپیرایت، aria-label تماس شناور، معرفی و alt تصویر هیرو، لید و alt گالری، کپی بخش داستان، تیتر خبرنامه، تیتر «چرا گروه ساختمانی آرامش»، لید مقالات
- صفحات: لید درباره ما، کپی مشارکت در سرمایهگذاری، لید وبلاگ
- index.html: عنوان صفحه