diff --git a/deploy/nginx.conf b/deploy/nginx.conf
index f8108f1..cd6f3ed 100644
--- a/deploy/nginx.conf
+++ b/deploy/nginx.conf
@@ -134,15 +134,31 @@ server {
}
location = /manifest.webmanifest {
types { } default_type application/manifest+json;
- add_header Cache-Control "public, max-age=3600";
+ # no-cache: при ребрендинге manifest (name/иконки) должен обновляться сразу.
+ add_header Cache-Control "no-cache, must-revalidate";
try_files /manifest.webmanifest =404;
}
location = /offline.html {
try_files /offline.html =404;
}
- # SPA fallback — all other routes return index.html
+ # Хэшированные ассеты Vite (имя содержит контент-хэш) — иммутабельно на год.
+ location /assets/ {
+ add_header Cache-Control "public, max-age=31536000, immutable";
+ try_files $uri =404;
+ }
+
+ # Нехэшированные бренд-ассеты (лого/иконки/favicon) — no-cache + ETag, чтобы
+ # смена логотипа не упиралась в кэш браузера (ETag даёт 304, если не менялось).
+ location ~* ^/(logo|logo-light|logo-bg|logo-fg|favicon|favicon-32|apple-touch-icon|icon-192|icon-512)\.(svg|png)$ {
+ add_header Cache-Control "no-cache, must-revalidate";
+ try_files $uri =404;
+ }
+
+ # index.html (SPA-оболочка) — no-cache: всегда свежая, подтягивает новые
+ # хэшированные бандлы и версии бренд-ассетов. SPA fallback для всех маршрутов.
location / {
+ add_header Cache-Control "no-cache, must-revalidate";
try_files $uri $uri/ /index.html;
}
}
diff --git a/docs/rebrand-all-market-progress.md b/docs/rebrand-all-market-progress.md
index 16524c4..b78dfd3 100644
--- a/docs/rebrand-all-market-progress.md
+++ b/docs/rebrand-all-market-progress.md
@@ -88,3 +88,18 @@ API и web (0 ошибок); лого вернулось на Food Market (dist/
- 08.10 — ревью Mac-Claude: безопасность входа (префилл/подсказка/сидер/ротация пароля стенда),
тост 404 (StageBanner/QuickLoginBlock → fetch), касса (лого крупнее + разделитель, бейдж внутри).
- 08.10 — deploy-stage OK; menu-walk 3/3; full-chain 16/16 ЗЕЛЁНЫЙ; откат проверен в worktree.
+- 08.10 — **кэш-бастинг лого** (у владельца в браузере оставалось старое лого из SW/кэша):
+ - `sw.js`: `CACHE_VERSION fm-v2 → am-v3` + `ASSET_VERSION=am3`; activate удаляет старые кэши,
+ skipWaiting+clients.claim есть; прекэш бренд-ассетов версионирован; бренд в комментариях → ALL MARKET.
+ - `?v=am3` на нехэшированных бренд-ассетах во всех ссылках: `index.html`, `manifest.webmanifest`,
+ `Logo.tsx`, публичный `Logo.astro` + `BaseLayout.astro` favicon.
+ - nginx web (`deploy/nginx.conf`): `index.html` + бренд-ассеты + `manifest` → `no-cache`; `/assets/*` → immutable.
+ - nginx public (`src/food-market.public/deploy/nginx.conf`): html + лого/favicon → `no-cache`; `/_astro/*` → immutable.
+ - Проверка Playwright: старый клиент (SW fm-v2 + лого Food Market) → после выкладки + 1 перезагрузки
+ кэш `am-v3`, `fm-v2` удалён, лого ALL MARKET. PASS.
+ - При будущей смене логотипа: bump `CACHE_VERSION` (sw.js) + `?v=` в ссылках (index.html, manifest, Logo.tsx/.astro).
+
+### Заметка на будущее (НЕ в этой задаче)
+SW кэширует ответы `GET /api/*` (`API_CACHE`). На ОБЩЕМ компьютере после выхода из аккаунта данные
+прошлого пользователя могут остаться в кэше. Предложение: при logout чистить `API_CACHE`
+(`caches.delete('am-v3-api')` или через `postMessage` к SW) — отдельной задачей.
diff --git a/src/food-market.public/deploy/nginx.conf b/src/food-market.public/deploy/nginx.conf
index 838a030..2de6bf9 100644
--- a/src/food-market.public/deploy/nginx.conf
+++ b/src/food-market.public/deploy/nginx.conf
@@ -23,18 +23,34 @@ server {
gzip_types text/css application/javascript application/json image/svg+xml text/plain;
gzip_min_length 1000;
+ # Хэшированные ассеты Astro (/_astro/*) — иммутабельно на год.
+ location /_astro/ {
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ try_files $uri =404;
+ }
+ # Легаси-путь на случай, если что-то лежит в /assets/ с хэшем.
location ~* ^/assets/.*\.(js|css|woff2?|svg|png|jpg|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
+ # Нехэшированные бренд-ассеты (лого/иконки/favicon) — no-cache + ETag, чтобы
+ # смена логотипа не упиралась в эвристический кэш браузера по Last-Modified.
+ location ~* ^/(logo|logo-light|favicon)\.(svg|png)$ {
+ add_header Cache-Control "no-cache, must-revalidate";
+ try_files $uri =404;
+ }
+
# Старый URL — постоянный редирект на новую страницу импорта.
location = /migration-from-other-system { return 301 /import/; }
location = /migration-from-other-system/ { return 301 /import/; }
- # Pretty URLs: /pricing → /pricing/index.html или /pricing.html
+ # Pretty URLs: /pricing → /pricing/index.html или /pricing.html.
+ # HTML — no-cache: страницы со ссылками на лого/ассеты должны быть свежими.
location / {
+ add_header Cache-Control "no-cache, must-revalidate";
try_files $uri $uri/ $uri.html =404;
}
}
diff --git a/src/food-market.public/src/components/Logo.astro b/src/food-market.public/src/components/Logo.astro
index 1243eed..2a3369d 100644
--- a/src/food-market.public/src/components/Logo.astro
+++ b/src/food-market.public/src/components/Logo.astro
@@ -1,6 +1,7 @@
---
interface Props { variant?: 'light' | 'dark'; class?: string }
const { variant = 'light', class: className = '' } = Astro.props
-const src = variant === 'dark' ? '/logo-light.svg' : '/logo.svg'
+// ?v=am3 — версия ассета для обхода кэша при ребрендинге.
+const src = variant === 'dark' ? '/logo-light.svg?v=am3' : '/logo.svg?v=am3'
---
diff --git a/src/food-market.public/src/layouts/BaseLayout.astro b/src/food-market.public/src/layouts/BaseLayout.astro
index e1cd732..351dbf4 100644
--- a/src/food-market.public/src/layouts/BaseLayout.astro
+++ b/src/food-market.public/src/layouts/BaseLayout.astro
@@ -27,7 +27,7 @@ const ymId = import.meta.env.PUBLIC_YM_ID ?? 'REPLACE_ME'