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

13 KiB
Raw Blame History

Active Context — Strava Frontend

Task State

  • task_id: TASK-HIDE-TRACK-3-FIX
  • status: success
  • parent_task: TASK-HIDE-TRACK
  • summary: Чекбокс hide_start_end + changeHideStartEnd + i18n ключ восстановлены в WorkoutItem.vue (потеряны в git stash при TASK-HIDE-TRACK-4).
  • next task: —

✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-3-FIX

  • src/pages/workouts/components/WorkoutItem.vue:
    • импорт import { useI18n } from "vue-i18n" + const { t } = useI18n(); (рядом с useToast).
    • template: чекбокс hide_start_end (v-model + v-on:change="changeHideStartEnd(...)") после блока is_public.
    • script: changeHideStartEnd(value: boolean) → axiosAuth.patch('/api/v0/workouts/${workoutItem.id}', { hide_start_end: value }) (с guard !workoutItem и catch-тостом, как у changePublic).
  • i18n: ключ workout.hide_start_end добавлен во ВСЕ 6 локали (br, cn, es, gb, ir, ru) — ранее отсутствовал (секция workout была создана заново).
  • Verified: yarn build exit 0 (vue-tsc --noEmit 0 ошибок, vite ✓).
  • Verified: grep hide_start_end → 4 совпадения; grep useI18n → 2 совпадения.
  • Note: yarn lint сломан системно — tsutils.iterateComments is not a function на всех .vue файлах (существующий дефект окружения, не от этих изменений).

✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-T1

  • ../backend/tests/test_api_workout.py: добавлен test_workout_hide_start_end — проверяет PATCH hide_start_end (False→True→False) с GET-верификацией на каждом шаге.
  • Verified: ./venv/bin/python -m pytest tests/test_api_workout.py::test_workout_hide_start_end -v → PASSED (1.92s)
  • Verified: ./venv/bin/python -m pytest tests/test_api_workout.py -v → 4 passed (5.13s)

✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-B3

  • ../backend/app/web/v0/workout.py: WorkoutEditReq + поле hide_start_end: bool | None = Field(None); endpoint передаёт hide_start_end=req.hide_start_end в workout_service.workout_edit(...).
  • ../backend/app/modules/charts/services/workout.py: workout_edit + параметр hide_start_end: bool | None = None; тело: if hide_start_end is not None: params["hide_start_end"] = hide_start_end.
  • Verified: ./venv/bin/python -c "from app.web.v0.workout import workout_update; print('OK')" → OK.
  • Verified: ./venv/bin/python -m mypy app/web/v0/workout.py app/modules/charts/services/workout.py --explicit-package-bases --no-error-summary → 0 errors.

✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-B2

  • ../backend/migration/versions/2025-09-25-0000-a1b2c3d4e5f6-hide-start-end.py создан: revision='a1b2c3d4e5f6', down_revision='b1c2d3e4f5a6'; upgrade() → op.add_column('workouts', sa.Column('hide_start_end', sa.Boolean(), server_default=sa.text('FALSE'), nullable=False)); downgrade() → op.drop_column(...). Без IS_TEST-guard (колонка нужна и в тестах).
  • Verified: python3 -c "import ast; ast.parse(...)" → OK.

✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-4

  • src/pages/workouts/WorkoutPublicItem.vue: импорт trimTrack; в .then() при d.workoutItem.hide_start_end === true — обрезка lineCoordinates/distances/data через trimTrack(..., totalDist) (totalDist = последний элемент distances). mapCenter остаётся неизменным.
  • src/pages/workouts/Definitions.vue: добавлено поле hide_start_end: boolean в тип WorkoutItem (восстановлено — было потеряно при git stash).
  • Приватный вид (WorkoutItem.vue страница) НЕ затронут.
  • Verified: yarn build exit 0 (vue-tsc --noEmit 0 ошибок, vite ✓ 6.86s).
  • Note: yarn lint → системная ошибка tsutils.iterateComments is not a function (касается ВСЕХ .vue файлов, не связано с изменениями — существующий дефект окружения lint-депенденций).

✅ CODER SUCCESS REPORT — TASK-TEST-AUTH

  • ../integration/tests/auth-flows.spec.ts создан: 4 теста (login success, login failure, signup+auto-login, logout)
  • Self-seed via POST /api/v0/signup, Vuestic selectors (input[type=email], input[type=password])
  • Verified: npx playwright test tests/auth-flows.spec.ts → 4 passed (19.2s)

TASK-TEST-PUBLIC: public-pages.spec.ts

Цель: Playwright spec для auth-сценариев (signup, login success/error, logout, validation).

Файл для создания: ../integration/tests/auth-flows.spec.ts

Конвенции (см. SKILL.md):

  • Self-seed user via POST /api/v0/signup in beforeAll
  • Selectors: input[type=email], input[type=password], getByRole('button', { name: 'Вход' })
  • Vuestic floating labels → select by input type, NOT placeholder
  • Auth mock via page.evaluate(() => localStorage.setItem(...))
  • Do NOT call expect() inside page.evaluate()
  • Base URLs: FRONTEND (5173), BACKEND (8000)
  • freshPage() helper: goto → clear localStorage → goto again

Тесты в spec:

  1. Signup: POST /api/v0/signup → returns token, user, profile; navigate to /auth/signup → fill form → submit → redirect to /explore
  2. Login success: pre-seed user via API → UI login → token in localStorage → redirect to /explore
  3. Login failure: wrong password → error toast appears, stays on /auth/login
  4. Logout: logged in → open profile dropdown → «Выход» → redirect to login, token cleared

Acceptance Criteria:

  1. Spec file created at ../integration/tests/auth-flows.spec.ts
  2. All tests self-contained (self-seed data)
  3. Follows existing sidebar-auth-switch.spec.ts patterns
  4. npx playwright test tests/auth-flows.spec.ts passes against integration stack

TASK-MCP-SETUP: Playwright MCP configuration

Что сделано:

  • MCP-конфиг Zoo Code (mcp_settings.json): server web-browser → @playwright/mcp@latest, Node 22 via nvm absolute path, --headless
  • Chromium 1234 уже установлен в ~/.cache/ms-playwright/
  • .mcp.json создан в проекте (project-level, для совместимости)
  • techContext.md обновлён: секция "UI Verification (MCP Browser)"

Как использовать (workflow):

  1. yarn dev — запустить dev server (порт 5173)
  2. browser_navigate → http://localhost:5173/explore — проверить публичную страницу
  3. browser_evaluate → () => { localStorage.setItem('token', 'test'); localStorage.setItem('user', JSON.stringify({id:1,name:'Test'})); location.reload(); } — сымитировать auth
  4. browser_navigate → проверить auth-страницы (/workouts, /workouts/:id)
  5. browser_snapshot — проверить DOM-структуру
  6. browser_take_screenshot — визуальная проверка
  7. browser_network_requests — проверить API-запросы

Баг (контекст)

Сайдбар показывает publicRoutes (Лента + Маршрут) после логина до F5. Корень: NavigationRoutes.ts:70 — routes вычисляется один раз при module evaluation и кэшируется. TASK-AUTH-NAV-1 уже добавил реактивный isAuthenticated в useGlobalStore (инициализация из localStorage + setAuthenticated в Login/Logout). Эта задача переключает UI на computed.

TASK-AUTH-NAV-2: реактивные маршруты (3 файла)

1. src/components/sidebar/NavigationRoutes.ts

  • Сделать named exports: export const authRoutes: INavigationRoute[] и export const publicRoutes: INavigationRoute[] (сейчас это локальные const, не экспортированные).
  • Убрать статическое поле routes из default export (или оставить default без routes, т.к. оба потребителя перейдут на computed). INavigationRoute интерфейс — не трогать.
  • Важно: массивы authRoutes/publicRoutes остаются теми же по структуре/содержимому — только экспортируются.

2. src/components/sidebar/AppSidebar.vue (Options API, setup())

  • import { useGlobalStore } from "../../stores/global-store"; + import { authRoutes, publicRoutes } from "./NavigationRoutes"; (импорт navigationRoutes по default можно оставить/убрать — но все обращения navigationRoutes.routes заменить).
  • В setup(): const globalStore = useGlobalStore();
  • computed: const routes = computed(() => globalStore.isAuthenticated ? authRoutes : publicRoutes);
  • В return заменить navigationRoutes на routes (тепловой шаблон уже использует navigationRoutes.routes → поправить на routes.value? НЕТ — в Options API computed из setup доступно в шаблоне как routes без .value, т.е. в шаблоне navigationRoutes.routes → routes).
  • setActiveExpand: navigationRoutes.routes.map(...) → routes.value.map(...) (в setup .value нужен).
  • Шаблоны: v-for="(route, index) in navigationRoutes.routes" → in routes.

3. src/components/app-layout-navigation/AppLayoutNavigation.vue (script setup)

  • import { authRoutes, publicRoutes } from "../sidebar/NavigationRoutes"; + import { useGlobalStore } from "../../stores/global-store";
  • const globalStore = useGlobalStore();
  • findRouteName (строка ~64): traverse(NavigationRoutes.routes) → traverse(globalStore.isAuthenticated ? authRoutes : publicRoutes).
  • Убедиться, что items computed (зависит от route.matched и findRouteName) остаётся реактивным — т.к. findRouteName читает globalStore.isAuthenticated внутри items computed, реactivity сохранится.

Acceptance Criteria (TASK-AUTH-NAV-2)

  1. yarn lint → 0 ошибок.
  2. yarn build → 0 ошибок (vue-tsc --noEmit).
  3. NavigationRoutes.ts: authRoutes и publicRoutes экспортируются; статического routes с localStorage-тернарником больше нет.
  4. AppSidebar.vue: routes = computed от globalStore.isAuthenticated; setActiveExpand использует routes.value.
  5. AppLayoutNavigation.vue: traverse использует выбор по globalStore.isAuthenticated.
  6. Ручной сценарий (ключевой): без F5 — выход из профиля → /explore → логин → сайдбар сразу показывает «Мои тренировки» (authRoutes). Аут → сайдбар сразу publicRoutes.

✅ CODER SUCCESS REPORT — TASK-AUTH-NAV-2

  • src/components/sidebar/NavigationRoutes.ts: export const authRoutes / export const publicRoutes; удалён статический routes: localStorage.getItem("token") ? ... из default export (оставлен только root).
  • src/components/sidebar/AppSidebar.vue: импорт authRoutes, publicRoutes + useGlobalStore; computed(() => globalStore.isAuthenticated ? authRoutes : publicRoutes); setActiveExpand использует routes.value.map; шаблон v-for="(route, index) in routes".
  • src/components/app-layout-navigation/AppLayoutNavigation.vue: const globalStore = useGlobalStore(); traverse(globalStore.isAuthenticated ? authRoutes : publicRoutes) внутри findRouteName (вызывается в items computed → реactivity сохранена).
  • Verified: yarn lint exit 0, yarn build exit 0 (vue-tsc --noEmit 0 ошибок, vite ✓ 7.07s).

История (закрытые задачи)

  • TASK-HIDE-TRACK-4: success — trimTrack в WorkoutPublicItem.vue при hide_start_end; hide_start_end в типе WorkoutItem (Definitions.vue). Verified: yarn build 0. (Пред. active: TASK-TEST-PUBLIC → в очереди TASK-TEST-PROTECTED.)

  • TASK-AUTH-NAV-1: success — isAuthenticated + setAuthenticated в useGlobalStore; Login setAuthenticated(true), Logout setAuthenticated(false). Verified lint/build 0.

  • TASK-SSR-DETAIL: success — SSR /public/workouts/:id под DOM WorkoutItem.vue.

  • TASK-404: success — HTTP 404 для неизвестных страниц.

  • TASK-PUBLIC-ROUTE-FIX: success — workout_public_item в top-level router.

  • TASK-F11/F12/F13/F14: success — SEO + фиксы карты тренировки.