munch-ease-frontend/refactor-strategy.md

172 lines
7.3 KiB
Markdown
Raw Normal View History

2025-10-18 01:30:30 +00:00
# Refactor Strategy
This document outlines a pragmatic, step-by-step refactor plan to improve structure, readability, and maintainability. Each step includes a clear outcome and a checkbox to track progress.
Last updated: 2025-10-18
## Goals
2025-10-18 02:08:22 +00:00
2025-10-18 01:30:30 +00:00
- Separate concerns (routing, HTTP/API, mapping/normalization, UI logic)
- Improve readability and testability
- Establish light-weight standards (naming, lint/format) without blocking development
- Keep changes incremental and safe
## Phases and Steps
### Phase 1 — Routing and Auth (Foundational)
2025-10-18 02:08:22 +00:00
2025-10-18 01:30:30 +00:00
- [x] Extract router into `src/router/index.js` with named routes
- [x] Add route meta `requiresAuth` and a global auth guard
- [x] Remove auth-redirect from `App.vue` (handled by guard instead)
2025-10-18 01:36:55 +00:00
- [x] Convert top-level nav to use route names consistently (optional)
2025-10-18 01:30:30 +00:00
Outcome: Routing logic is centralized and testable; pages redirect consistently based on auth.
### Phase 2 — API Layer Split (Incremental)
2025-10-18 02:08:22 +00:00
2025-10-18 01:30:30 +00:00
- [x] Add `src/api/http.js` wrapper for JSON fetch with error handling and env-based base URL
- [x] Add `src/api/mappers/mealMapper.js` to normalize Meal data (dates)
- [x] Add `src/api/meals.js` and migrate MealPlan API calls (get upcoming, mark consumed, delete)
2025-10-18 01:36:55 +00:00
- [x] Create `src/api/recipes.js` and migrate recipe endpoints
- [x] Create `src/api/shopping.js` and migrate shopping endpoints
- [x] Create `src/api/auth.js` and migrate auth endpoints
2025-10-18 01:30:30 +00:00
Outcome: Feature modules call cohesive services; logic for mapping/normalization is isolated and testable.
### Phase 3 — Composables (UI-Facing Logic)
2025-10-18 02:08:22 +00:00
2025-10-18 01:42:23 +00:00
- [x] Add `src/composables/useAuth.js` (user ref, ensureAuth)
2025-10-18 02:01:18 +00:00
- [x] Add `src/composables/useMeals.js` (fetch and mutate meals)
- [x] Refactor pages to use composables and `<script setup>` where appropriate
- Converted: `MealPlanPage.vue`, `EditMealPage.vue`, `CurrentShoppingListPage.vue`, `MyShoppingPage.vue`, `PurchasedShoppingListPage.vue`
- Added: `src/composables/useShopping.js`; adopted by shopping pages
2025-10-18 01:30:30 +00:00
Outcome: Components get smaller and easier to read; business logic is reusable.
### Phase 4 — Tooling and Standards
2025-10-18 02:08:22 +00:00
2025-10-18 01:42:23 +00:00
- [x] Add Prettier config and .editorconfig; wire Prettier with ESLint
2025-10-18 01:30:30 +00:00
- [ ] Upgrade ESLint (if/when convenient) and align with Vue 3 rules
2025-10-18 02:06:25 +00:00
- [x] Ensure Volar is used (dev environment) for Vue 3 type intelligence
- [x] Add lint-staged + husky for `pre-commit` formatting
- Optional next: enable Vue macros (defineProps/defineOptions) in ESLint or upgrade ESLint/vue plugin
2025-10-18 01:30:30 +00:00
Outcome: Stable formatting and consistent linting across contributors.
### Phase 5 — Tests (Targeted)
2025-10-18 02:08:22 +00:00
2025-10-18 02:39:25 +00:00
# Composition API Migration Plan
This document tracks the migration of remaining components to Vue 3 Composition API using `<script setup>`, with clear ordering and acceptance criteria.
Last updated: 2025-10-18
## Goals
- Convert all SFCs to Composition API `<script setup>`.
- Remove Options API patterns (`data`, `methods`, `computed`, `watch`, `this.*`).
- Standardize on composables for cross-cutting concerns (auth, alerts, API calls).
- Keep changes incremental and safe with focused PRs and existing tests.
## Current status
Already using `<script setup>`:
- Meals: `MealPlanPage.vue`, `EditMealPage.vue`
- Shopping: `CurrentShoppingListPage.vue`, `MyShoppingPage.vue`, `PurchasedShoppingListPage.vue`
Remaining to migrate (Options API or mixed):
- Core
- `App.vue`
- `components/AlertToast.vue`
- `components/ActionItem.vue`
- `components/LoginPage.vue`
- Recipes
- `components/recipes/RecipesPage.vue`
- `components/recipes/RecipeSearchBox.vue`
- `components/recipes/RecipeCard.vue`
- `components/recipes/EditRecipePage.vue` (most complex)
- Meals
- `components/meals/MealCard.vue`
- `components/meals/DatePicker.vue`
- `components/meals/PersonList.vue` (mixed Options+setup, unify under `<script setup>`)
- Ingredients
- `components/ingredients/CompactParsedIngredient.vue`
- `components/ingredients/IngredientLine.vue`
- `components/ingredients/EditableIngredientsPanel.vue`
- Shopping
- `components/shopping/MealSelectionList.vue`
- `components/shopping/ShoppingListItem.vue`
## Migration order (batches)
1) Leaf/presentational components (low risk)
- `ActionItem.vue`, `RecipeCard.vue`, `CompactParsedIngredient.vue`
- Patterns: defineProps, no router; replace `props: ['x']` with `defineProps<{...}>` (or JSDoc). Simple emits with `defineEmits`.
2) Simple interactive components
- `IngredientLine.vue`, `MealCard.vue`, `MealSelectionList.vue`, `DatePicker.vue`
- Patterns: replace `data` with `ref/reactive`, computed with `computed`, methods with local functions. Replace `this.$emit` with `emit`.
3) Components with watchers and DOM refs
- `EditableIngredientsPanel.vue`, `PersonList.vue`, `ShoppingListItem.vue`
- Patterns: use `ref` for elements, `onMounted` for subscriptions/layout, `watch` for reactive sources. Ensure timeouts/listeners are cleaned up.
4) Pages and core scaffolding
- `RecipesPage.vue`, `RecipeSearchBox.vue`, `EditRecipePage.vue`, `LoginPage.vue`, `App.vue`, `AlertToast.vue`
- Patterns: replace `this.$router`/`this.$route` with `useRouter`/`useRoute`. Consider a small `useAlert` composable to replace the event bus pattern used by `AlertToast.vue` and current `alert.js`.
## Conventions and helpers
- Routing: `const router = useRouter(); const route = useRoute();`
- Props/Emits:
- `const props = defineProps({ ... })`
- `const emit = defineEmits(['event-name'])`
- State: `const state = reactive({...})` or `const x = ref(initial)`
- Computed/Watch: `const y = computed(() => ...)`; `watch(source, (val, old) => ...)`
- Lifecycle: `onMounted`, `onBeforeUnmount`
- Assets: import statics via `new URL('@/assets/foo.svg', import.meta.url).href` or leave template `require()` where needed (non-blocking).
- Testing: keep current Vitest setup; prefer unit tests for any functional changes.
## Acceptance criteria per component
- The component uses a single `<script setup>` block.
- No `this.*` usage remains; props accessed via `props` or destructured; emits via `emit`.
- Route navigation uses `useRouter`/`useRoute` where applicable.
- All existing functionality and events preserved.
- Lint/test/build pass.
## Tracking checklist
- [ ] Core: `App.vue`
- [ ] Core: `components/AlertToast.vue`
- [ ] Core: `components/ActionItem.vue`
- [ ] Core: `components/LoginPage.vue`
- [ ] Recipes: `components/recipes/RecipesPage.vue`
- [ ] Recipes: `components/recipes/RecipeSearchBox.vue`
- [ ] Recipes: `components/recipes/RecipeCard.vue`
- [ ] Recipes: `components/recipes/EditRecipePage.vue`
- [ ] Meals: `components/meals/MealCard.vue`
- [ ] Meals: `components/meals/DatePicker.vue`
- [ ] Meals: `components/meals/PersonList.vue`
- [ ] Shopping: `components/shopping/MealSelectionList.vue`
- [ ] Shopping: `components/shopping/ShoppingListItem.vue`
## Notes and risks
- `PersonList.vue` aligns a dropdown to an input via DOM measurements; ensure the ref-based approach updates positions correctly on focus/resize.
- `RecipeSearchBox.vue` uses timeouts for debouncing; prefer `watch` with a debounced effect and clean up on unmount.
- `AlertToast.vue` uses a simple event-bus (`alert.js`); consider migrating to a `useAlert` composable with a `ref`-based queue to simplify subscriptions.
## Done (context)
- Routing extracted with auth guard; API layer split; composables for auth/meals/shopping; prettier/husky configured; Vitest tests for mappers and units in place.