strava-frontend/.roo/memory-bank/activeContext.md

8.0 KiB
Raw Blame History

Active Context — Strava Frontend

Task State

  • task_id: TASK-SSR-DETAIL
  • status: success
  • parent_task: TASK-SSR-2
  • summary: SSR /public/workouts/:id — HTML-контент переписан под DOM-структуру WorkoutItem.vue (вёрстка + фото + OG:image + noscript).
  • next task: — (no active tasks)

TASK-F12/F13/F14 — фиксы карты тренировки (WorkoutItem.vue)

  • Ф12: position="top-center left-center" (центрирование маркера на координате); findNearestTrackIndex (радиус 40 м) вместо точного lookup getKey/coordWithIndex.
  • Ф13: стабильные :settings фото-маркеров через Map-кэш (getPhotoMarkerSettings) — одного этого оказалось НЕДОСТАТОЧНО (Vue патчит VNode-ы и при неизменённых пропсах).
  • Ф14: v-memo="[photo.id]" на фото-маркерах — жёсткий пропуск патча, onUpdated/clearElement() больше не срабатывают. Методология и причины записаны в systemPatterns.md (секция «Charts & maps»).

TASK-404: HTTP 404 для несуществующих страниц (SEO)

Проблема

Любой неизвестный URL (например /random-page) отдаёт 200 + redirect на /explore. Поисковик путается.

Решение

  1. server/index.ts — catch-all 404 handler: app.use((req, res) => { if (req.method === "GET") res.status(404).send(renderTemplate(...)) }) с SEO-мета (title: "404 — страница не найдена — Cycle Rider", noindex meta).
  2. nginx.conf — whitelist SPA-роутов (/workouts, /auth, /preferences, /404) → try_files $uri /index.html; всё остальное (кроме SSR-локаций) → proxy_pass http://127.0.0.1:3001.
  3. src/router/index.ts — catch-all /:pathMatch(.*)* → redirect на { name: "404" } (вместо explore).
  4. src/router/seo.ts — запись 404: { title: "404 — страница не найдена — Cycle Rider", description: "..." } в SEO_MAP.

Acceptance Criteria

  • curl -s -o /dev/null -w "%{http_code}" http://localhost:80/random-path → 404
  • curl -s http://localhost:80/random-path | grep -c '404' → > 0
  • curl -s -o /dev/null -w "%{http_code}" http://localhost:80/workouts → 200
  • curl -s -o /dev/null -w "%{http_code}" http://localhost:80/auth/login → 200
  • curl -s -o /dev/null -w "%{http_code}" http://localhost:80/explore → 200
  • yarn lint → 0, yarn build → 0

✅ CODER SUCCESS REPORT — TASK-404

  • server/index.ts — добавлен catch-all 404 handler (app.use(...) без path) перед app.listen: для GET — renderTemplate с SEO-мета (title: "404 — Страница не найдена — Cycle Rider", canonical /404), для остальных методов — res.status(404).send("Not Found").
  • nginx.conf — реорганизация: добавлен SPA whitelist ~ ^/(workouts|auth|preferences|404)(/|$) → try_files $uri /index.html; старое location / (SPA fallback) заменено на catch-all → proxy_pass http://127.0.0.1:3001 (SSR вернёт 404 для неизвестных путей).
  • src/router/index.ts — catch-all /:pathMatch(.*)* redirect: { name: "explore" } → { name: "404" }.
  • src/router/seo.ts — добавлена запись "404" в SEO_MAP (title + description).
  • Verified: yarn lint exit 0, yarn build exit 0 (vue-tsc 0 errors, vite build ✓ 7.02s).

✅ CODER SUCCESS REPORT — TASK-F11

  • package.json — @unhead/vue ^3.4.1 в dependencies (установлено через npm install @unhead/vue --legacy-peer-deps; peer-конфликт vite 4 vs vite 5 разрешён legacy-flag'ом; vite в project поднят до 5.4.21 транзитивно).
  • Создан src/router/seo.ts — setupSeo(router, head: Unhead): SEO_MAP по name роута + DEFAULT_SEO, head.push({title, meta:[description]}) + router.afterEach(() => update()).
  • src/main.ts — import { createHead } from "unhead/client" + import { headSymbol } from "@unhead/vue"; const head = createHead(); app.provide(headSymbol, head); setupSeo(router, head); (после app.use(router)).
  • index.html — <title> заменён на «Cycle Rider — платформа для анализа велотренировок: ...»; добавлен <meta name="description"> в <head> как fallback; блок Yandex.Metrika перенесён из <head> в начало <body> (Vite 5 parse5 запрещает <div>/<img> внутри <noscript> в <head> — disallowed-content-in-noscript-in-head).
  • Verified: npm run build exit 0 (vue-tsc 0 ошибок, vite build ✓ 6.65s; warning chunk >500kB — предсуществующий); npm run lint exit 0.

✅ CODER SUCCESS REPORT — TASK-PUBLIC-ROUTE-FIX

  • Изменён файл (единственный): src/router/index.ts:
    • Удалён вложенный workout_public_item из children маршрута workouts (бывшие строки 50–54: path: "public/workouts/:id").
    • Добавлен top-level роут { name: "workout_public_item", path: "/public/workouts/:id", component: () => import("../pages/workouts/WorkoutPublicItem.vue") } — зарегистрирован до catch-all /:pathMatch(.*)*, вне AppLayout (без auth-guard'а).
  • Поведение: URL /public/workouts/:id теперь доступен без авторизации (не обёрнут в AppLayout), совпадает с SSR-эндпоинтом, nginx-прокси location ~ ^/public/workouts/ и sitemap. Внутренняя навигация по name: "workout_public_item" (см. Feed.vue) не тронута — имя не менялось.
  • WorkoutPublicItem.vue / WorkoutItem.vue: проверено — inject("axiosAuth") работает глобально (app.provide в main.ts), от AppLayout не зависит; auth-check'ов от вложенности не найдено.
  • yarn lint: exit 0 (prettier: все файлы unchanged, eslint 0 ошибок).
  • yarn build: exit 0 (vue-tsc --noEmit 0 ошибок, vite build ✓ 6.95s; warning о chunk >500kB — предсуществующий).

✅ CODER SUCCESS REPORT — TASK-SSR-3

  • Изменённые файлы:
    • server/index.ts — добавлены GET /sitemap.xml и GET /robots.txt.
    • nginx.conf — полная замена: SSR proxy, cookie-based landing, assets cache, SPA fallback.
    • Dockerfile — multi-stage: node:20-alpine build → runtime (nginx + tsx server).
    • run.sh — npx tsx server/index.ts & nginx -g 'daemon off;'.
    • package.json — tsx → dependencies.
    • src/stores/user-store.ts — typeof window guard для SSR.
    • src/main.ts — typeof window guard перед localStorage.
  • Verified: lint 0, build 0, curl /robots.txt 200, /sitemap.xml 200, /health ok.

✅ CODER SUCCESS REPORT — TASK-SSR-2

  • server/index.ts — 4 SSR route handlers + app.disable("x-powered-by"): /, /explore, /public/workouts/:id, /routes.
  • Helpers: getAssetTagsSafe(), escapeHtml, formatDate, formatDuration, formatDistance, formatSpeed, getToken.
  • Canonical base: SSR_BASE_URL || https://cycle-rider.ru.
  • Verified: lint 0, build 0, curl all routes OK.

✅ CODER SUCCESS REPORT — TASK-SSR-1

  • Created server/index.ts, server/template.ts, server/api.ts.
  • package.json: +express, +@types/express, +tsx, +3 server scripts.
  • Verified: lint 0, build 0, curl /health OK.

✅ CODER SUCCESS REPORT — TASK-SSR-0

  • src/router/index.ts: dashboard → explore (name + path), legacy redirect /dashboard → explore.
  • NavigationRoutes.ts, AppLayoutNavigation.vue, AppLayout.vue, Login.vue, Signup.vue, CheckTheEmail.vue — все ссылки dashboard → explore.
  • Verified: lint 0, build 0.