- /admin/projects/new و /admin/projects/:id — همهٔ فیلدها در یک صفحه با
ورودی دوزبانهٔ صریح (فارسی/English)، ذخیره، حذف
- GalleryField تازه: گالری چندتصویری فقط با آپلود به MinIO (حذف/جابهجایی/
افزودن چندفایلی) — فیلد «هر خط یک URL» دیگر استفاده نمیشود
- مدادِ کارت پروژه و دکمهٔ «افزودن پروژه» به صفحهٔ اختصاصی هدایت میشوند؛
دکمهٔ ویرایش روی صفحهٔ جزئیات هم لینک همان صفحه است
- دکمههای CTA: بازگشت به ButtonLink شیشهای (اصلی با دایرهٔ مسی، ثانویه مات)
- کارت شناور آمار (badge_value/badge_label) که UI v1 حذف کرده بود برگشت —
فیلدهایش در کشوی «تنظیمات هیرو» دوباره معنا دارند
- Button.tsx که قبلاً بازگردانده شده بود دوباره استفاده میشود
- دکمهٔ تغییر زبان: کپسول بزرگ دوزبانه → دکمهٔ کوچک آیکون+متن (طرح قبلی)
- ساختار صفحهٔ جزئیات پروژه: بازگشت به چیدمان قبلی (دیتابیسمحور بود و میماند)
- قالب پرسشوپاسخ: بازگشت به چیدمان دوستونه (تیتر کنار آکاردئون)
توجه: بخشی از UI v1 (fatemeh) عمداً برگردانده شده به درخواست تیم UI؛
بقیهٔ تغییرات آن کامیت سر جایش است. ویرایشپذیری دیتابیسمحور پروژهها
و دکمهٔ ویرایش، روی همین ساختار قدیمی دوباره اعمال شدهاند.
- page-heroes به فهرست موجودیتهای پنل اضافه شد و PageHero یک دکمهٔ واضح
«عنوان، سرآغاز و تصویر هیروی این صفحه» گرفت (پیشتر فقط ویرایش درجای
نامرئی روی خود متن بود).
- صفحهٔ پروژهها و صفحهٔ جزئیات پروژه حالا از دیتابیس خوانده میشوند
(فایل استاتیک projectsData فقط جانشین دیتابیس خالی/اسلاگهای قدیمی است) —
پیشتر ویرایش پنل روی این دو صفحه اصلاً نمایش داده نمیشد.
- روی لیست پروژهها دکمهٔ ویرایش/جابهجایی/حذف و «افزودن پروژه» اضافه شد و
روی صفحهٔ جزئیات هر پروژه دکمهٔ ویرایش همان پروژه.
- کپشن: قاعدهٔ وسطچینِ .article-body figcaption با قاعدههای [data-dir=...] برای
راست/چپچین بازنویسی میشد و عملاً وسطچین نمیشد؛ figcaption از آن فهرستها
برداشته شد. متن کپشن در ویرایشگر هم وسطچین شد تا با خروجی سایت یکی باشد.
- نام تصویر: نامی که پیش از بارگذاری نوشته میشود، حالا همان Alt تصویر میشود
(پیشتر نام فایل مبنا بود و باید دستی در جعبهٔ زیر تصویر اصلاح میشد).
- فهرست مطالب: H3 با ps-4 فقط ۴ پیکسل بیشتر از H2 تورفتگی داشت (عملاً نامرئی)؛
حالا ps-6 با فونت یک پله کوچکتر.
پیشنمایش خصوصی دو بار احراز هویت میخواست (Basic Auth لبه + ورود خود پنل) و
هر origin (www/apex/.ir) هم پرسش جداگانهای داشت؛ نتیجه سردرگمی تیم.
حالا روترهای /admin و /api میدلور preview-auth ندارند (noindex میماند) و
پنل با همان ورود خودش کار میکند؛ صفحات عمومی همچنان خصوصیاند.
docker compose مقادیر .env را خودش تفسیر میکند؛ هش htpasswd شامل $apr1$...
است و بدون کوتیشن، $apr1 و بخشهای بعدی بهعنوان متغیر خالی جایگزین میشدند
(برچسب تبدیل به preview:/OBoRS/... میشد) و پیشنمایش خصوصی هرگز رمز را
نمیپذیرفت. حالا env_set مقدارهای دارای $ را تککوتیشن میگذارد و env_get
کوتیشن را برمیدارد.
بدون آن، psycopg3 تاپل برمیگرداند و row["model"] خطای
«tuple indices must be integers or slices, not str» میداد؛ نتیجه:
«Initial index sync failed» و unavailable ماندن چت با وجود امبد موفق.
- content.py: ستون desc در SQL بدون کوتیشن بود و PostgreSQL آن را کلمهٔ کلیدی
میگیرد؛ نتیجه: «Initial index sync failed: syntax error at or near "desc"»
در استارت و غیرقابل استفاده ماندن چت تا reindex. حالا "desc" کوتیشن شده.
- Dockerfile: با اینکه سرور GPU ندارد، pip نسخهٔ CUDA تورچ را از PyPI میگرفت
(ایمیج ۹.۷GB با کتابخانههای nvidia). اول torch از ایندکس CPU نصب میشود.
نمونهٔ OpenPanel موجود (stats.*) با یک پروژهٔ دوم برای این سایت استفاده میشود؛
VITE_OPENPANEL_URL/VITE_OPENPANEL_CLIENT_ID در زمان بیلد تزریق میشوند و در
نبودشان همهچیز بیاثر است. API عمومی track() تغییر نکرده و مسیر Umami هم
برای عقبنشینی دستنخورده مانده.
- gen-env.sh: rand با دو آرگومان صدا زده میشد ولی فقط $1 را میخواند؛
openssl rand -hex بدون تعداد بایت خروجی خالی و کد ۰ میدهد، پس fallback
هرگز اجرا نمیشد و .env با رازهای خالی ساخته میشد. حالا تعداد بایت
رعایت میشود و اگر مقداری خالی بماند، اسکریپت با خطا متوقف میشود.
- preview-mode.sh: python روی اوبونتو ۲۴.۰۴ وجود ندارد (فقط python3).
بازگرداندن من اشتباه بود — تیم UI عمداً این بخش را برداشته/جابهجا کرده است.
جاینگهدار خودشان (section خالی با aria-label) حفظ شد و فقط importهای
بیاستفاده حذف شدند تا تایپچک تمیز بماند.
شاخه UI این بخش را به یک section خالی تبدیل کرده بود (کار ناتمام)؛
ادغام خودکار آن را بیصدا حذف میکرد. محتوای دفاتر (شهر/نشانی/ساعات)
با همان چیدمان و ویرایشپذیری مدیریتی برگردانده شد.
- گیت ورود Traefik (Basic Auth) روی همه مسیرها: سایت، API، تصاویر و چت — بدون رمز فقط ۴۰۱
- لایه دوم noindex: هدر X-Robots-Tag روی همه پاسخها + robots.txt مسدودکننده + نقشه سایت خالی
- اسکریپت scripts/preview-mode.sh on|off|status — ساخت خودکار نام کاربری/رمز و هماهنگکردن .env
- دو دامنه (DOMAIN + DOMAIN_ALIAS) با گواهی TLS و ریدایرکت ۳۰۱ دامنه دوم به اصلی در زمان انتشار
- اسکیمای FAQPage در پوسته سئوی سمت سرور (فارسی و انگلیسی) برای خزندههای بدون جاوااسکریپت
- مستندسازی جریان پیشنمایش و چکلیست انتشار در README و .env.example
- Alt/Title تصویر شاخص اکنون ذخیره میشود (ستونهای جدید image_alt/image_title — قبلاً بیصدا دور ریخته میشد)
- Alt و Title تصاویر داخل متن پس از درج هم قابل ویرایشاند (کنار کپشن)
- نام فایل ذخیرهسازی خوانا: نام دلخواه هنگام درج یا نام خود فایل (بهجای UUID خالی)
- پنل پرسشوپاسخ پایان مقاله (ستونهای faqs/faqs_en) با ظاهر آکاردئونی سایت و اسکیمای FAQPage
- چسباندن از Outline و هر منبع خارجی: تصاویر خودکار دانلود و در Object Storage سایت میزبانی میشوند (endpoint جدید import-image با محافظ SSRF) + دکمه میزبانی مجدد روی تصاویر خارجی موجود
- traefik pin v3.3 -> v3.6: v3.3's old docker client fails against
Engine 29 socket proxy (empty daemon errors, no routers)
- backend/minio/chatbot/umami: traefik.docker.network hint — Traefik
picked the internal-network IP for multi-network services and replies
were hairpin-dropped (all backend routes hung)
- db-init: psql needs an explicit -d arameshplaza (no default db 'aramesh'),
set -e so failures actually fail; one-shot folded-YAML needs semicolons
- chatbot image: drop g++ (apt unreachable in build network; all wheels
prebuilt) and mkdir /data before chown (VOLUME does not create it)
- frontend image: create caddy user (alpine image has none) with writable
/config and /data
- monitoring: blackbox probes replace raw metric scrapes of JSON/HTML
health endpoints (they reported 'down' while healthy); blackbox joins
edge; SITE_URL passed via env (Prometheus has no ${VAR:-default}
expansion); ContainerMemoryNearLimit PromQL fixed (comparison inside
label braces); HostDiskAlmostFull filters WSL/Docker-Desktop
pseudo-mounts
- alertmanager: config rendered by stack.sh (no env expansion in AM) and
delivered to Bale (tapi.bale.ai); stack.sh monitoring command
- machine-local override: minio console/API moved to 29001/29000
Added animated auto-opening link modal, custom image node with isolated caption deletion, fixed single-select category data binding, improved featured image layout, and updated README.
- مرحله npm run build فرانتاند (لازم برای اولین اجرا) اضافه شد
- اشاره به seed شدن خودکار تصاویر از seed-media در بیلد تازه
- یادآوری اینکه هیچ فایل رمزدار در گیت نیست و فقط .env.example کپی شود
فایلهای اصلی Pinar از شاخه feature/frontend-updates گرفته شد (fatemeh sane آنها را
سلفهاست کرده بود) — همان فونتی که پیشتر CDN از کار افتادهاش را سرو میکرد:
- ۵ وزن (Light 300، Regular 400، Bold 700، ExtraBold 800، Black 900) در
frontend/public/fonts/pinar بهصورت woff2 + ttf
- index.css: Pinar فونت اصلی و Vazirmatn جایگزین پشتیبان
- tailwind: کلاس pinar دوباره Pinar را اول میگذارد
تا وقتی کسی کلون/بیلد تازه میگیرد، همان تصاویر را داشته باشد:
- seed-media شامل هر ۱۹ فایل تصویری است که در دیتابیس با پیشوند /media ثبتاند
- minio-setup بعد از ساخت باکت، محتوای seed-media را با mc mirror در bucket
میگذارد — روی حجم موجود idempotent است و داده تازه را نمیخورد
ابزار یکباره برای وقتی میزبان عکس (مثل i.postimg.cc) در دسترس است:
- از /api/site فهرست همه تصاویرِ URL خارجی را میگیرد، هرکدام را دانلود و از
انتهای ادمین در MinIO آپلود میکند و مقدار فیلد را به /media/... بازنویسی میکند
- اعتبارسنجی فایل با هدر (تا HTML/خطا ذخیره نشود) + فرمت واقعی برای آپلود
- خروجی گزارش ردیفهای ناتمام برای اجرای دوباره
دیتابیسِ همین سایت هم با آن منتقل شد: ۱۹ تصویر در باکت aramesh-media و دیگر
هیچ URL خارجی (postimg/housedesign) در محتوای سایت نیست.
- فونت قبلی (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 سرگردان فرانت