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

475 lines
44 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-ROUTE-FIX
- status: success
- parent_task: —
- summary: **FIX + FEATURE: Route.vue — багфикс GPX-генератора (for...in, дубликаты, фейковый ele) + snap to road через GraphHopper Cloud API.**
- next task: —
## ✅ CODER SUCCESS REPORT — TASK-ROUTE-FIX
- Изменены файлы:
- `src/pages/routes/Route.vue`: `toGPX()` (var→const, for...in→index loop, ele fix), `handleMapClick` (async, 5m filter + snapToRoad), template onClick
- `src/services/roadSnap.ts` (НОВЫЙ): `snapToRoad(lon, lat)` → GraphHopper Cloud API, fallback к исходным координатам
- Поведение: клик рядом с дорогой → точка прилипает (snap); двойной клик < 5м → игнорируется; GraphHopper down → работает как раньше
- `yarn lint`: exit 0
- `yarn build`: exit 0 (vue-tsc --noEmit + vite build)
## TASK-LINK1 — TODO (delegate to Coder)
- [x] `src/pages/workouts/components/WorkoutItem.vue`, секция «Ссылки на описание» (~строка 183): добавить `v-if="dzenLink || isPrivate"` на внешний `div.workout-item-params` секции. Внутренняя логика без изменений: `v-if="dzenLink"` → `<a :href="dzenLink">Дзен</a>` + `VaIcon edit v-if="isPrivate"`; `v-else` → «Добавить» (теперь достижим только при isPrivate, т.к. секция скрыта иначе).
- [x] Файлы трогать ДРУГИЕ НЕЛЬЗЯ: только `src/pages/workouts/components/WorkoutItem.vue`.
- [x] Acceptance: `yarn lint` exit 0, `yarn build` exit 0. Поведение: публичная страница без ссылки → секции нет вообще; публичная со ссылкой → видна ссылка «Дзен» без иконки edit; приватная без ссылки → «Добавить» (открывает модалку, PATCH работает); приватная со ссылкой → «Дзен» + иконка edit.
## ✅ CODER SUCCESS REPORT — TASK-LINK1
- Изменен файл (единственный): `src/pages/workouts/components/WorkoutItem.vue` — одна строка: на внешний `div.workout-item-params` секции «Ссылки на описание» (стр. 183) добавлен `v-if="dzenLink || isPrivate"`. Внутренняя логика секции не тронута.
- Поведение после фикса: публичная страница без ссылки → секция полностью скрыта; публичная со ссылкой → только «Дзен» (иконка edit уже была `v-if="isPrivate"`); приватная без ссылки → «Добавить» (модалка `v-if="isPrivate"` доступна, PATCH работает); приватная со ссылкой → «Дзен» + иконка edit.
- `yarn lint`: exit 0 (prettier: файлы без изменений, eslint 0 ошибок).
- `yarn build`: exit 0 (`vue-tsc --noEmit` 0 ошибок, `vite build` ✓ built in 5.41s; warning о chunk >500kB — предсуществующий).
## TASK-F1 — TODO
- [x] `src/pages/workouts/Definitions.vue`: тип `WorkoutPhoto` + `photos?: Array<WorkoutPhoto>` в `WorkoutItem` (fetch менять не нужно — бэкенд уже присылает `workout.photos`).
- [x] `src/pages/workouts/components/WorkoutItem.vue`: `photos` ref (из `workoutItem?.photos`), `photosWithCoords` computed, `<yandex-map-default-marker>` для фото с координатами (порядок `[lon, lat]` как у `clickCoordinates`, `color: 'blue'`, onClick → `window.open(photo.url, "_blank")`).
- [x] `src/pages/workouts/components/WorkoutItem.vue`: секция `#workout-photos` под `#workout-container` — grid `<img :src="photo.url">`, «Добавить фото» (`v-if="isPrivate"`, скрытый `input[type=file] accept="image/*" multiple`, `axiosAuth.post` multipart поле `file`, `Promise.allSettled`, ответ в `photos`, VaButton `:loading`), «Удалить» (`v-if="isPrivate"`, `axiosAuth.delete` → убрать из массива), ошибки/успех — `useToast`.
- [x] `src/pages/workouts/components/WorkoutItem.vue`: `isPrivate` добавлен в деструктуризацию `defineProps`; стили `.workout-photos-*` (grid auto-fill 160px, img 120px object-fit cover, кнопка удаления absolute).
- [x] `WorkoutListItem.vue` НЕ тронут (по ТЗ).
- [x] Верификация: `npm run build` exit 0 (vue-tsc --noEmit + vite, ~8–12s), `npm run lint` exit 0 (prettier+eslint --fix).
## ✅ CODER SUCCESS REPORT — TASK-F1
- Изменены файлы: `src/pages/workouts/Definitions.vue` (+8 строк: тип `WorkoutPhoto`, поле `photos?`), `src/pages/workouts/components/WorkoutItem.vue` (+163 строки: маркеры фото, галерея, upload/delete, стили).
- `photos` — локальный `ref<Array<WorkoutPhoto>>` (иниц. из пропса), все мутации только по нему; `axiosAuth` — существующий `inject("axiosAuth")`.
- Маркеры: `<yandex-map-default-marker>` с `coordinates: [lon, lat] as LngLat` (тот же порядок, что у `clickCoordinates`), `color: 'blue'` для отличия от серых маркеров кликов; onClick → `window.open(photo.url, "_blank")`.
- Загрузка: `Promise.allSettled` по каждому файлу (multipart, поле `file`); успех → push в `photos` + toast success; частичная неудача → toast error «Не удалось загрузить часть фото.»; `:loading` на кнопке.
- Удаление: `axiosAuth.delete` → filter из `photos`; ошибка → toast «Не удалось удалить фото.»
- Кнопки «Добавить фото»/«Удалить» и `v-if` секции только при `isPrivate` (владелец); на публичной странице (`WorkoutPublicItem.vue`, `isPrivate=false`) фото видны только-чтение без управления.
- `npm run build`: exit 0, `✓ built in 11.71s` (vue-tsc 0 ошибок; warning о chunk >500kB — предсуществующий).
- `npm run lint`: exit 0 (prettier: `WorkoutItem.vue` переформатирован, eslint 0 ошибок).
- Ручные проверки (сценарии для QA): фото с GPS → в галерее + синий маркер на карте; фото без GPS → только в галерее; добавление нескольких файлов сразу → все добавлены, `:loading` на кнопке во время; удаление → исчезло из галерее и с карты; публичная страница → фото видны, кнопок нет; клик по фото/маркеру → opens в новой вкладке.
## W3 acceptance criteria
- `eslint` 9.x + `typescript-eslint` 8.x in yarn.lock; legacy `@typescript-eslint/eslint-plugin@6` + `@typescript-eslint/parser@6` removed (superseded by the `typescript-eslint` 8 meta-package); NO other package moved to a new major
- `yarn lint` 0 errors + `yarn build` green
- `eslint.config.mjs` adjustments minimal and documented (flat config already in use — migration should be trivial)
- Memory Bank: status `success` + Success Report
## W3 notes for the Coder
- Current state: `eslint@8.57.1` (flat config works on 8.57), `typescript-eslint@7.18.0`, legacy `@typescript-eslint/eslint-plugin@^6.11.0` + `@typescript-eslint/parser@^6.11.0` still in package.json (redundant with the meta-package but currently unused by eslint.config.mjs).
- Target: `yarn add -D eslint@^9 typescript-eslint@^8`, then `yarn remove @typescript-eslint/eslint-plugin @typescript-eslint/parser` ONLY if eslint.config.mjs does not import them directly (check first).
- eslint 9 removes some legacy config options — if `eslint.config.mjs` breaks, apply the minimal migration (documented).
- `eslint-plugin-prettier`/`@vue/eslint-config-prettier` are NOT part of W3 — leave versions as-is.
## W2d acceptance criteria
- `package.json`: no `storybook`/`@storybook/*`/`eslint-plugin-storybook` deps, no `storybook`/`build-storybook` scripts
- yarn.lock: no `@storybook/vue3-vite` entry, no nested `@vitejs/plugin-vue@4` install
- `yarn lint` 0 errors + `yarn build` green
- `eslint.config.mjs` — no references to storybook plugin (verify; add minimal fix if present)
- Memory Bank: status `success` + Success Report (removed list, install-size delta if measurable)
## W2b acceptance criteria
- `vue-tsc` resolved to 2.x and `typescript` to 5.8.x in yarn.lock; NO other package moved to a new major
- `yarn lint` — 0 errors; `yarn build` — green (vue-tsc 2 type-check 0 errors, bundle built)
- Minimal type-only fixes in `src/` allowed only if required by the stricter checker; each documented with justification
- Memory Bank: status `success` + Success Report (old/new versions, full list of src/ fixes with justification)
## Wave plan (each wave = one atomic task, verified independently)
- **W0a (TASK-DEPS-UPDATE-W0a, success)**: Fix everything that hard-blocks `yarn build`:
- `LineWithLineChart.ts(41)` TS2532 "Object is possibly 'undefined'" (labels can be undefined) — fix via non-null assertion or guarded length.
- SFC parsing errors: `src/pages/workouts/components/WorkoutItem.vue:260` (`Unexpected token {`) and `WorkoutListItem.vue:60` (`'interface' is reserved`). Root-cause candidates: TS syntax in a plain `<script>` (no `lang="ts"`) or malformed block — inspect and fix minimally (no logic changes).
- **W0b (TASK-DEPS-UPDATE-W0b, success, Architect-verified)**: `yarn lint` 0 errors. TS parser hooked for `.vue` in `eslint.config.mjs`; 21 files code-fixed (type-only/dead-code); file-targeted config exceptions with comments (`src/main.ts` any/unused off, `pages/**` multi-word off, `components/WorkoutItem.vue` no-mutating-props off). Prettier pass committed.
- **W1 (TASK-DEPS-UPDATE-W1, success, Architect-verified)**: patch/minor only, no major bumps. Capped: `typescript@^5.2.2` → 5.4.5 (5.9.x crashes vue-tsc 1.8), `sass` kept 1.69.5 (1.104 needs node ≥20.19, baseline node 18.19.1). `package.json` unchanged.
- **W2 split into 3 atomic waves** (vue-tsc 2 may surface new type errors in src/, so it gets its own wave):
- **W2a (success, Architect-verified)**: `vue` 3.3.9→3.5.42 + `pinia` 3.0.4 (package.json: only these 2 lines). Type fixes: `LngLat` refs/casts in `pages/routes/Route.vue` and `pages/workouts/components/WorkoutItem.vue` (vue-yandex-maps strict `:settings` types in vue 3.5).
- **W2b (success, Architect-verified)**: `typescript` 5.4.5→**5.8.3** (`typescript@5.8` in package.json, pinned no-caret to keep the lock honest on 5.8.x) + `vue-tsc` 1.8.27→**2.2.12** (`^2`). Type-only fixes: `File | undefined` in `PreferencesHeader.vue` + `WorkoutUpload.vue` (TS 5.8 `Blob.bytes`).
- **W2c (success, Coder-verified)**: `vite` 4.5.14→**5.4.21** + `@vitejs/plugin-vue` 4.6.2→**5.2.4** (package.json: only these 2 lines). No `vite.config.ts` changes needed; no sass legacy-API warnings appeared; CJS Node API deprecation warning observed (documented, not fixed).
- **sass**: deferred — latest 1.x requires node ≥20.19; revisit only if the environment's node is upgraded.
- **W2c-FIX (in_progress)**: Dockerfile → yarn (`COPY yarn.lock`, `yarn install --frozen-lockfile`) to align with dev workflow and unblock the Docker build broken by the stale `package-lock.json` + npm strict peer validation.
- **W2c-FIX (success, Coder-verified)**: Dockerfile switched to yarn (`COPY package.json yarn.lock ./` + `RUN yarn install --frozen-lockfile`). Full `docker build` verified green.
- **W2d (success, Coder-verified)**: Removed all 9 dead Storybook deps (`storybook`, 7× `@storybook/*`, `eslint-plugin-storybook`) + the `storybook`/`build-storybook` scripts. No `eslint.config.mjs` references existed (verified — untouched). yarn.lock: zero `@storybook/*`/`storybook` entries, no nested `@vitejs/plugin-vue@4` (only `@vitejs/plugin-vue@^5` → 5.2.4). Lint 0 errors, build green.
- **W3 (planned)**: Tooling majors: `eslint` 8→9 + `typescript-eslint` 6→8 (flat config `eslint.config.mjs` may need small adjustments), `prettier` minor. Storybook handled by W2d.
## W2a acceptance criteria
- `vue` resolved in yarn.lock to 3.5.x, `pinia` to 3.x; NO other package moved to a new major
- `yarn lint` — 0 errors; `yarn build` — green (vue-tsc 0 errors, bundle built)
- No behavior changes; minimal type fixes in `src/` allowed only if required, each documented
- Memory Bank: status `success` + Success Report (old/new versions, any src/ fixes with justification)
## W0b acceptance criteria
- `yarn lint` — 0 errors, 0 warnings-as-errors
- `yarn build` — still green (regression check)
- No behavior changes: fixes are cosmetic/type-only; no rendering logic, props, or API calls modified
- Memory Bank updated: status `success` + Success Report with the full list of changed files and eslint config diff
## Notes for the Coder (all waves)
- yarn v1 (repo has `yarn.lock`); baseline node 18.19.1.
- Do NOT touch `HOST`, Yandex Maps key, GTM config in `src/main.ts`.
- One concern per task — do not continue into W0b/W1 after finishing your wave; the Architect delegates the next one.
- On escalation: set status `escalated`, write a Failure Report, roll back your changes, return control.
---
## ✅ CODER SUCCESS REPORT (W0a)
### Verified outcome
- `yarn build` GREEN: `vue-tsc --noEmit` → 0 errors, `vite build` → 1309 modules transformed, bundle built in ~8s.
- Working tree contains exactly ONE minimal diff (see below). Lint still red — expected, W0b.
### Changes made (single file, 1 line)
- `src/pages/workouts/components/LineWithLineChart.ts` (`draw()`): removed `// @ts-ignore` above the zoom calculation and replaced it with non-null assertions `this.chart.config.data!.labels!.length`. No rendering logic, props, or runtime behavior changed (non-null assertions are type-level only). This also resolves the W0b `ban-ts-comment` error for this file up front.
### Baseline discrepancy (observed, documented honestly)
- The W1 escalation report recorded `yarn build` FAIL with `LineWithLineChart.ts(41,7) TS2532` on e79722d, but on the clean tree at W0a start the build already PASSED: the TS2532 was suppressed by the pre-existing `// @ts-ignore` (the error would resurface in stricter TS/vue-tsc versions — W1/W2 — which is why the assertion fix is still correct and pre-authorized by the task).
- The "SFC parsing errors" in `components/WorkoutItem.vue:260` and `components/WorkoutListItem.vue:60` do NOT block `yarn build` — both files have `<script setup lang="ts">`, and `vite build` transforms them without error. They are **eslint-only** parse artifacts (eslint's JS parser choking on TS syntax) → remain in scope for **W0b** (likely need `parserOptions.parser` typescript-eslint hookup in `eslint.config.mjs`, no source changes required — to be confirmed by W0b Coder).
---
## ✅ CODER SUCCESS REPORT (W0b)
### Verified outcome
- `yarn lint` → **0 errors** (exit 0; prettier pass clean, eslint `--fix` clean).
- `yarn build` → **green**: `vue-tsc --noEmit` 0 errors, `vite build` OK (~8.3s).
- No behavior changes: all fixes are type-level, dead-code removal, or unused-cleanup. The only functional nuance: `CheckTheEmail.vue` recover-error check is now null-safe (`error.response?.data`) — a strict subset of the previous behavior (previously a hard crash if `response` was missing).
### eslint.config.mjs (rewritten, flat config)
1. CJS interop: `import tseslintPkg from "typescript-eslint"`; `const tsParser = tseslintPkg.parser` (named import `tsParser` fails on eslint 8 + CJS module).
2. **Root cause of the SFC parse errors fixed**: new block `files: ["**/*.vue"]` with `languageOptions.parserOptions.parser = tsParser`. The vue flat config already sets the SFC parser — only the inner TS parser was missing (setting `languageOptions.parser` to `pluginVue.parser` fails: it is undefined at that level; the vue plugin injects the SFC parser inside its own config entries).
3. Global: `@typescript-eslint/no-unused-vars` → `["error", { argsIgnorePattern: "^_" }]` (covers all `_response`/`_error` axios catch params across src/).
4. File-targeted overrides (each with a reason comment):
- `src/main.ts` — `no-explicit-any` + `no-unused-vars` OFF (documented axios-interceptor exception).
- `src/pages/**/*.vue` — `vue/multi-word-component-names` OFF (route-level pages are single-word by design; renaming would break router/public names).
- `src/pages/auth/Logout.vue` — `vue/valid-template-root` OFF (redirect-only screen, empty template by design).
- `src/pages/workouts/components/WorkoutItem.vue` — `vue/no-mutating-props` OFF (checkbox/name edits mutate the prop object in place; fixing would be a state-management change, out of scope for the lint wave).
5. **No `// eslint-disable` lines were added anywhere** — every error was fixed in code or via the config blocks above.
### Code changes (21 files, type-only / dead-code)
- `src/router/index.ts` — removed unused `RouteViewComponent` import.
- `src/services/utils.ts` — `validators.required: (v: any)` → `(v: unknown)`.
- `src/pages/workouts/components/LineWithLineChart.ts` — remaining `// @ts-ignore` (plugin cast) → `// @ts-expect-error` with reason (chart.js plugin config untyped).
- `src/pages/auth/Login.vue` — removed unused `HOST` inject + `inject` import; 2 unused catch params dropped.
- `src/pages/auth/Signup.vue` — 2 unused catch params dropped.
- `src/pages/auth/CheckTheEmail.vue` — catch param typed `AxiosError` (import added); `error.response.data.detail` access made null-safe + cast (fixes TS18048/TS18046 surfaced by strict typing).
- `src/pages/auth/RecoverPassword.vue`, `src/pages/auth/Logout.vue` — (covered by config + earlier unused-param cleanup).
- `src/pages/auth/Logout.vue` — removed unused `push` destructure.
- `src/pages/workouts/Feed.vue` — removed redundant `v-if` on `v-for` template (same truth condition as the sibling `v-if`), unused `index`; catch param `any`→`unknown`.
- `src/pages/workouts/WorkoutList.vue` — same template fix; `event: any`→`Event`; 2× catch `any`→`unknown`.
- `src/pages/workouts/WorkoutPublicItem.vue` — no code change needed (covered by `argsIgnorePattern`).
- `src/pages/workouts/WorkoutUpload.vue` — `catch(function (error: any)` → nameless.
- `src/pages/workouts/components/WorkoutItem.vue` — `v-for` marker got `:key`; `afterEvent(chart: any, args, opts: any)` → `(_chart: unknown, args)`; `isEmpty(obj: any)` → `Record<string, unknown>`; tooltip `label(context: any)` → `{ dataIndex: number }`; `onZoomComplete(chart: any)` → structural type; `saveLink`/`saveName (hide: any)` → `() => void`.
- `src/pages/workouts/components/WorkoutListItem.vue` — prop `deleteItem?: (item, event: any)` → `Event`.
- `src/pages/preferences/preferences-header/PreferencesHeader.vue` — removed dead `readFile` function (never referenced); inner `.then((response: any)` → `(_response: AxiosResponse)`, unused catch params dropped.
- `src/pages/preferences/modals/EditNameModal.vue`, `ResetPasswordModal.vue` — unused `.then(response)`/`.catch(error)` params dropped.
- `src/components/VuesticLogo.vue` — removed dead `useColors`/`getColor`/`colorsComputed` (unused; logo is a static SVG); props kept for API compatibility.
- `src/components/app-layout-navigation/AppLayoutNavigation.vue` — `traverse(routers: any[])` now typed with the route interface exported from `NavigationRoutes.ts` (imported alongside the default); `src/components/navbar/components/AppNavbarActions.vue` — dropped unused `useI18n`/`t` destructure.
- `src/components/sidebar/AppSidebar.vue` — internal `name: "Sidebar"` → `"AppSidebar"` (not used anywhere as a global name; options-API `name` field only).
- `src/components/navbar/components/AppNavbarActions.vue` — removed unused `useI18n`/`t`.
- Prettier (`prelint`) auto-reformatted ~30 `src/` files — these formatting changes are part of the intended clean diff (kept).
### Left for later waves
- `vue/no-mutating-props` in `components/WorkoutItem.vue` (suppressed, file-targeted) — proper fix = local state extraction, separate task.
- `src/main.ts` loose typing (suppressed, file-targeted) — pre-existing documented debt.
- W1 (`yarn up` patch/minor) is unblocked.
---
## ✅ CODER SUCCESS REPORT (W1)
### Verified outcome
- `yarn lint` → **0 errors** (prettier + eslint `--fix` clean) — run AFTER the upgrade.
- `yarn build` → **green**: `vue-tsc --noEmit` 0 errors, `vite build` OK (~7.3s).
- `yarn install --frozen-lockfile` → clean (fresh install from the new lockfile works).
- `package.json` — **unchanged** (verified via `git diff`). The only W1 diffs are `yarn.lock` (+ the pre-existing uncommitted W0a/W0b changes in `src/` / `eslint.config.mjs`, which W1 did not touch).
- No major bump anywhere in `yarn.lock`: every direct dependency stayed within its semver range (spot-checked all 61 direct deps, old vs new lockfile).
### Notable version changes (direct deps, old → new)
| package | old | new | note |
| ----------------------------------------- | -------------- | --------- | ------------------------------------------- |
| typescript | 5.2.2 | **5.4.5** | ⚠️ capped — see known issues |
| postcss | 8.4.31 | 8.5.28 | |
| axios | 1.7.7 | 1.20.0 | |
| chart.js | 4.4.4 | 4.5.1 | |
| chartjs-chart-geo | 4.2.8 | 4.3.6 | |
| chartjs-plugin-zoom | 2.0.1 | 2.2.0 | |
| eslint | 8.57.0 | 8.57.1 | |
| eslint-plugin-prettier | 5.0.1 | 5.5.6 | |
| eslint-plugin-react | 7.34.1 | 7.37.5 | |
| eslint-plugin-vue | 9.25.0 | 9.33.0 | |
| globals | 15.0.0 | 15.15.0 | |
| lint-staged | 15.2.10 | 15.5.2 | |
| pinia | 2.1.7 | 2.3.1 | |
| prettier | 3.1.0 | 3.9.6 | |
| serve | 14.2.3 | 14.2.6 | |
| storybook (suite) | 7.6.20 / 7.5.3 | 7.6.24 | addons 7.5.3 → 7.6.24 |
| tailwindcss | 3.4.1 | 3.4.19 | |
| typescript-eslint | 7.6.0 | 7.18.0 | |
| @typescript-eslint/eslint-plugin, /parser | 6.11.0 | 6.21.0 | within `^6.11.0` (minor) — verified in lock |
| vite | 4.5.5 | 4.5.14 | |
| vue-chartjs | 5.3.1 | 5.3.4 | |
| vue-eslint-parser | 9.4.2 | 9.4.3 | |
| vue-i18n | 9.6.5 | 9.14.5 | |
| vue-router | 4.2.5 | 4.6.4 | |
| vue-yandex-maps | 2.1.4 | 2.3.3 | |
| vuestic-ui | 1.9.0 | 1.10.3 | |
| sass | 1.69.5 | 1.69.5 | ⚠️ capped (not upgraded) — see known issues |
| vue, vue-tsc | 3.3.9, 1.8.27 | unchanged | pinned / latest 1.x |
Verified: `@typescript-eslint/eslint-plugin` / `@typescript-eslint/parser` (declared `^6.11.0`) resolve to **6.21.0** in the new lockfile — within range, no out-of-range resolution. The separate `7.18.0` lock entries belong to the `typescript-eslint@^7.6.0` meta-package's fixed dependencies.
### Known issues / caveats (recorded in progress.md)
1. **`yarn up` alias missing** in the installed yarn 1.22.22 binary (`/home/artem/.local/lib/node_modules/yarn` — `lib/cli.js` has no `up` command). Used `yarn upgrade [pkgs]` — the documented equivalent.
2. **`sass` capped at 1.69.5**: `^1.69.5` resolves to 1.104.0, whose `engines` require node ≥20.19.0 (baseline is node 18.19.1) → hard engine error. Kept at baseline; the latest 1.x compatible with node 18 can be picked up in a follow-up or after a node 20 baseline.
3. **`typescript` capped at 5.4.5**: `^5.2.2` resolved to 5.9.3, which crashes `vue-tsc@1.8.27` (`Search string not found: "supportedTSExtensions"` — TS ≥5.5 internal API change). Applied per rule 5: `yarn add -D typescript@5.4.5`, then **restored `package.json` to `^5.2.2`** via `git checkout` (package.json must stay untouched) and renamed the lockfile key `typescript@5.4.5` → `typescript@^5.2.2` (one manual 1-line lock edit) so `--frozen-lockfile` stays consistent. Upgrading vue-tsc to 2.x (which supports newer TS) is explicitly W2 scope.
### Files changed by W1
- `yarn.lock` — full patch/minor refresh + 2 caps (typescript 5.4.5, sass 1.69.5) + 1 key rename.
- No `src/` changes, no `package.json` changes, no HOST/Yandex/GTM changes.
---
## ✅ CODER SUCCESS REPORT (W2a)
### Versions (package.json → resolved in yarn.lock)
| package | old | new |
| ------- | ------------------------ | ------------------- |
| `vue` | `3.3.9` (exact) | `^3.5` → **3.5.42** |
| `pinia` | `^2.1.7` (2.3.1 in lock) | `^3` → **3.0.4** |
- Applied via `yarn add vue@^3.5 pinia@^3`. `git diff package.json` = exactly the two lines above, nothing else.
- No other direct dependency moved to a new major: the only new/changed lockfile entries are the vue 3.5 subtree (`@vue/runtime-core@3.5.42`, `@vue/server-renderer@3.5.42`, `@vue/devtools-kit/shared`) and pinia 3's new deps (`birpc`, `mitt`, `hookable`, `superjson`, `speakingurl`, `copy-anything`, `perfect-debounce`) — all newly required by the two target packages; everything else is patch/minor drift inside existing ranges (W1 was already verified major-free, and the W2a re-resolution only touched the vue/pinia subtrees).
### Type-only fixes in `src/` (2 files, no logic changes)
Vue 3.5's template type-checking became strict about the `vue-yandex-maps` `:settings` prop: `ymaps` `LngLat = [lon, lat, alt?]` is a **tuple**, while the app data is `number[]` / `number[][]`. Under 3.3 these assignments were accepted; 3.5 rejects them (6× TS2322 in `Route.vue` + `components/WorkoutItem.vue`). Fixes are type-level only — runtime values are unchanged:
- `src/pages/routes/Route.vue` — `ref([30.31413, 59.93863])` → `ref<LngLat>([30.31413, 59.93863])` (literal is a valid 2-tuple; `LngLat` already imported in the file).
- `src/pages/workouts/components/WorkoutItem.vue`:
- `import type { YMap }` → `import type { LngLat, YMap } from "@yandex/ymaps3-types"`;
- template casts (values already `[lon, lat]` pairs from the API): `center: mapCenter as LngLat`, `coordinates: lineCoordinates as LngLat[]`, `coordinates: markedCoordinats as LngLat[]`, `coordinates: currentCoordinates as LngLat`;
- `clickCoordinates: ref<Array<number>>` → `ref<LngLat[]>` — sound: it is only ever assigned `e.coordinates` from Yandex map click events, which are `LngLat`.
Parent components (`pages/workouts/WorkoutItem.vue`, `WorkoutPublicItem.vue`) pass their existing `Array<number>`/`Array<Array<number>>` refs into the props unchanged — prop signatures untouched, so no cascade.
### Verification
- Baseline (before update): `yarn lint` 0 errors, `yarn build` green (1390 modules).
- After update: `yarn lint` → 0 errors (eslint clean, prettier all unchanged); `yarn build` → **green**: `vue-tsc --noEmit` 0 errors, `vite build` OK (~7.5s, 1396 modules).
- Runtime smoke-check: `yarn dev` boots (Vite ready ~0.6s, no errors); `GET /` → 200 with expected HTML; key entry modules (`/src/main.ts`, `/src/App.vue`, both map pages, `/src/stores/user-store.ts`) transform and serve 200 with no dev-server compile errors.
- Untouched as required: `HOST`/Yandex key/GTM in `src/main.ts`, i18n locales, `eslint.config.mjs`.
### Left for W2b
- `vue-tsc` 1.8.27 currently works with vue 3.5.42; vue-tsc 2.x + TS bump is W2b. Note: vue 3.5 types are already stricter in templates (see above) — more type-only fixes may surface in W2b/W2c.
---
## ✅ CODER SUCCESS REPORT (W2b)
### Versions (package.json → resolved in yarn.lock)
| package | old | new |
| ------------ | ------------------------ | ------------------- |
| `typescript` | `^5.2.2` (5.4.5 in lock) | `"5.8"` → **5.8.3** |
| `vue-tsc` | `^1.8.22` (1.8.27) | `^2` → **2.2.12** |
- Applied via `yarn add -D typescript@5.8 vue-tsc@^2`. `git diff package.json` changed exactly these two lines (plus the pre-existing uncommitted W2a `vue`/`pinia` lines). `typescript` pinned without caret so the lock resolves to 5.8.x, NOT 5.9 (vue-tsc 2 officially supports TS ≤5.8).
- No foreign major bump: verified all 61 direct deps — only new lock entries are the `vue-tsc` 2.x subtree (`@vue/language-core@2.2.12`, `@volar/source-map`, `@volar/typescript`, `muggle-string`, `alien-signals`, `vscode-uri`, `@vue/compiler-vue2`), all newly required by vue-tsc 2. `typescript` stayed at 5.8.x (not 5.9).
### Type-only fixes in `src/` (2 files, 4 errors, no logic changes)
TS 5.8 + vue-tsc 2 surfaced errors in the two file-upload pages. The legacy `let file: {inline object type}` declaration was (a) never a real `File` (TS 5.8's `Blob` now declares required `bytes`, which the structural object lacked → TS2769 on `FormData.append`), and (b) had no initializer (definite-assignment TS2454). Fixed type-only — runtime values/behavior unchanged:
- `src/pages/preferences/preferences-header/PreferencesHeader.vue` — `let file: {…inline…}` (14-line structural type) → `let file: File | undefined = undefined;` (initial value `undefined` resolves TS2454); `formData.append("file", file)` → `formData.append("file", file!)` (non-null assertion; the upload is only ever reachable after a file is chosen, so this is type-level only).
- `src/pages/workouts/WorkoutUpload.vue` — `let file: {…inline…}` → `let file: File | undefined = undefined;` (same fix; the function already guards `if (file == undefined) return;` so no assertion needed).
### Verification
- Baseline (before update): `yarn lint` 0 errors, `yarn build` green.
- After update: `yarn lint` → 0 errors (eslint clean); `yarn build` → **green**: `vue-tsc 2.2.12 --noEmit` 0 errors, `vite build` OK (~7.3s).
- Untouched as required: `HOST`/Yandex key/GTM in `src/main.ts`, i18n locales, `eslint.config.mjs`, `vite.config.ts`.
### Left for W2c
- `vite` 4→5 + `@vitejs/plugin-vue` 4→5. Watch: sass legacy-API deprecation warnings in vite 5 (warnings OK, errors not). Architect delegates.
---
## ✅ CODER SUCCESS REPORT (W2c)
### Versions (package.json → resolved in yarn.lock)
| package | old | new |
| -------------------- | ------------------------- | ----------------- |
| `vite` | `^4.4.6` (4.5.14 in lock) | `^5` → **5.4.21** |
| `@vitejs/plugin-vue` | `^4.2.3` (4.6.2 in lock) | `^5` → **5.2.4** |
- Applied via `yarn add -D vite@^5 @vitejs/plugin-vue@^5`. `git diff package.json` changed exactly these two lines.
- **No foreign major bump**: audited the full lockfile diff — the only version-moved packages are `vite` (4.5.14→5.4.21) and `@vitejs/plugin-vue` (^4.2.3 key → 5.2.4). New lock entries are exclusively the vite 5 subtree: `rollup@4.63.1` + `@rollup/rollup-*` platform binaries, `esbuild@0.21.5` + `@esbuild/*` platform binaries, `@napi-rs/lzma-linux-x64-gnu`. `esbuild@0.18.20` and `rollup@3.30.0` remain for the storybook pin; the storybook `@vitejs/plugin-vue@^4.0.0` pin still resolves to 4.6.2 (separate lock entry, untouched).
- `sass` stayed at 1.69.5 (per task rule — update forbidden in this wave).
### Warnings observed (documented, NOT fixed per task rules)
- `The CJS build of Vite's Node API is deprecated` (both `vite build` and `vite dev`) — expected with vite 5 + CJS-transpiled config consumers; warning only, no action required in this wave.
- **No sass legacy JS API deprecation warnings appeared** in `yarn build` (sass 1.69.5 + vite 5.4.21 compiled `src/scss/**` cleanly). The anticipated legacy-API warning did not materialize.
- Pre-existing (unchanged): chunk-size warning (`index-*.js` > 500 kB) and `vuestic-icons.eot` runtime-resolution notice — present on the vite 4 baseline as well.
### Verification
- Baseline (before update): `yarn lint` 0 errors, `yarn build` green (vite 4.5.14, ~7.2s).
- After update: `yarn lint` → 0 errors (eslint clean, prettier all unchanged); `yarn build` → **green**: `vue-tsc --noEmit` 0 errors, `vite build` v5.4.21 OK (~6.5s, 1396 modules).
- Smoke-check: `yarn dev` booted (VITE v5.4.21 ready in 372 ms); `GET /` → 200, `GET /src/main.ts` → 200, `GET /src/App.vue` → 200, `GET /src/pages/workouts/Feed.vue` → 200; dev log free of errors; dev server stopped after the check.
- Untouched as required: all `src/` code, `vite.config.ts` (no config changes needed — API-compatible), `HOST`/Yandex key/GTM in `src/main.ts`, i18n locales, `eslint.config.mjs`, sass.
### Left for W3 (Architect delegates)
- Tooling majors: `eslint` 8→9 + `typescript-eslint` 6/7→8 (flat config adjustments), `prettier` minor. Storybook stays on 7.
---
## ✅ CODER SUCCESS REPORT (W2c-FIX)
### Changes made (single file, 2 lines)
- `Dockerfile`:
- Line 18: `COPY package.json package-lock.json ./` → `COPY package.json yarn.lock ./`
- Line 25: `RUN npm install` → `RUN yarn install --frozen-lockfile`
- No other files touched: `package.json`, `yarn.lock`, `package-lock.json` (left in repo per task rules), `src/`, `nginx.conf`, `run.sh` all unchanged (verified via `git status --porcelain` — only `Dockerfile` modified).
- No explicit `yarn install -g yarn@1` line needed: `docker run --rm node:18 yarn --version` → **1.22.22** (yarn 1.x ships out of the box with the `node:18` base image).
### Why this fixes the Docker build
The W2c wave moved `vite`/`@vitejs/plugin-vue` to 5 in `yarn.lock`, but the Dockerfile installed via **npm** against the stale `package-lock.json`. npm ≥7 strictly validates peer deps and hard-fails on `@storybook/vue3-vite@7.6.20` → `@vitejs/plugin-vue@^4.0.0` vs root `^5` (ERESOLVE). yarn 1 does not enforce peer-dep installation and resolves the conflict via a nested `@vitejs/plugin-vue@4.6.2` install for storybook (already present as a separate lock entry from W2c). Installing from the current `yarn.lock` with `--frozen-lockfile` makes the Docker build use the same, verified resolution as the local dev workflow.
### Local verification
- `yarn install --frozen-lockfile` → clean ("Already up-to-date", exit 0; the pre-existing `package-lock.json found` warning is informational only — removal of that file is explicitly out of scope for this task).
- `yarn lint` → **0 errors** (prettier clean, eslint `--fix` clean).
- `yarn build` → **green**: `vue-tsc --noEmit` 0 errors, `vite build` v5.4.21 OK (~6.4s).
- No `node_modules`-dependent drift: `git status` confirms lockfiles untouched by the verification runs.
### Docker verification (performed)
- `docker build -t strava-frontend-w2cfix .` → **GREEN** (exit 0, image exported). Full 13-step pipeline completed: `yarn install --frozen-lockfile` inside the image succeeded (no ERESOLVE), `npm run build` (= `vue-tsc --noEmit && vite build`) succeeded, nginx setup + `run.sh` chmod steps completed.
### Left for later
- `package-lock.json` remains in the repo (yarn warns about it at install time) — removal is a separate Architect decision, out of scope here.
- Storybook 7 ↔ vite 5 peer conflict is now only a _warning-level_ concern (nested resolution); the clean fix remains W2d (Storybook 7 → 8).
---
## ✅ CODER SUCCESS REPORT (W2d)
### Removed (package.json only, verified via `git diff`)
- devDependencies (9): `storybook`, `@storybook/addon-essentials`, `@storybook/addon-interactions`, `@storybook/addon-links`, `@storybook/blocks`, `@storybook/testing-library`, `@storybook/vue3`, `@storybook/vue3-vite`, `eslint-plugin-storybook`.
- scripts (2): `"storybook"`, `"build-storybook"`.
- `eslint.config.mjs`: checked — contains NO references to `eslint-plugin-storybook` or any storybook config (flat config only wires `globals`, `typescript-eslint`, `eslint-plugin-vue`). Not touched.
- No other files touched: `src/`, `vite.config.ts`, `tailwind.config.js`, `package-lock.json`, `nginx.conf`, i18n locales all unchanged.
### Method
- `yarn remove storybook @storybook/addon-essentials @storybook/addon-interactions @storybook/addon-links @storybook/blocks @storybook/testing-library @storybook/vue3 @storybook/vue3-vite eslint-plugin-storybook` (lockfile regenerated automatically), then manual 2-line script removal from `package.json`.
### yarn.lock cleanliness (verified via grep)
- `grep -c storybook yarn.lock` → **0** (no `@storybook/*`, no `storybook`, no `eslint-plugin-storybook` entries).
- No nested `@vitejs/plugin-vue@4.x` install: the only plugin-vue entry is `@vitejs/plugin-vue@^5` → 5.2.4. The storybook peer conflict is gone at the root, not just warned away.
- Transitive leftovers (e.g. `@storybook/csf` copies) are also gone — the whole subtree pruned.
### Verification
- Baseline (before removal): `yarn lint` 0 errors, `yarn build` green (vue-tsc 0 errors, vite 5.4.21, 1396 modules).
- After removal: `yarn install` clean; `yarn lint` → **0 errors** (prettier all unchanged, eslint clean); `yarn build` → **green** (vue-tsc --noEmit 0 errors, vite build ~6.3s, 1396 modules).
- No hidden dependency on storybook code/configs surfaced (rule 8 not triggered — nothing to escalate).
- `docker build` not re-run (optional per task; W2c-FIX was green and this change only shrinks the tree — `yarn install --frozen-lockfile` inside the image gets an even smaller, conflict-free set).
### Left for later
- `package-lock.json` remains stale in the repo (still references the storybook suite) — removal/refresh is a separate Architect decision (unchanged here per task rule 7).
- W3 (eslint 8→9, typescript-eslint →8, prettier minor) — Architect delegates.
---
## ✅ CODER SUCCESS REPORT (W3 — FINAL wave)
### Verified outcome
- `yarn lint` → **0 errors** (eslint 9.39.5, prettier pass all unchanged).
- `yarn build` → **green** (vue-tsc 2.2.12 --noEmit 0 errors, vite 5.4.21 build ~5.3s, 1396 modules).
- `docker build --pull --no-cache` → **green** (image `strava-frontend-w3` built on `node:22`).
- Baseline before the wave: lint 0 errors + build green (re-verified at wave start).
### Version moves (verified via `git diff package.json` + `yarn.lock`)
| Package | Old | New |
| ---------------------------------------- | ---------------- | ----------------------------------------------- |
| `eslint` (dev) | ^8.57.0 (8.57.1) | **^9** → resolved **9.39.5** |
| `typescript-eslint` (dev) | ^7.6.0 (7.18.0) | **^8** → resolved **8.69.0** |
| `@typescript-eslint/eslint-plugin` (dev) | ^6.11.0 | **REMOVED** (superseded by the v8 meta-package) |
| `@typescript-eslint/parser` (dev) | ^6.11.0 | **REMOVED** (superseded by the v8 meta-package) |
| `Dockerfile` base | `node:18` | **`node:22`** (see node-requirement below) |
- NO other package moved to a new major (verified in yarn.lock: vue 3.5.42, pinia 3, TS 5.8.3, vue-tsc 2.2.12, vite 5.4.21, sass 1.69.5, prettier 3.9.6, eslint-plugin-vue 9.33.0 — all unchanged from W2 state).
- `eslint-plugin-prettier` / `@vue/eslint-config-prettier` untouched per task rule 7.
- Note: yarn v1 re-resolved the remaining `^` ranges during the lockfile regen; only `@vue/eslint-config-typescript`'s nested legacy `@typescript-eslint/*@6.21.0` subtree remains (peer warnings only — that package is NOT imported by `eslint.config.mjs`, behavior unchanged).
### eslint.config.mjs
- **Zero changes required** — flat config from eslint 8.57 works as-is on eslint 9.39.5 + typescript-eslint 8.69.0:
- `import tseslintPkg from "typescript-eslint"` (CJS default import) → `tseslint.configs.recommended` (3 blocks, already spread individually) + `tseslintPkg.parser` — API unchanged in v8.
- No `name` additions needed on config blocks (eslint 9 did not reject the anonymous blocks in this setup).
- Legacy `@typescript-eslint/eslint-plugin` / `@typescript-eslint/parser` were confirmed NOT imported — hence removed.
### Why Dockerfile node 18 → 22 (documented scope addition)
- The new tree resolves `@typescript-eslint/parser@8.69.0 → minimatch@^10 → brace-expansion@^5`, whose `engines` is `node "20 || >=22"`; on node 18 `yarn install` (and `yarn install --frozen-lockfile` in the image) fails the engine check. `eslint-visitor-keys@5` (engines `^20.19 || ^22.13 || >=24`) appeared the same way.
- Node 18 is EOL since 2025-04-30; node 22 is the LTS choice. Local dev verified on node **22.14.0** (`~/.nvm/versions/node/v22.14.0`).
- `yarn install --frozen-lockfile` inside the new `node:22` image: clean (verified by full `docker build`).
### Method / notes
- `yarn add -D eslint@^9 typescript-eslint@^8` + `yarn remove @typescript-eslint/eslint-plugin @typescript-eslint/parser` (executed on node 22).
- One environment quirk (dev machine, not repo state): a stale nested `node_modules/typescript-eslint/node_modules/@typescript-eslint/*@7.18.0` survived the major bump (yarn v1 does not prune nested duplicates) and caused a transient `addCandidateTSConfigRootDir is not a function`; resolved by a clean `node_modules` reinstall — lockfile unchanged, no repo impact.
### Left for later
- `package-lock.json` still stale in the repo (unchanged here, per W2d decision — separate Architect call).
- `sass` still 1.69.5 (node-20.19 requirement) — revisit only if node baseline moves further.
- W3 was the FINAL wave → TASK-DEPS-UPDATE can be closed by the Architect.
---
## History
### W1 escalation (2025, commit e79722d)
Baseline was RED before any dependency change — W1 stopped before `yarn up`. Zero dependencies modified.
- `yarn lint` → FAIL: 55 errors (11 auto-fixable). `lint` script runs `prelint: prettier --write .`, auto-rewriting ~30 `src/` files.
- `yarn build` → FAIL: `LineWithLineChart.ts(41,7): error TS2532`.
- Non-auto-fixable classes: `ban-ts-comment`, SFC parse errors in `WorkoutItem.vue:260` / `WorkoutListItem.vue:60`, `no-unused-vars` (`router/index.ts:6`), `no-explicit-any` (`services/utils.ts:11`).
- Resolved by: prerequisite wave W0 (this plan).