سئوی سمت سرور (backend/app/seo_pages.py) - متا/canonical/hreflang/JSON-LD برای همهٔ صفحات عمومی (شش صفحهٔ استاتیک فارسی که قبلاً پوستهٔ خالی بودند) - canonical سمت سرور (قبلاً فقط با JS ست میشد)، ۴۰۴ واقعی برای مسیرهای ناموجود - اسکیما: Organization با لوگوی ImageObject، FAQPage، LocalBusiness، BreadcrumbList، CreativeWork پروژه با همهٔ تصاویر بهصورت ImageObject (نام/توضیح + موقعیت پروژه) - hreflang فقط وقتی ترجمهٔ انگلیسی واقعاً وجود دارد؛ sitemap با URLهای درصدگذاریشده - llms.txt و robots.txt تازهساز از دیتابیس؛ سیاست صریح خزندههای AI + Allow: /api/site - _site_content_html: محتوای واقعی سایت بهصورت HTML خوانا در <noscript> — خزندههای بدون جاوااسکریپت (GPTBot/OAI-SearchBot/ClaudeBot/PerplexityBot) از ۲۴۰ نویسه به ۸٬۵۰۰+ نویسه محتوای معنایی میرسند - Cache-Control: no-store روی HTML و llms.txt (جلوگیری از کش کهنهٔ CDN)، max-age روی sitemap فرانتاند - api.tsx: خواندن دادهٔ تزریقشدهٔ سرور (window.__SITE__) بهعنوان حالت اولیه — رندر بدون XHR - App.tsx: اسکلت بارگذاری بهجای DOM خالی (رفع Soft 404 گوگل) - index.html: فاوآیکون واقعی برند (قبلاً به vite.svg ناموجود اشاره میکرد) + preload فونت زیرساخت - Dockerfile: آینهٔ PyPI (Tsinghua/Aliyun) — PyPI برای IP ایران بلاک است - Caddyfile: هر مسیر پسونددار بدون فایل واقعی ۴۰۴ میگیرد (قبلاً HTML اسپا برمیگرداند) - docker-compose.prod.yml: مسیرهای seo برای صفحات استاتیک + llms.txt + کلیدهای IndexNow داده - seed_data*.py: حذف دفاتر و معرفیهای دمو (که در هر استقرار برمیگشتند)؛ تنها دفتر واقعی: اصفهان، ملاصدرا شمالی داراییها - فاوآیکون/آیکونهای برند از لوگوی رسمی + کلیدهای IndexNow
40 lines
1.8 KiB
Caddyfile
40 lines
1.8 KiB
Caddyfile
{
|
|
# پنل مدیریت Caddy لازم نیست — سطح حمله کمتر
|
|
admin off
|
|
}
|
|
|
|
:80 {
|
|
root * /srv
|
|
encode zstd gzip
|
|
|
|
# فایلهای هشدار بیلد: کش بلندمدت بیرحم — ولی هرگز fallback به index.html نداشته باشند؛
|
|
# پاسخ 200ٔ HTML برای یک مسیر /assets/* نبوده (مثلاً هنگام پنجرهٔ تعویض کانتینر در استقرار)
|
|
# توسط CDN (WCDN، سیاست SMART) با همین هدر immutable یک سال کش میشود و اسکریپت ماژول
|
|
# را برای همه بازدیدکنندهها میشکند. فایل ناموجود در assets باید 404 بدهد، نه HTML.
|
|
@assets path /assets/*
|
|
handle @assets {
|
|
file_server
|
|
}
|
|
|
|
# هر مسیر دارای پسوند فایل (فونت، تصویر، نقشه، آیکون، …): فقط فایل واقعی سرو میشود؛
|
|
# فایل ناموجود ۴۰۴ میگیرد، نه HTML اسپا — خزندهها (گوگل) پاسخ HTML برای فونت/تصویر
|
|
# را «خطای منابع» ثبت میکنند و CDN هم همان HTML را کش میکند
|
|
@filelike path_regexp fileext \.[a-zA-Z0-9]{2,5}$
|
|
handle @filelike {
|
|
file_server
|
|
}
|
|
|
|
# مسیریابی SPA — فقط مسیرهای بدون پسوند (مسیرهای اپ) به index.html برمیگردند
|
|
handle {
|
|
try_files {path} /index.html
|
|
file_server
|
|
}
|
|
|
|
# index.html و fallback اسپا: بدون کش مرورگر تا هر استقرار فوری دیده شود
|
|
header Cache-Control "no-cache"
|
|
# فایلهای ثابت (فونت/تصویر): یک ساعت کش مرورگر
|
|
header @filelike Cache-Control "public, max-age=3600"
|
|
# داراییهای هشدار: کش یکساله
|
|
header @assets Cache-Control "public, immutable, max-age=31536000"
|
|
}
|