# Progress — Strava Frontend ## What works (verified at Memory Bank init) - `yarn dev` / `yarn build` / `yarn lint` scripts defined; build runs `vue-tsc --noEmit` type-check. - App boots: axios providers, Pinia, router, i18n, Vuestic, Yandex Maps, optional GTM (`src/main.ts`). - Auth flow: JWT Bearer interceptor, 401 -> logout redirect, startup `/api/v0/auth/check`. - Pages: workout feed (dashboard), workout list/detail/public detail, upload, routes, preferences, auth pages, 404. - Charts (Chart.js) and Yandex Maps route rendering for workout data. ## Known issues / tech debt (observed, not yet fixed) - `HOST`, Yandex Maps API key and GTM keys hardcoded in `src/main.ts` (no env-driven base URL). - `GetWorkout.ts` uses mutable module-level `let` variables shared across calls (state leakage risk) — refactor to pure functions returning state if touched. - `user-store.ts` embeds a huge base64 avatar blob in source. - No test suite; no global router auth guard (relies on 401 interceptor). - Mixed callback (`.then/.catch`) and imperative styles in pages. - ~~**BLOCKER (2026-09-04, TASK-DEPS-UPDATE-W1)**~~ — **RESOLVED by W0a (build) + W0b (lint)**: both `yarn build` and `yarn lint` are green; W1/W2/W3 unblocked. - `vue/no-mutating-props` in `workouts/components/WorkoutItem.vue` (checkbox/name edits mutate the prop object in place) — suppressed file-targeted in `eslint.config.mjs`; proper fix = local state extraction, needs its own task. - `src/main.ts` axios interceptors loosely typed (`any`) — suppressed file-targeted; pre-existing documented debt. - ~~**`typescript` capped at 5.4.5** (TASK-DEPS-UPDATE-W1)~~ — **RESOLVED by W2b**: `typescript` now 5.8.3 (`"5.8"` pinned no-caret in package.json), `vue-tsc` 2.2.12 (`^2`). vue-tsc 2.x officially supports TS up to 5.8 — do NOT go to TS 5.9. - **`sass` left at 1.69.5** (TASK-DEPS-UPDATE-W1): latest 1.x (1.104.0) requires node ≥20.19.0, baseline is node 18.19.1. Revisit on node 20 baseline or as a follow-up. - Installed yarn 1.22.22 binary lacks the `up` alias — use `yarn upgrade` (verified equivalent). ## Milestones ### 2026-09-05 — TASK-DEPS-UPDATE-W0a: baseline `yarn build` green (uncommitted) - Replaced `// @ts-ignore` with non-null assertions (`data!.labels!`) in `LineWithLineChart.ts` `draw()` — eliminates the latent TS2532 and the `ban-ts-comment` lint error for that file. - Verified: `vue-tsc --noEmit` 0 errors, `vite build` OK (1309 modules). - The two SFC "parsing errors" were confirmed eslint-only (vite/vue-tsc parse both files fine) — deferred to W0b along with remaining lint errors. - Note: on the clean tree the build was already green (TS2532 was suppressed by the `@ts-ignore`); the fix is still required because stricter TS/vue-tsc in W2 would re-surface it without the suppression. ### 2026-09-05 — TASK-DEPS-UPDATE-W0b: `yarn lint` green (uncommitted) - Rewrote `eslint.config.mjs` (flat config): - TS parser wired into `.vue` files (`languageOptions.parserOptions.parser = tsParser` from `typescript-eslint` CJS default import) — this was the root cause of all ~20 SFC parse errors (vue flat preset leaves espree as inner parser). - `@typescript-eslint/no-unused-vars` global `argsIgnorePattern: "^_"`. - File-targeted overrides only (no inline eslint-disable anywhere): `src/main.ts` (any + unused, documented exception), `src/pages/**/*.vue` (multi-word names), `Logout.vue` (valid-template-root), `components/WorkoutItem.vue` (no-mutating-props). - Code fixes (21 files, type-only / dead-code / unused-cleanup): unused import in `router/index.ts`; `any`→`unknown`/`Event`/structural types across `services/utils.ts`, auth pages, workouts pages, `AppLayoutNavigation.vue`; `@ts-ignore`→`@ts-expect-error` in `LineWithLineChart.ts`; removed dead code (`VuesticLogo` computed, `PreferencesHeader.readFile`, `Login.HOST`, `AppNavbarActions.t`, `Logout.push`); removed redundant `v-if` on `v-for` in `Feed.vue`/`WorkoutList.vue`; null-safe error handling in `CheckTheEmail.vue` (fixes TS18048/TS18046 surfaced by the new strict typing); `AppSidebar` name → `AppSidebar`; added `:key` to `v-for` marker in `components/WorkoutItem.vue`. - Prettier auto-reformatted ~30 `src/` files via `prelint` — formatting changes are part of the intended clean diff. - Verified: `yarn lint` 0 errors (exit 0), `yarn build` green (`vue-tsc --noEmit` 0 errors, vite build OK). ### 2026-09-05 — TASK-DEPS-UPDATE-W1: patch/minor dependency refresh via `yarn upgrade` (uncommitted) - Ran `yarn upgrade ` (yarn 1.22.22 binary has no `up` alias). Baseline was green before the run (lint 0 errors, build green). - Result: `package.json` unchanged; `yarn.lock` refreshed — 61 direct deps verified, none moved to a new major. Notable bumps: typescript 5.2.2→5.4.5 (capped), postcss 8.4.31→8.5.28, axios 1.7.7→1.20.0, chart.js 4.4.4→4.5.1, eslint 8.57.0→8.57.1, typescript-eslint 7.6.0→7.18.0, @typescript-eslint/* 6.11.0→6.21.0, prettier 3.1.0→3.9.6, tailwindcss 3.4.1→3.4.19, vite 4.5.5→4.5.14, 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, storybook suite →7.6.24, pinia 2.1.7→2.3.1. - Two caps applied (rule 5): `typescript` pinned to 5.4.5 in the lock (vue-tsc 1.8.27 incompatible with TS ≥5.5; `yarn add -D typescript@5.4.5` then `git checkout -- package.json` + 1-line lock key rename `typescript@5.4.5`→`typescript@^5.2.2`); `sass` excluded from the upgrade (engine node ≥20.19.0 vs baseline 18.19.1). - Verified after upgrade: `yarn install --frozen-lockfile` clean; `yarn lint` 0 errors; `yarn build` green (vue-tsc 0 errors, vite build OK ~7.3s). - No `src/` changes in W1; no HOST/Yandex/GTM changes. ### 2026-09-05 — TASK-DEPS-UPDATE-W2a: vue 3.3.9 → 3.5.42 + pinia 2 → 3.0.4 (uncommitted) - `yarn add vue@^3.5 pinia@^3`: `package.json` changed exactly two lines (`vue: 3.3.9 → ^3.5`, `pinia: ^2.1.7 → ^3`); lockfile resolved `vue@3.5.42`, `pinia@3.0.4`. No other direct dep moved to a new major (new lock entries are only the vue 3.5 / pinia 3 subtrees). - Vue 3.5 template type-check surfaced 6× TS2322 (`number[]` → ymaps `LngLat` tuple) in the `vue-yandex-maps` `:settings` props of `src/pages/routes/Route.vue` and `src/pages/workouts/components/WorkoutItem.vue`. Fixed type-only: `ref` in Route.vue; `import type { LngLat }` + 4 template `as LngLat`/`as LngLat[]` casts + `clickCoordinates` typed `ref` in components/WorkoutItem.vue. No runtime/prop-signature changes. - Verified: `yarn lint` 0 errors; `yarn build` green (vue-tsc 0 errors, vite build ~7.5s); `yarn dev` smoke-check OK (boot + key modules serve 200, no console/compile errors). ### 2026-09-05 — TASK-DEPS-UPDATE-W2b: typescript 5.4.5 → 5.8.3 + vue-tsc 1.8.27 → 2.2.12 (uncommitted) - `yarn add -D typescript@5.8 vue-tsc@^2`: `package.json` changed exactly the two lines (`typescript: ^5.2.2 → "5.8"`, `vue-tsc: ^1.8.22 → ^2`); lock resolved `typescript@5.8.3`, `vue-tsc@2.2.12`. No other direct dep moved to a new major (new lock entries are only the vue-tsc 2.x subtree: `@vue/language-core@2.2.12`, `@volar/*@2.4.15`, `muggle-string`, `alien-signals`, `vscode-uri`, `@vue/compiler-vue2`). - vue-tsc 2 + TS 5.8 surfaced 4 type errors in 2 file-upload pages (TS 5.8 `Blob` gained required `bytes` property + definite-assignment TS2454 on the uninitialized `let file`). Fixed type-only: legacy 14-line inline structural `file` type → `let file: File | undefined = undefined` in both files; `formData.append("file", file!)` non-null assertion in `PreferencesHeader.vue` (`WorkoutUpload.vue` already guards `if (file == undefined) return`). No runtime/prop-signature changes. - Verified: baseline green before update; after update `yarn lint` 0 errors, `yarn build` green (vue-tsc 2.2.12 --noEmit 0 errors, vite build ~7.3s). ### 2026-09-05 — TASK-DEPS-UPDATE-W2c: vite 4.5.14 → 5.4.21 + @vitejs/plugin-vue 4.6.2 → 5.2.4 (uncommitted) - `yarn add -D vite@^5 @vitejs/plugin-vue@^5`: `package.json` changed exactly the two lines (`vite: ^4.4.6 → ^5`, `@vitejs/plugin-vue: ^4.2.3 → ^5`); lock resolved `vite@5.4.21`, `@vitejs/plugin-vue@5.2.4`. No other direct dep moved to a new major — new lock entries are only the vite 5 subtree (`rollup@4.63.1` + `@rollup/*` platform binaries, `esbuild@0.21.5` + `@esbuild/*` platform binaries, `@napi-rs/lzma-linux-x64-gnu`); storybook pin `@vitejs/plugin-vue@^4.0.0` still resolves 4.6.2 (separate lock entry); `esbuild@0.18.20`/`rollup@3.30.0` retained for storybook. - No `src/` or `vite.config.ts` changes — config API-compatible between vite 4 and 5. - Warnings: CJS Node API deprecation (vite 5, expected, documented, not fixed); NO sass legacy-API warnings appeared (sass 1.69.5 untouched, per task rule). - Verified: baseline green before update; after update `yarn lint` 0 errors, `yarn build` green (vue-tsc 0 errors, vite 5.4.21 build ~6.5s, 1396 modules); `yarn dev` smoke-check OK (VITE v5.4.21 ready 372 ms; `GET /`, `/src/main.ts`, `/src/App.vue`, `/src/pages/workouts/Feed.vue` all 200; server stopped after check). ### 2026-09-05 — TASK-DEPS-UPDATE-W2c-FIX: Dockerfile switched to yarn (uncommitted) - `Dockerfile` only (2 lines): `COPY package.json package-lock.json ./` → `COPY package.json yarn.lock ./`; `RUN npm install` → `RUN yarn install --frozen-lockfile`. Root cause fixed: the Docker build ran `npm install` against a stale `package-lock.json` while dev uses yarn; npm's strict peer validation failed on `@storybook/vue3-vite@7.6.20` → `@vitejs/plugin-vue@^4` vs root `^5`. yarn 1 resolves this via a nested plugin-vue 4.6.2 for storybook (existing separate lock entry). - `node:18` base image ships yarn 1.22.22 out of the box (verified via `docker run --rm node:18 yarn --version`) — no `npm i -g yarn@1` line added. - `package-lock.json` intentionally left in the repo (removal = separate decision, out of scope). - Verified: `yarn install --frozen-lockfile` clean locally (lockfiles untouched per `git status`); `yarn lint` 0 errors; `yarn build` green (vue-tsc 0 errors, vite 5.4.21 ~6.4s); **full `docker build` green** (image `strava-frontend-w2cfix` built: yarn install + npm run build + nginx steps all OK). ### 2026-09-05 — TASK-DEPS-UPDATE-W2d: dead Storybook deps removed (uncommitted) - `yarn remove` of 9 packages: `storybook`, `@storybook/addon-essentials`, `@storybook/addon-interactions`, `@storybook/addon-links`, `@storybook/blocks`, `@storybook/testing-library`, `@storybook/vue3`, `@storybook/vue3-vite`, `eslint-plugin-storybook` + manual removal of the 2 scripts (`storybook`, `build-storybook`) from `package.json`. - `eslint.config.mjs` verified: zero storybook references — untouched. - `yarn.lock` pruned: `grep -c storybook` → 0; nested `@vitejs/plugin-vue@4.6.2` (storybook peer-conflict workaround) gone — only `@vitejs/plugin-vue@^5` → 5.2.4 remains. - Baseline green before removal; after: `yarn install` clean, `yarn lint` 0 errors, `yarn build` green (vue-tsc 0 errors, vite 5.4.21 ~6.3s, 1396 modules). - No `src/` changes; `package-lock.json` left stale (separate decision). ### 2026-09-05 — TASK-DEPS-UPDATE-W3 (FINAL): eslint 8→9 + typescript-eslint 7→8 (uncommitted) - `package.json` devDeps: `eslint` ^8.57.0→**^9** (resolved 9.39.5), `typescript-eslint` ^7.6.0→**^8** (resolved 8.69.0); REMOVED `@typescript-eslint/eslint-plugin@^6.11.0` + `@typescript-eslint/parser@^6.11.0` (not imported by `eslint.config.mjs` — verified). No other package moved to a new major (lock checked: vue 3.5.42, pinia 3, TS 5.8.3, vue-tsc 2.2.12, vite 5.4.21, sass 1.69.5). - `eslint.config.mjs`: **unchanged** — flat config (CJS default-import of the `typescript-eslint` meta-package, `configs.recommended` spread, `tseslintPkg.parser`) works as-is on eslint 9 / typescript-eslint 8. - `Dockerfile`: base image `node:18` → `node:22` (transitive `brace-expansion@5.0.9` / `eslint-visitor-keys@5` engines require node ≥20; node 18 EOL). Local dev verified on node 22.14.0. - Verified: baseline green at wave start; after — `yarn lint` 0 errors, `yarn build` green (vue-tsc 0 errors, vite 5.4.21 ~5.3s), `docker build --pull --no-cache` green (image `strava-frontend-w3`, `yarn install --frozen-lockfile` clean inside image). - No `src/` changes; `vite.config.ts`, i18n, HOST/keys untouched. W3 = FINAL wave → TASK-DEPS-UPDATE ready to close. ## Left to build - (empty — filled as tasks are created)