26 KiB
26 KiB
Progress — Strava Frontend
2026-09-24 — TASK-AUTH-NAV-2: реактивные маршруты в сайдбаре и хлебных крошках
NavigationRoutes.ts: named exportsauthRoutes/publicRoutes, удалён module-levellocalStorage.getItem("token")тернарник.AppSidebar.vue: computedroutesотglobalStore.isAuthenticated;AppLayoutNavigation.vue:traverseпоglobalStore.isAuthenticated ? authRoutes : publicRoutes.- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc 0 ошибок).
2026-09-24 — TASK-AUTH-NAV-1: auth-состояние в Pinia (реактивный isAuthenticated)
src/stores/global-store.ts— state:isAuthenticated(SSR-guardtypeof window !== "undefined"), actionsetAuthenticated(v: boolean).src/pages/auth/Login.vue—import { useGlobalStore }; в.thenпослеlocalStorage.setItem(...)и доpush({ name: "explore" }):globalStore.setAuthenticated(true).src/pages/auth/Logout.vue—import { useGlobalStore }; послеlocalStorage.clear()и доpush({ name: "login" }):globalStore.setAuthenticated(false).- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc 0 errors, vite ✓ 7.17s).
2026-09-19 — TASK-404: HTTP 404 для несуществующих страниц (SEO)
server/index.ts— catch-all 404 handler (app.useбез path, передapp.listen): GET →renderTemplate(SEO-мета, canonical/404), non-GET →res.status(404).send("Not Found").nginx.conf— SPA whitelist location~ ^/(workouts|auth|preferences|404)(/|$)→try_files $uri /index.html; catch-alllocation /→proxy_pass http://127.0.0.1:3001(SSR 404 для неизвестных URL).src/router/index.ts— catch-all redirect:explore→404.src/router/seo.ts—SEO_MAP["404"]добавлен.- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc 0, vite ✓ 7.02s).
2026-09-19 — TASK-F11: SEO @unhead/vue dynamic title + meta description per route
package.json—@unhead/vue^3.4.1 added to dependencies (npm install @unhead/vue --legacy-peer-deps; vite transitively bumped 4.5.5→5.4.21).- Created
src/router/seo.ts—setupSeo(router, head: Unhead):SEO_MAPkeyed by routename(+""for/),DEFAULT_SEOfallback,head.push({ title, meta: [{ name: "description", content }] })+router.afterEach(() => update()). Covers:"",explore,routes,list_workouts,upload_workouts,workout_item,workout_public_item,preferences,login,signup,recover-password. src/main.ts—import { createHead } from "unhead/client",import { headSymbol } from "@unhead/vue";const head = createHead(); app.provide(headSymbol, head); setupSeo(router, head);right afterapp.use(router). (NOTapp.use(head)—ClientUnheadis not a Vue plugin;@unhead/vuev3 installs viaapp.provide(headSymbol, head).)index.html—<title>set to «Cycle Rider — платформа для анализа велотренировок: мощность, пульс, скорость, каденс»; added<meta name="description">in<head>as fallback; moved Yandex.Metrika counter block from<head>to top of<body>(Vite 5 parse5 rejects<div>/<img>inside<noscript>within<head>→disallowed-content-in-noscript-in-head).- Verified:
npm run buildexit 0 (vue-tsc 0 errors, vite build ✓ 6.65s);npm run lintexit 0. - Tech note:
@unhead/vuev3 API —createUnheadis inunheadcore (createHeadfromunhead/clientadds DOM renderer); theUnheadtype is exported fromunhead/types.@unhead/vueitself only re-exportsuseHead/useSeoMeta/injectHead/headSymbol— nocreateHeadfrom it.
2026-09-19 — TASK-PUBLIC-ROUTE-FIX: workout_public_item moved to top-level (no auth)
src/router/index.ts: removed nestedworkout_public_itemfromworkoutschildren; added top-level route/public/workouts/:idbefore catch-all, outside AppLayout.- Result:
/public/workouts/:idaccessible without auth, aligns with SSR endpoint + nginx proxy. - Verified:
yarn lintexit 0,yarn buildexit 0.
2026-09-18 — TASK-SSR-3: Sitemap, robots.txt, nginx, Dockerfile, guards
- Modified:
server/index.ts(+49 lines:GET /sitemap.xml— XML with 3 static URLs + workout URLs from API,Content-Type: application/xml;GET /robots.txt— Disallow/auth/ /workouts/ /preferences/ /admin/, Sitemap line,Content-Type: text/plain). - Modified:
nginx.conf— full rewrite: SSR proxy locations for/explore|/routes|/sitemap.xml|/robots.txtand/public/workouts/;location = /withhascookie token(no cookie → proxy, cookie → static);/assets/with 30d immutable cache; SPA fallbacktry_files $uri /index.html. - Modified:
Dockerfile— multi-stage (node:20-alpine): build stage (yarn install + yarn build), runtime stage (nginx + node, copies dist/, server/, node_modules/, package.json; CMDnpx tsx server/index.ts & nginx -g 'daemon off;'). - Modified:
run.sh—cd /app && npx tsx server/index.ts & nginx -g 'daemon off;'. - Modified:
package.json—tsxmoved from devDependencies to dependencies. - Modified:
src/stores/user-store.ts—typeof window === "undefined"guard instate()(returns empty state on SSR). - Modified:
src/main.ts—typeof window !== "undefined" &&guard beforelocalStorage.getItem("token")(line 110). - Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc 0 errors, vite 6.68s). Curl:/robots.txt→ 200 + correct text;/sitemap.xml→ 200 + valid XML (3 static + 2 workout URLs);/health→ ok.
2026-09-18 — TASK-SSR-2: SSR route handlers
- Modified:
server/index.ts— 4 route handlers:GET /(landing, 302→/explore iftokencookie),GET /explore(public feed viagetPublicWorkouts()),GET /public/workouts/:id(detail viagetPublicWorkout(), 404 on API 404, 500 on other errors),GET /routes(static SEO).app.disable("x-powered-by"). Helpers:getAssetTagsSafe()(falls back to dev script tag if nodist/index.html),escapeHtml,formatDate(DD.MM.YYYY),formatDuration(X ч. Y мин.),formatDistance(m→km 1 decimal),formatSpeed(m/s→km/h rounded). Canonical base:SSR_BASE_URL||https://cycle-rider.ru. - Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc 0 errors). Curl:/→<h1>Cycle Rider — анализ велотренировок</h1>;/routes→<h1>Конструктор маршрутов</h1>;/public/workouts/test→ 500 (API unreachable/404→500 acceptable locally);/explore→ 200;/withtokencookie → 302 →/explore;/health→ ok.
2026-09-18 — TASK-SSR-1: SSR server skeleton
- Created:
server/index.ts,server/template.ts,server/api.ts. - Modified:
package.json(+express, +@types/express, +tsx, +3 scripts). tsconfig.jsonunchanged (server/ already excluded viaincludeglob).- Verified:
yarn lintexit 0,yarn buildexit 0,npx tsx server/index.ts+ curl /health OK.
What works (verified at Memory Bank init)
yarn dev/yarn build/yarn lintscripts defined; build runsvue-tsc --noEmittype-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 insrc/main.ts(no env-driven base URL).GetWorkout.tsuses mutable module-levelletvariables shared across calls (state leakage risk) — refactor to pure functions returning state if touched.user-store.tsembeds 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): bothyarn buildandyarn lintare green; W1/W2/W3 unblocked.vue/no-mutating-propsinworkouts/components/WorkoutItem.vue(checkbox/name edits mutate the prop object in place) — suppressed file-targeted ineslint.config.mjs; proper fix = local state extraction, needs its own task.src/main.tsaxios interceptors loosely typed (any) — suppressed file-targeted; pre-existing documented debt.— RESOLVED by W2b:typescriptcapped at 5.4.5 (TASK-DEPS-UPDATE-W1)typescriptnow 5.8.3 ("5.8"pinned no-caret in package.json),vue-tsc2.2.12 (^2). vue-tsc 2.x officially supports TS up to 5.8 — do NOT go to TS 5.9.sassleft at 1.69.5 (TASK-DEPS-UPDATE-W1): latest 1.x (1.104.0) requires node ≥20.19.0. Docker is now node:22, so a sass bump is viable — verify the local dev node version first; small follow-up task.- Stale
package-lock.jsonin repo (npm workflow abandoned for yarn in W2c-FIX) — remove as a small cleanup task. - yarn v1 nested-stale dirs: after major bumps,
node_modulescan keep leftover nested packages (observed:@typescript-eslint/*@7undertypescript-eslint/) causing transient CJS resolution glitches — fix with a cleanrm -rf node_modules && yarn install; not reproducible from the lockfile. - Installed yarn 1.22.22 binary lacks the
upalias — useyarn upgrade(verified equivalent).
Milestones
2026-09-19 — SSR PHASE COMPLETE (TASK-SSR-0 → SSR-3 + PUBLIC-ROUTE-FIX)
- SSR-0: Renamed
/dashboard→/exploreacross router, nav, auth pages, layout guard. Legacy redirect/dashboard→explore. - SSR-1: Created
server/(Express on :3001):index.ts(app + /health),template.ts(SEO HTML shell with JSON-LD, OG, canonical),api.ts(getPublicWorkouts/getPublicWorkout). - SSR-2: 4 SSR route handlers:
GET /(landing/302),GET /explore,GET /public/workouts/:id,GET /routes. Helpers for formatting. - SSR-3:
GET /sitemap.xml,GET /robots.txt. Nginx rewrite (SSR proxy + SPA fallback). Dockerfile multi-stage (node:20-alpine + nginx). tsx → dependencies. SSR guards in user-store/main.ts. - PUBLIC-ROUTE-FIX:
workout_public_itemmoved to top-level router (outside AppLayout) — accessible without auth, aligns with SSR + nginx. - Final state: SSR renders
/,/explore,/routes,/public/workouts/:id,/sitemap.xml,/robots.txtwith full SEO meta + JSON-LD. Nginx proxies these to :3001; all else → SPA. Docker: multi-stage,npx tsx server/index.ts & nginx. - Verified: lint 0, build 0, docker build 0, curl all SSR endpoints 200.
2026-09-05 — TASK-DEPS-UPDATE-W0a: baseline yarn build green (uncommitted)
- Replaced
// @ts-ignorewith non-null assertions (data!.labels!) inLineWithLineChart.tsdraw()— eliminates the latent TS2532 and theban-ts-commentlint error for that file. - Verified:
vue-tsc --noEmit0 errors,vite buildOK (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
.vuefiles (languageOptions.parserOptions.parser = tsParserfromtypescript-eslintCJS 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-varsglobalargsIgnorePattern: "^_".- 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).
- TS parser wired into
- Code fixes (21 files, type-only / dead-code / unused-cleanup): unused import in
router/index.ts;any→unknown/Event/structural types acrossservices/utils.ts, auth pages, workouts pages,AppLayoutNavigation.vue;@ts-ignore→@ts-expect-errorinLineWithLineChart.ts; removed dead code (VuesticLogocomputed,PreferencesHeader.readFile,Login.HOST,AppNavbarActions.t,Logout.push); removed redundantv-ifonv-forinFeed.vue/WorkoutList.vue; null-safe error handling inCheckTheEmail.vue(fixes TS18048/TS18046 surfaced by the new strict typing);AppSidebarname →AppSidebar; added:keytov-formarker incomponents/WorkoutItem.vue. - Prettier auto-reformatted ~30
src/files viaprelint— formatting changes are part of the intended clean diff. - Verified:
yarn lint0 errors (exit 0),yarn buildgreen (vue-tsc --noEmit0 errors, vite build OK).
2026-09-05 — TASK-DEPS-UPDATE-W1: patch/minor dependency refresh via yarn upgrade (uncommitted)
- Ran
yarn upgrade <all direct deps except sass>(yarn 1.22.22 binary has noupalias). Baseline was green before the run (lint 0 errors, build green). - Result:
package.jsonunchanged;yarn.lockrefreshed — 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):
typescriptpinned to 5.4.5 in the lock (vue-tsc 1.8.27 incompatible with TS ≥5.5;yarn add -D typescript@5.4.5thengit checkout -- package.json+ 1-line lock key renametypescript@5.4.5→typescript@^5.2.2);sassexcluded from the upgrade (engine node ≥20.19.0 vs baseline 18.19.1). - Verified after upgrade:
yarn install --frozen-lockfileclean;yarn lint0 errors;yarn buildgreen (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.jsonchanged exactly two lines (vue: 3.3.9 → ^3.5,pinia: ^2.1.7 → ^3); lockfile resolvedvue@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[]→ ymapsLngLattuple) in thevue-yandex-maps:settingsprops ofsrc/pages/routes/Route.vueandsrc/pages/workouts/components/WorkoutItem.vue. Fixed type-only:ref<LngLat>in Route.vue;import type { LngLat }+ 4 templateas LngLat/as LngLat[]casts +clickCoordinatestypedref<LngLat[]>in components/WorkoutItem.vue. No runtime/prop-signature changes. - Verified:
yarn lint0 errors;yarn buildgreen (vue-tsc 0 errors, vite build ~7.5s);yarn devsmoke-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.jsonchanged exactly the two lines (typescript: ^5.2.2 → "5.8",vue-tsc: ^1.8.22 → ^2); lock resolvedtypescript@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
Blobgained requiredbytesproperty + definite-assignment TS2454 on the uninitializedlet file). Fixed type-only: legacy 14-line inline structuralfiletype →let file: File | undefined = undefinedin both files;formData.append("file", file!)non-null assertion inPreferencesHeader.vue(WorkoutUpload.vuealready guardsif (file == undefined) return). No runtime/prop-signature changes. - Verified: baseline green before update; after update
yarn lint0 errors,yarn buildgreen (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.jsonchanged exactly the two lines (vite: ^4.4.6 → ^5,@vitejs/plugin-vue: ^4.2.3 → ^5); lock resolvedvite@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.0still resolves 4.6.2 (separate lock entry);esbuild@0.18.20/rollup@3.30.0retained for storybook.- No
src/orvite.config.tschanges — 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 lint0 errors,yarn buildgreen (vue-tsc 0 errors, vite 5.4.21 build ~6.5s, 1396 modules);yarn devsmoke-check OK (VITE v5.4.21 ready 372 ms;GET /,/src/main.ts,/src/App.vue,/src/pages/workouts/Feed.vueall 200; server stopped after check).
2026-09-05 — TASK-DEPS-UPDATE-W2c-FIX: Dockerfile switched to yarn (uncommitted)
Dockerfileonly (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 rannpm installagainst a stalepackage-lock.jsonwhile dev uses yarn; npm's strict peer validation failed on@storybook/vue3-vite@7.6.20→@vitejs/plugin-vue@^4vs root^5. yarn 1 resolves this via a nested plugin-vue 4.6.2 for storybook (existing separate lock entry).node:18base image ships yarn 1.22.22 out of the box (verified viadocker run --rm node:18 yarn --version) — nonpm i -g yarn@1line added.package-lock.jsonintentionally left in the repo (removal = separate decision, out of scope).- Verified:
yarn install --frozen-lockfileclean locally (lockfiles untouched pergit status);yarn lint0 errors;yarn buildgreen (vue-tsc 0 errors, vite 5.4.21 ~6.4s); fulldocker buildgreen (imagestrava-frontend-w2cfixbuilt: yarn install + npm run build + nginx steps all OK).
2026-09-05 — TASK-DEPS-UPDATE-W2d: dead Storybook deps removed (uncommitted)
yarn removeof 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) frompackage.json.eslint.config.mjsverified: zero storybook references — untouched.yarn.lockpruned: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 installclean,yarn lint0 errors,yarn buildgreen (vue-tsc 0 errors, vite 5.4.21 ~6.3s, 1396 modules). - No
src/changes;package-lock.jsonleft stale (separate decision).
2026-09-05 — TASK-DEPS-UPDATE-W3 (FINAL): eslint 8→9 + typescript-eslint 7→8 (uncommitted)
package.jsondevDeps: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 byeslint.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 thetypescript-eslintmeta-package,configs.recommendedspread,tseslintPkg.parser) works as-is on eslint 9 / typescript-eslint 8.Dockerfile: base imagenode:18→node:22(transitivebrace-expansion@5.0.9/eslint-visitor-keys@5engines require node ≥20; node 18 EOL). Local dev verified on node 22.14.0.- Verified: baseline green at wave start; after —
yarn lint0 errors,yarn buildgreen (vue-tsc 0 errors, vite 5.4.21 ~5.3s),docker build --pull --no-cachegreen (imagestrava-frontend-w3,yarn install --frozen-lockfileclean inside image). - No
src/changes;vite.config.ts, i18n, HOST/keys untouched. W3 = FINAL wave → TASK-DEPS-UPDATE ready to close.
2026-09-05 — TASK-DEPS-UPDATE CLOSED (parent)
- All waves W0a → W3 completed and Architect-verified. Final stack: vue 3.5.42, pinia 3.0.4, TS 5.8.3, vue-tsc 2.2.12, vite 5.4.21, @vitejs/plugin-vue 5.2.4, eslint 9.39.5, typescript-eslint 8.69.0, axios 1.20.0, tailwind 3.4.19, vuestic 1.10.3, node:22 (Docker). Storybook fully removed.
- End state:
yarn lint0 errors,yarn buildgreen,docker buildgreen. Runtime behavior unchanged (type-level + config + lockfile only). - Lessons captured in
systemPatterns.md: TS parser for.vuein flat eslint config;LngLattyping contract for vue-yandex-maps; vue-tsc 2 ↔ TS ≤5.8 ceiling; yarn-only workflow;ban-ts-commentenforcement.
Left to build (small follow-ups, no urgency)
- Remove stale
package-lock.jsonfrom the repo (npm workflow abandoned in W2c-FIX). - Bump
sassto latest 1.x — Docker (node:22) is ready; check local dev node ≥20.19 first. - Consider vite 6/7 after the ecosystem settles (own breaking changes).
GetWorkout.tsmodule-levelletrefactor to pure functions returning state.components/WorkoutItem.vueprop mutation → local state extraction (unblock theno-mutating-propssuppression).
2026-09-12 — TASK-F1: workout photos gallery + upload/delete + map markers (uncommitted)
src/pages/workouts/Definitions.vue:WorkoutPhototype ({id, url, size, latitude: number|null, longitude: number|null}) +photos?: Array<WorkoutPhoto>inWorkoutItem. No fetch changes (backend already sendsworkout.photosviaGET /workouts/{id}/ public / list).src/pages/workouts/components/WorkoutItem.vue: localphotosref initialized fromworkoutItem?.photos;photosWithCoordscomputed (non-null lat/lon); photo markers as<yandex-map-default-marker>withcoordinates: [lon, lat] as LngLat(same order asclickCoordinates),color: 'blue',onClick→window.open(photo.url, "_blank").- Same file:
#workout-photossection under the map/short-data container — grid of<img :src="photo.url">(auto-fill 160px, 120px cover), «Добавить фото» (v-if="isPrivate", hiddeninput[type=file] accept="image/*" multiple,axiosAuth.postmultipart fieldfile,Promise.allSettled, success → push tophotos+ toast, partial failure → error toast, VaButton:loading), per-photo «Удалить» (v-if="isPrivate",axiosAuth.delete→ filter fromphotos, error toast).isPrivateadded todefinePropsdestructure. Styles:.workout-photos-*block. WorkoutListItem.vueuntouched (per scope).- Verified:
npm run buildexit 0 (vue-tsc --noEmit 0 errors, vite✓ built in 11.71s; pre-existing >500kB chunk warning),npm run lintexit 0 (prettier reformatted the component, eslint 0 errors).
2026-09-17 — TASK-LINK1: «Ссылки на описание» скрыта на публичной странице без ссылки (uncommitted)
src/pages/workouts/components/WorkoutItem.vue(единственный файл, 1 строка): на внешнийdiv.workout-item-paramsсекции «Ссылки на описание» добавленv-if="dzenLink || isPrivate". Поведение: публичная без ссылки → секция скрыта; публичная со ссылкой → только «Дзен»; приватная без ссылки → «Добавить» (модалка доступна); приватная со ссылкой → «Дзен» + иконка edit. Внутренняя логика секции не тронута.- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc --noEmit 0 ошибок, vite✓ built in 5.41s; pre-existing >500kB chunk warning).
2026-09-18 — TASK-SSR-0: rename /dashboard → /explore + legacy redirect (uncommitted)
src/router/index.ts: маршрутname: "explore",path: "explore"(Feed.vue); catch-all и admin redirect →{ name: "explore" }; новый legacy redirect{ path: "/dashboard", redirect: { name: "explore" } }(до catch-all).src/components/sidebar/NavigationRoutes.ts:name: "dashboard"→"explore"вauthRoutesиpublicRoutes(i18n-ключmenu.dashboardсохранён).src/components/app-layout-navigation/AppLayoutNavigation.vue: breadcrumb:to="{ name: 'explore' }".src/layouts/AppLayout.vue: auth-guarduseRoute().path != "/explore".src/pages/auth/Login.vue(2×),src/pages/auth/Signup.vue(2×),src/pages/auth/CheckTheEmail.vue(1×):push({ name: "explore" }).src/pages/workouts/Feed.vue: изменений не потребовалось (ссылок на dashboard нет).- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc --noEmit 0 ошибок, vite✓ built in 6.99s; pre-existing >500kB chunk warning).