8.0 KiB
8.0 KiB
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 м) вместо точного lookupgetKey/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. Поисковик путается.
Решение
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).nginx.conf— whitelist SPA-роутов (/workouts,/auth,/preferences,/404) →try_files $uri /index.html; всё остальное (кроме SSR-локаций) →proxy_pass http://127.0.0.1:3001.src/router/index.ts— catch-all/:pathMatch(.*)*→ redirect на{ name: "404" }(вместоexplore).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→404curl -s http://localhost:80/random-path | grep -c '404'→ > 0curl -s -o /dev/null -w "%{http_code}" http://localhost:80/workouts→200curl -s -o /dev/null -w "%{http_code}" http://localhost:80/auth/login→200curl -s -o /dev/null -w "%{http_code}" http://localhost:80/explore→200yarn 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 lintexit 0,yarn buildexit 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 buildexit 0 (vue-tsc 0 ошибок, vite build ✓ 6.65s; warning chunk >500kB — предсуществующий);npm run lintexit 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 windowguard для SSR.src/main.ts—typeof windowguard перед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.