# Active Context — Strava Frontend ## Task State - task_id: TASK-PUBLIC-ROUTE-FIX - status: success - parent_task: TASK-SSR-3 - summary: **BUG FIX: workout_public_item route — move to top-level, remove auth requirement.** - next task: — (task complete) ## ✅ 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` (XML с 3 статическими URL + workouts из `getPublicWorkouts()`, `Content-Type: application/xml`) и `GET /robots.txt` (Disallow `/auth/`, `/workouts/`, `/preferences/`, `/admin/`, Sitemap ссылка, `Content-Type: text/plain`). - `nginx.conf` — полная замена: SSR proxy для `/explore`, `/routes`, `/sitemap.xml`, `/robots.txt`, `/public/workouts/`; `location = /` с `hascookie token` → proxy без cookie / static с cookie; `/assets/` → 30d immutable; `try_files $uri /index.html` для SPA fallback. - `Dockerfile` — multi-stage: build (node:20-alpine, yarn install, yarn build) → runtime (node:20-alpine + nginx, copy dist/, server/, node_modules/, package.json; CMD `npx tsx server/index.ts & nginx -g 'daemon off;'`). - `run.sh` — `cd /app && npx tsx server/index.ts & nginx -g 'daemon off;'`. - `package.json` — `tsx` перемещён из `devDependencies` в `dependencies` (нужен в runtime container). - `src/stores/user-store.ts` — `typeof window === "undefined"` guard в `state()` (возврат пустого state для SSR). - `src/main.ts` — `typeof window !== "undefined" &&` guard перед `localStorage.getItem("token")` (line 110). - `yarn lint`: exit 0 (prettier: все файлы unchanged, eslint 0 ошибок). - `yarn build`: exit 0 (vue-tsc --noEmit 0 ошибок, vite build ✓ 6.68s; warning о chunk >500kB — предсуществующий). - Curl: `/robots.txt` → 200 + `Sitemap: https://cycle-rider.ru/sitemap.xml`; `/sitemap.xml` → 200 + валидный XML (3 static + 2 workout URLs с ``); `/health` → ok. ## ✅ CODER SUCCESS REPORT — TASK-SSR-2 - Изменён файл (единственный): `server/index.ts` — добавлены 4 SSR route handler + `app.disable("x-powered-by")`: - `GET /` — если cookie `token` → 302 → `/explore`; иначе SEO-лендинг: `

Cycle Rider — анализ велотренировок

`, топ-5 публичных тренировок из `getPublicWorkouts()` (при ошибке API — «Загрузка…», не 500), секция «Возможности»; JSON-LD `WebApplication`. - `GET /explore` — полный список публичных тренировок (ссылка, дата, км, км/ч, пульс); JSON-LD `WebPage`; при ошибке API → 500. - `GET /public/workouts/:id` — детали тренировки из `getPublicWorkout(id)`; API 404 → `404 Not found`; другие ошибки → 500; JSON-LD `SportsActivity`. - `GET /routes` — статический SEO-текст (без API). - Хелперы в том же файле: `getAssetTagsSafe()` (try/catch вокруг `getAssetTags()` → fallback `