### Project Installation
Source: https://github.com/alexanderop/workouttracker/blob/main/README.md
Install project dependencies using pnpm.
```bash
pnpm install
```
--------------------------------
### Configure Browser Test Setup
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/vitest-browser-mode-plan.md
Create `src/__tests__/browser/setup.ts` to configure global stubs and mocks for browser tests. This example shows how to stub `Teleport` components and mock the `$t` function for i18n.
```typescript
import { config } from 'vitest-browser-vue'
// Global stubs for shadcn-vue components that use Teleport
config.global.stubs = {
Teleport: true,
}
// Mock i18n if needed
config.global.mocks = {
$t: (key: string) => key,
}
```
--------------------------------
### Define Script Setup with TypeScript
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
All components must use the script setup syntax with TypeScript.
```vue
```
--------------------------------
### Vitest Browser Mode Setup
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/vitest-browser-mode.md
A minimal setup file for Vitest Browser Mode that leverages native browser APIs.
```typescript
// Browser setup - real APIs, no mocks needed
import 'fake-indexeddb/auto'
export { resetDatabase } from '../helpers/resetDatabase'
```
--------------------------------
### jsdom Mock Setup
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/vitest-browser-mode.md
A complex setup file required to polyfill missing browser APIs in a jsdom environment.
```typescript
// jsdom setup - 49 lines of faking browser APIs
import 'fake-indexeddb/auto'
import { setupAudioContextMock } from './helpers/audioMock'
setupAudioContextMock() // 101 more lines in a separate file!
window.matchMedia = (query: string): MediaQueryList => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => true,
})
Object.defineProperty(window.HTMLMediaElement.prototype, 'play', {
configurable: true,
writable: true,
value: vi.fn().mockResolvedValue(undefined),
})
// ... more mocks for pause, load, etc.
```
--------------------------------
### Setup Pre-commit Hooks
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Commands and configuration for Husky and lint-staged to automate linting before commits.
```bash
pnpm add -D husky lint-staged
pnpm husky init
```
```json
{
"lint-staged": {
"*.{ts,vue,js}": "eslint --fix --cache",
"*.md": "markdownlint-cli2 --fix"
}
}
```
```bash
# .husky/pre-commit
pnpm lint-staged
pnpm type-check
```
--------------------------------
### Install shadcn-vue Components
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Command-line instructions to initialize shadcn-vue in a project and add specific components like 'button' and 'dialog'.
```bash
npx shadcn-vue@latest init
npx shadcn-vue@latest add button dialog
```
--------------------------------
### Standard Component Organization
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Follow the recommended order of operations within the script setup block.
```vue
```
--------------------------------
### Usage of ExerciseSettingsItem
Source: https://github.com/alexanderop/workouttracker/blob/main/plan/vue-component-review.md
Example implementation showing how to use the ExerciseSettingsItem component within a parent container.
```vue
```
--------------------------------
### Install Vitest Browser Dependencies
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/vitest-browser-mode-plan.md
Install the necessary Vitest packages for browser testing and Playwright browsers. Run `pnpm exec playwright install chromium` to download the Chromium browser for Playwright.
```bash
pnpm install -D vitest@latest @vitest/browser-playwright vitest-browser-vue
pnpm exec playwright install chromium
```
--------------------------------
### Development Server
Source: https://github.com/alexanderop/workouttracker/blob/main/README.md
Start the development server with Hot Module Replacement (HMR).
```bash
pnpm dev
```
--------------------------------
### View script output examples
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/enforcing-clean-composable-architecture-vue.md
Expected console output when running the composable usage check.
```text
$ pnpm check:composables
⚠️ useUserGreeting (src/composables/useUserGreeting.ts) - only 1 usage(s), minimum is 2
```
```text
$ pnpm check:composables
✓ All composables are used at least 2 times
```
--------------------------------
### Monolithic Component Structure Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/REFACTORING_PATTERNS.md
An example of a monolithic component structure before refactoring.
```text
src/views/ActiveWorkout.vue (520 lines)
├── State: workout, restTime, showAddExercise, ...
├── Functions: calculate10RM, formatTime, toggleTimer, ...
├── Template: Header, Carousel, Table, History, Timer
└── All mixed together
```
--------------------------------
### Install VueUse RxJS Dependencies
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/dexie-improvements.md
Command to add necessary packages for reactive query integration.
```bash
pnpm add @vueuse/rxjs rxjs
```
--------------------------------
### Install VueUse Core Package
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Install the VueUse core package, a required utility library for Vue 3 Composition API.
```bash
pnpm add @vueuse/core
```
--------------------------------
### Plate Calculator Output Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/PRODUCT_ROADMAP.md
Example output from the plate calculator showing bar weight, weight per side, and total weight. Configurable plates and nearest achievable weight are supported.
```text
Bar: 20kg
Each side: 20kg + 15kg + 5kg
Total: 100kg
```
--------------------------------
### shadcn-vue Carousel Installation and Reference
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Installation command and interface definition for the Carousel component.
```bash
pnpm dlx shadcn-vue@latest add carousel
```
```typescript
interface CarouselApi {
scrollTo(index: number, jump: boolean): void // jump=true for instant (no animation)
selectedScrollSnap(): number // Current slide (0-based)
on(event: 'select', callback: () => void): void
canScrollNext(): boolean
canScrollPrev(): boolean
}
```
--------------------------------
### Install Browser Testing Dependencies
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/vitest-browser-mode.md
Command to add the necessary Vitest browser and Playwright packages.
```bash
pnpm add -D @vitest/browser @vitest/browser-playwright playwright
```
--------------------------------
### Add Pinia to `withSetup()` Helper (After)
Source: https://github.com/alexanderop/workouttracker/blob/main/.plan.md
This updated `withSetup` helper installs Pinia using `app.use(createPinia())`, ensuring Pinia context is available for composables in browser tests. Each call creates a new Pinia instance.
```typescript
import type { App } from 'vue'
import { createApp } from 'vue'
import { createPinia } from 'pinia' // ← ADD
export function withSetup(composable: () => TResult): [TResult, App] {
let result: TResult
const app = createApp({
setup() {
result = composable()
return () => {}
},
})
app.use(createPinia()) // ← ADD
app.mount(document.createElement('div'))
// @ts-expect-error - result is assigned synchronously in setup
return [result, app]
}
```
--------------------------------
### PWA Installation Detection
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Uses the `matchMedia` API to detect if the application is currently running in standalone mode as a Progressive Web App. This is used to dynamically skip the PWA installation slide.
```javascript
matchMedia('display-mode: standalone')
```
--------------------------------
### Install shadcn-vue calendar component
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/2024-12-14-workout-calendar-design.md
Use this command to add the required calendar component to the project.
```bash
pnpm dlx shadcn-vue@latest add calendar
```
--------------------------------
### Initialize Internationalization
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Setup for vue-i18n with English as the default locale.
```typescript
import { createI18n } from 'vue-i18n'
import en from './locales/en.json'
export const i18n = createI18n({
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: { en },
})
```
--------------------------------
### Weekly Program Planner Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/PRODUCT_ROADMAP.md
A sample weekly schedule for a training program, showing assigned workouts and rest days. Supports drag-and-drop scheduling and recurring weekly routines.
```text
Monday: Push Day (template)
Tuesday: Pull Day (template)
Wednesday: Rest
Thursday: Legs (template)
Friday: Upper Body (template)
Saturday: CrossFit WOD
Sunday: Rest
```
--------------------------------
### Define Vite Environment Variables
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Example of .env file structure for Vite environment variables.
```bash
# .env
VITE_API_URL=https://api.example.com
VITE_APP_VERSION=$npm_package_version
# .env.local (gitignored)
VITE_API_KEY=secret-dev-key
```
--------------------------------
### Add Pinia to `withSetup()` Helper (Before)
Source: https://github.com/alexanderop/workouttracker/blob/main/.plan.md
The original `withSetup` helper function in `src/__tests__/helpers/withSetup.ts` did not install Pinia, causing issues in browser tests where Pinia context was expected.
```typescript
import type { App } from 'vue'
import { createApp } from 'vue'
export function withSetup(composable: () => TResult): [TResult, App] {
let result: TResult
const app = createApp({
setup() {
result = composable()
return () => {}
},
})
app.mount(document.createElement('div'))
// @ts-expect-error - result is assigned synchronously in setup
return [result, app]
}
```
--------------------------------
### Refactoring Output Summary
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/REFACTOR_COMMAND_USAGE.md
Example output showing the results of a successful refactoring operation, including metrics and file changes.
```text
✅ Refactoring Complete
📊 Improvements:
• Component size reduced by 88%
• 6 reusable child components created
• 2 state/logic composables extracted
• 2 pure utility functions extracted
📁 Files Created:
+ src/lib/workout-utils.ts
+ src/composables/useWorkout.ts
+ src/composables/useRestTimer.ts
+ src/components/workout/WorkoutHeader.vue
+ src/components/workout/ExerciseCarousel.vue
+ src/components/workout/SetTable.vue
+ src/components/workout/PreviousHistory.vue
+ src/components/workout/RestTimerWidget.vue
+ src/components/workout/WorkoutAddExerciseDialog.vue
📝 Files Modified:
~ src/views/ActiveWorkout.vue (520 → 62 lines)
⚙️ Recommended Next Steps:
1. Run: pnpm type-check
2. Run: pnpm lint
3. Run: pnpm test
4. Review components for domain-specific adjustments
```
--------------------------------
### Handle Tool Execution Errors
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/TIL-claude-parallel-tools.md
Example output showing error results when the system attempts to execute invalid tool calls parsed from text.
```xml
EditFile does not exist.EditFile does not exist.
```
--------------------------------
### Define CI/CD Pipeline
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
GitHub Actions workflow for continuous integration, including setup, linting, type-checking, and testing.
```yaml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
setup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
lint:
needs: setup
# parallel with type-check, test
type-check:
needs: setup
# parallel
test:
needs: setup
strategy:
matrix:
shard: [1, 2, 3, 4]
# run: pnpm vitest --shard=${{ matrix.shard }}/4
```
--------------------------------
### Implement Context Menu with VueUse
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/2026-01-16-set-context-menu.md
Full example of using onLongPress and onClickOutside to manage a context menu for set rows.
```vue
```
--------------------------------
### Manage Workout Templates Repository
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/agent/database.md
Create templates from active workouts, start workouts from existing templates, and retrieve all templates sorted by usage.
```typescript
const repo = getTemplatesRepository()
// Create template from active workout
const template = await repo.createFromWorkout(activeWorkout, 'My Template')
// Start workout from template (updates lastUsedAt)
const workout = await repo.startFromTemplate(templateId)
// Get all templates (sorted by lastUsedAt)
const templates = await repo.getAll()
```
--------------------------------
### Configure CI for Browser Tests
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/vitest-browser-mode-plan.md
GitHub Actions workflow steps to install Playwright dependencies and execute browser tests in a CI environment.
```yaml
- name: Install Playwright
run: pnpm exec playwright install chromium --with-deps
- name: Run Browser Tests
run: pnpm test:browser
env:
CI: true
```
--------------------------------
### Create Test App Helper
Source: https://github.com/alexanderop/workouttracker/blob/main/blog-tdd-workflow-claude-code.md
A helper function that initializes a testing environment with Pinia, Vue Router, and user-event setup for consistent integration testing.
```typescript
export async function createTestApp(): Promise {
const pinia = createPinia()
const router = createRouter({
history: createMemoryHistory(),
routes,
})
const user = userEvent.setup()
render(App, {
global: {
plugins: [router, pinia],
},
})
await router.isReady()
return {
router,
user,
getByRole: screen.getByRole,
getByText: screen.getByText,
// ... more helpers
waitForDialog: () => waitFor(() => screen.getByRole('dialog')),
waitForRoute: (pattern) => waitFor(() => {
if (!pattern.test(router.currentRoute.value.path)) {
throw new Error(`Route mismatch`)
}
}),
// ... domain-specific helpers
fillSet: async (index, values) => { /* ... */ },
getSetRow: (index) => { /* ... */ },
}
}
```
--------------------------------
### Onboarding State Management Interface
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Defines the state interface for the onboarding composable, including current step, completion status, returning user flag, and PWA installation status. Persists `currentStep` for resuming onboarding.
```typescript
interface OnboardingState {
currentStep: number // 0-indexed (0-5), persisted for resume
completed: boolean // true when finished or skipped
isReturningUser: boolean // true if existing data detected
isPwaInstalled: boolean // true if running as PWA
}
// Computed
totalSlides: number // 5 if PWA installed, 6 otherwise
```
--------------------------------
### Achievement Badges Categories
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/PRODUCT_ROADMAP.md
Defines categories for achievement badges, including 'Getting Started', 'Consistency', 'Strength', 'Volume', and 'Benchmarks', with examples for each.
```text
Categories:
- Getting Started: First workout, first template, first benchmark
- Consistency: 7-day streak, 30-day streak, 100 workouts
- Strength: First PR, 10 PRs, PR in every major lift
- Volume: 10,000kg week, 100,000kg month, 1 million kg lifetime
- Benchmarks: Complete Fran, sub-5 Fran, complete all Hero WODs
```
--------------------------------
### Implement Onboarding Repository
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Creates a repository for managing onboarding state with fail-open error handling.
```typescript
// src/db/implementations/dexie/onboarding.ts
export function createDexieOnboardingRepository(
database: WorkoutTrackerDatabase
): OnboardingRepository {
return {
async get() {
try {
const record = await database.onboarding.get('onboarding')
return record ?? { id: 'onboarding', completed: false, currentStep: 0 }
} catch {
// Fail-open: assume complete to avoid blocking app access
return { id: 'onboarding', completed: true, currentStep: 0 }
}
},
async update(data: Partial) {
await database.onboarding.put({ id: 'onboarding', ...data })
}
}
}
```
--------------------------------
### Production Build
Source: https://github.com/alexanderop/workouttracker/blob/main/README.md
Perform type-checking and build the application for production.
```bash
pnpm build
```
--------------------------------
### English Message Domain Example (Common)
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/2025-12-03-i18n-design.md
Example of a message domain file for English, defining common strings for buttons, states, and empty states. Uses 'as const' for literal type inference.
```typescript
// src/i18n/messages/en/common.ts
export default {
buttons: {
cancel: 'Cancel',
save: 'Save',
delete: 'Delete',
create: 'Create',
finish: 'Finish',
},
states: {
loading: 'Loading...',
exporting: 'Exporting...',
},
empty: {
noResults: 'No results found',
noResultsFor: 'No results for "{query}"'
},
} as const
```
--------------------------------
### File Structure for Onboarding Feature
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Provides an overview of the directory structure for the onboarding feature, detailing the organization of components, composables, constants, and views.
```treeview
src/features/onboarding/
├── components/
│ ├── OnboardingCarousel.vue # Main carousel wrapper
│ ├── OnboardingSlide.vue # Generic slide layout
│ ├── WelcomeSlide.vue # Slide 1
│ ├── PwaInstallSlide.vue # Slide 2 (conditionally included)
│ ├── QuickWorkoutSlide.vue # Slide 3
│ ├── TemplatesSlide.vue # Slide 4
│ ├── BenchmarksSlide.vue # Slide 5
│ ├── ChecklistSlide.vue # Slide 6
│ └── previews/
│ ├── OnboardingBlockPreview.vue
│ ├── OnboardingTemplatePreview.vue
│ └── OnboardingBenchmarkPreview.vue
├── composables/
│ └── useOnboarding.ts # State management + persistence
├── constants/
│ └── previewData.ts # Sample data for previews
├── views/
│ └── OnboardingView.vue # Route component
└── spec.md # This file
```
--------------------------------
### Mutation Testing: Boolean Logic Operator Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog-draft-mutation-testing-with-ai.md
Demonstrates a mutation on a boolean condition by negating it. This mutation helps verify that tests correctly handle both positive and negative outcomes of logical checks. The example shows the original condition, the mutated version, and the test outcome.
```typescript
// Original (composables/useTheme.ts:26)
newMode === 'dark'
// Mutation: Negate the condition
newMode !== 'dark'
// Result: Tests PASSED → Mutant SURVIVED
```
--------------------------------
### Mutation Testing: Boundary Operator Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog-draft-mutation-testing-with-ai.md
Illustrates a boundary mutation where a less than operator is changed to less than or equal to. This type of mutation is effective for testing edge cases in numerical comparisons. The provided example shows the original code, the mutation applied, and the test result.
```typescript
// Original (stores/settings.ts:65)
Math.min(Math.max(volume, 0.5), 1)
// Mutation: Change 0.5 to 0.4
Math.min(Math.max(volume, 0.4), 1)
// Result: Tests PASSED → Mutant SURVIVED
```
--------------------------------
### Project Commands
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Common CLI commands for development, testing, linting, and building the project.
```bash
pnpm dev # Development server
pnpm test # Run tests
pnpm lint # Fix lint errors
pnpm type-check # TypeScript checking
pnpm build # Production build
```
--------------------------------
### Mutation Testing: Error Handling Path Example
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog-draft-mutation-testing-with-ai.md
Shows a mutation applied to an error handling condition by inverting the check. This mutation is crucial for ensuring that error paths within the code are adequately tested. The example includes the original error check, the mutated version, and the test result.
```typescript
// Original (stores/settings.ts:28)
if (error) return
// Mutation: Negate the condition
if (!error) return
// Result: Tests PASSED → Mutant SURVIVED
```
--------------------------------
### Write Release Notes
Source: https://github.com/alexanderop/workouttracker/blob/main/product-planning/CLAUDE_PROMPTS.md
Use this prompt to generate user-friendly release notes from a list of shipped items.
```text
These items shipped this sprint: [LIST ITEMS]
Write user-friendly release notes that:
1. Focus on user benefits, not technical details
2. Are scannable with clear headers
3. Include any breaking changes or required actions
```
--------------------------------
### PWA Detection Pattern
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Detects PWA installation status with a fallback for Safari iOS.
```typescript
import { useMediaQuery } from '@vueuse/core'
const isPwaInstalled = useMediaQuery('(display-mode: standalone)')
// Safari iOS fallback
const isSafariStandalone = computed(() =>
'standalone' in globalThis.navigator && globalThis.navigator.standalone === true
)
const isPWA = computed(() => isPwaInstalled.value || isSafariStandalone.value)
const totalSlides = computed(() => isPWA.value ? 5 : 6)
```
--------------------------------
### Configure Vue Router
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Setup for Vue Router with named routes and lazy-loaded components.
```typescript
import { createRouter, createWebHistory } from 'vue-router'
export const RouteNames = {
Home: 'home',
WorkoutDetail: 'workout-detail',
Settings: 'settings',
} as const
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: RouteNames.Home,
component: () => import('@/views/HomeView.vue'),
},
{
path: '/workout/:id',
name: RouteNames.WorkoutDetail,
component: () => import('@/views/WorkoutDetailView.vue'),
props: true,
},
],
})
```
--------------------------------
### Onboarding Checklist Items with Deep-Links
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
Illustrates the structure of checklist items for the final onboarding slide, including a descriptive text and a deep-link route name for navigation. Clicking an item marks onboarding complete and navigates to the specified route.
```markdown
- [ ] Create your first template → routes to `TemplatesCreate`
- [ ] Browse the exercise library → routes to `Exercises`
- [ ] Start a quick workout → routes to `WorkoutCreate`
- [ ] Try a benchmark → routes to `Benchmarks`
```
--------------------------------
### Configure Performance Budgets
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Lighthouse CI configuration to enforce performance and accessibility scores.
```json
{
"ci": {
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.80 }],
"categories:accessibility": ["error", { "minScore": 1.0 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 3500 }]
}
}
}
}
```
--------------------------------
### Project Directory Structure
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/TEMPLATE_PLAN.md
The target file and folder hierarchy for the new PWA starter template.
```text
vue-pwa-starter/
├── src/
│ ├── components/
│ │ ├── ui/ # All shadcn-vue (copied as-is)
│ │ ├── Layout.vue
│ │ ├── PageHeader.vue
│ │ ├── PageLayout.vue
│ │ └── ErrorDialog.vue
│ ├── composables/
│ │ ├── usePwaUpdate.ts
│ │ ├── useVersionCheck.ts
│ │ ├── useScreenWakeLock.ts
│ │ ├── useGlobalWakeLock.ts
│ │ ├── useTouchDevice.ts
│ │ ├── useDialogState.ts
│ │ ├── useAnimatedCounter.ts
│ │ ├── useNumberLocale.ts
│ │ └── useEnterAnimation.ts
│ ├── db/
│ │ ├── schema.ts
│ │ ├── interfaces.ts
│ │ ├── implementations/
│ │ │ └── DexieItemRepository.ts
│ │ ├── provider.ts
│ │ ├── converters.ts
│ │ └── index.ts
│ ├── features/
│ │ └── items/
│ │ ├── components/
│ │ │ ├── ItemCard.vue
│ │ │ ├── ItemForm.vue
│ │ │ └── ItemStatusBadge.vue
│ │ ├── composables/
│ │ │ └── useItems.ts
│ │ ├── views/
│ │ │ └── ItemDetailView.vue
│ │ ├── index.ts
│ │ └── CLAUDE.md
│ ├── i18n/
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── messages/
│ │ ├── en.ts
│ │ └── de.ts
│ ├── stores/
│ │ └── settings.ts
│ ├── types/
│ │ └── item.ts
│ ├── views/
│ │ ├── TheHomeView.vue
│ │ ├── TheItemsView.vue
│ │ └── TheSettingsView.vue
│ ├── router/
│ │ └── index.ts
│ ├── __tests__/
│ │ ├── setup.ts
│ │ ├── factories/
│ │ │ └── itemFactory.ts
│ │ ├── helpers/
│ │ │ └── testUtils.ts
│ │ ├── composables/
│ │ │ └── useItems.spec.ts
│ │ ├── db/
│ │ │ └── itemRepository.spec.ts
│ │ └── CLAUDE.md
│ ├── App.vue
│ ├── main.ts
│ └── style.css
├── CLAUDE.md
├── package.json
├── vite.config.ts
├── tsconfig.json
├── eslint.config.js
└── README.md
```
--------------------------------
### Localization Keys for Onboarding
Source: https://github.com/alexanderop/workouttracker/blob/main/src/features/onboarding/spec.md
YAML structure for onboarding-related text localization.
```yaml
onboarding:
welcome:
title: "Workout Tracker"
startTour: "Start Tour"
skipToApp: "Skip to App"
welcomeBack:
title: "Welcome back!"
resumeTour: "Resume Tour"
pwa:
title: "Install for the best experience"
instruction1: "..."
quickWorkout:
title: "Build workouts on the fly"
description: "..."
templates:
title: "Save your favorites"
benchmarks:
title: "Track your progress"
checklist:
title: "You're ready!"
createTemplate: "Create your first template"
browseExercises: "Browse the exercise library"
startWorkout: "Start a quick workout"
tryBenchmark: "Try a benchmark"
navigation:
next: "Next"
back: "Back"
skip: "Skip"
letsGo: "Let's Go"
```
--------------------------------
### Development and Build Commands
Source: https://github.com/alexanderop/workouttracker/blob/main/CLAUDE.md
Standard CLI commands for managing the development lifecycle of the project.
```bash
pnpm dev # Development server
pnpm test # Run tests (NOT test:unit!)
pnpm lint # Fix lint errors
pnpm type-check # TypeScript checking
pnpm build # Production build
pnpm knip # Find unused exports
```
--------------------------------
### Create DbForTimeBenchmark Factory
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/test-factory-improvements.md
Factory for creating 'fortime' type benchmarks. It sets default values specific to this type and includes predefined exercises.
```typescript
import type { DbBenchmark, DbBenchmarkExercise } from '@/db/schema'
import { generateId } from '@/db'
const DEFAULTS: Readonly> = {
name: 'Fran',
type: 'fortime',
rounds: 1,
createdAt: Date.now(),
lastUsedAt: null,
}
export function createDbBenchmarkExercise(
overrides: Partial = {}
): DbBenchmarkExercise {
return {
exerciseDefinitionId: null,
name: 'Thrusters',
prescribedReps: 21,
thumbnail: '🏋️',
...overrides,
}
}
export function createDbForTimeBenchmark(
overrides: Partial = {}
): DbBenchmark {
return createDbBenchmark({
type: 'fortime',
exercises: [
createDbBenchmarkExercise({ name: 'Thrusters', prescribedReps: 21 }),
createDbBenchmarkExercise({ name: 'Pull-ups', prescribedReps: 21 }),
],
...overrides,
})
}
```
--------------------------------
### File Naming Conventions
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Naming patterns for components, utilities, and test files.
```text
Component.vue # PascalCase for components
useFeature.ts # camelCase with 'use' prefix
featureName.ts # camelCase for utilities
feature.spec.ts # camelCase with .spec.ts for tests
```
--------------------------------
### Integrate WeekStrip into HomeView
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/2024-12-14-workout-calendar-design.md
Example of placing the WeekStrip component within the main home view layout.
```vue
{{ t('nav.homeView.greeting') }}
```
--------------------------------
### Define a sample Vue composable
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/enforcing-clean-composable-architecture-vue.md
An example of a composable that might be extracted prematurely if only used in a single component.
```typescript
// src/composables/useUserGreeting.ts
export function useUserGreeting(name: string) {
return computed(() => `Hello, ${name}!`)
}
```
--------------------------------
### Run Project Test Commands
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/test-factory-improvements.md
Standard commands for executing tests and verifying code quality.
```bash
# Run all tests
pnpm test
# Run specific test file you're refactoring
pnpm test src/__tests__/integration/benchmark-flows.spec.ts
# Type check (catch any type errors in factories)
pnpm type-check
# Lint (auto-fix style issues)
pnpm lint
```
--------------------------------
### Integrate check into CI pipeline
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/enforcing-clean-composable-architecture-vue.md
Example GitHub Actions step to enforce the composable usage rule during CI.
```yaml
- name: Check composable usage
run: pnpm check:composables
```
--------------------------------
### Integration Test Structure
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/VUE_STYLE_GUIDE.md
Use createTestApp() instead of render() for integration tests to ensure proper setup and cleanup.
```typescript
describe('Template Flow', () => {
beforeEach(setupIntegrationTest)
afterEach(cleanupIntegrationTest)
it('should save completed workout as template when user completes flow', async () => {
const { builder, workout, router } = await createTestApp()
await userEvent.click(getByRole('button', { name: /start new workout/i }))
expect(router.currentRoute.value.path).toBe('/workout/builder')
await builder.addExercise('Bench Press')
await builder.startWorkout()
await workout.fillSetAndComplete({ weight: '80', reps: '10' })
await workout.endWorkout()
await userEvent.fill(getByRole('textbox', { name: /name/i }), 'Push Day')
await userEvent.click(getByRole('button', { name: /save template/i }))
const templates = await db.templates.toArray()
expect(templates.find(t => t.name === 'Push Day')).toBeDefined()
})
})
```
--------------------------------
### Update Imports in BenchmarkForTimeView
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/plans/2025-12-14-benchmark-workout-ui-implementation.md
Update the script setup imports to include necessary components and types for the benchmark view.
```vue
```
--------------------------------
### Define Boolean Flag Anti-pattern
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/state-machine-pattern.md
Example of the boolean flag anti-pattern where multiple independent refs can lead to invalid UI states.
```typescript
const showEquipmentModal = ref(false)
const showMuscleModal = ref(false)
const showTypeModal = ref(false)
const showMetricsModal = ref(false)
```
--------------------------------
### Execute Cross-Environment Test
Source: https://github.com/alexanderop/workouttracker/blob/main/docs/blog/vitest-browser-mode.md
Example of a test case that runs identically in both jsdom and browser environments using a shared test helper.
```typescript
it('completes a workout flow', async () => {
const { builder, workout, user, cleanup } = await createTestApp()
await builder.addStrengthBlock('Squat')
await builder.startWorkout()
await workout.fillSet(0, { kg: 100, reps: 8, rir: 2 })
expect(await screen.findByText('1/3')).toBeTruthy()
cleanup()
})
```