112 lines
3.4 KiB
Markdown
112 lines
3.4 KiB
Markdown
## Munch Ease — Plan, Cook, Shop, Repeat
|
||
|
||
Munch Ease is a snappy Vue 3 app that helps you plan meals, manage recipes, and turn plans into stress-free shopping lists. Search and save recipes, build your weekly meal plan, and seamlessly check items off your shopping list—everything stays in sync so you can focus on what’s cooking.
|
||
|
||
Built with modern Vue patterns, a clean API layer, and lightweight tests, the project is easy to extend and fun to work on.
|
||
|
||
---
|
||
|
||
## Quick start
|
||
|
||
1) Install dependencies
|
||
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
2) Run the dev server
|
||
|
||
```bash
|
||
npm run serve
|
||
```
|
||
|
||
3) Run unit tests (Vitest)
|
||
|
||
```bash
|
||
npm run test
|
||
```
|
||
|
||
4) Build for production
|
||
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
Environment
|
||
- API base URL: set VUE_APP_API_BASE (e.g. http://localhost:8081)
|
||
|
||
---
|
||
|
||
## Architecture and conventions
|
||
|
||
Strict TypeScript, Vue 3 Composition API, and a single typed API boundary.
|
||
|
||
Key axioms
|
||
- OpenAPI (generated `src/api/types.ts`) is the single source of truth for shapes.
|
||
- SDK (`src/api/sdk.ts`) is the only data access surface; UI uses domain types from `src/domain/types.ts`.
|
||
- Domain normalization is minimal in `src/domain/decoders.ts` (e.g., date strings → `Date`).
|
||
- No casts (`as`, angle brackets) and no `any`/`unknown` in app code. Generated files are exempt.
|
||
- Arrays that are required in OpenAPI are non-nullable in domain types (e.g., `Meal.recipes`).
|
||
- Disallow runtime type checks in app code; acceptable exceptions: DOM event narrowing, error/env handling in the boundary.
|
||
|
||
Layout
|
||
- `src/api/` — Typed client and SDK boundary
|
||
- `src/domain/` — Domain types and decoders
|
||
- `src/composables/` — Reusable app logic (auth, meals, shopping, pagination, alert)
|
||
- `src/components/` — UI components and pages
|
||
- `src/router/` — Routes and helpers (`parseRouteId`, `parseQueryString`)
|
||
|
||
Testing and tooling
|
||
- Vitest + MSW under `tests/`
|
||
- ESLint (type-aware) + Prettier + Volar
|
||
|
||
---
|
||
|
||
## Development tips
|
||
|
||
- Prefer composables for shared logic; keep components thin.
|
||
- Use computed for derived values; avoid mutating props directly.
|
||
- Use discriminated unions for UI-only shapes when helpful (e.g., shopping `Group`).
|
||
- Add/adjust tests when changing behavior.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
- API errors: verify `VUE_APP_API_BASE` is set and reachable.
|
||
- Type/IDE help: ensure Volar is enabled and ESLint is not conflicting with Prettier.
|
||
- Build issues: this project uses Vue CLI 5. If migrating to Vite, update scripts and configs accordingly.
|
||
|
||
---
|
||
|
||
## Type checking and codegen
|
||
|
||
- Type check (TS strict + vue-tsc):
|
||
|
||
```bash
|
||
npm run typecheck
|
||
```
|
||
|
||
- Generate API types (consumed by SDK):
|
||
|
||
```bash
|
||
npm run codegen
|
||
```
|
||
|
||
Environment
|
||
- VUE_APP_API_BASE (Vue CLI) or VITE_API_BASE_URL (Vite) for API base URL
|
||
|
||
Testing
|
||
- Unit tests use MSW; the client defaults to a localhost base in tests for easy mocking
|
||
|
||
### CurrentShoppingList item kinds
|
||
|
||
The OpenAPI spec models current shopping list items as distinct kinds:
|
||
- outstandingItems: ListIngredientItem[]
|
||
- requestedMeals: RequestedMealItem[]
|
||
- purchasedItems: ListIngredientItem[]
|
||
|
||
The SDK maps these to a domain DTO (`CurrentShoppingListDTO`) and may attach refs (`ingredient`, `recipe`, `meal`, `list`) for convenience. UI code should:
|
||
- Prefer stable IDs (`ingredientId`, `mealId`, `recipeId`, `listId`) for actions and lookups
|
||
- Treat attached refs as optional view helpers (never required)
|
||
- Keep all normalization at the boundary (decoders); avoid casts and runtime type checks in app code
|