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

95 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Active Context — Strava Frontend
## Task State
- task_id: TASK-F14
- status: success
- parent_task: TASK-F12, TASK-F13
- summary: **Карта тренировки: одиночные метки фото не пропадают при сбросе участка (v-memo + стабильные :settings), метки центрированы на GPS-точках, клик по треку — поиск ближайшей точки (радиус 40 м).**
- 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.