# CLAUDE.md — CartWise v1 Development Guide ## Read First This repository builds **CartWise**, a mobile-first grocery companion implemented as a conventional **ASP.NET Core MVC** application. The canonical architecture and scope are defined in `AGENTS.md`. Read `AGENTS.md` completely before making architectural changes. This file gives Claude-specific operating guidance and a compact execution map. --- ## Core Stack Use: - ASP.NET Core MVC - C# - Razor Views - HTML5 - CSS3 - jQuery - vanilla JavaScript - EF Core - PostgreSQL - ASP.NET Core Identity Do not introduce React, Vue, Angular, Blazor, MAUI, Flutter, SPA architecture, microservices, MediatR, or unnecessary repository/unit-of-work wrappers unless explicitly requested. --- ## Product Goal CartWise v1 must help a household: 1. Maintain a shared grocery list. 2. Add generic concepts such as “milk” without requiring exact product selection. 3. Resolve exact packaged products when useful. 4. Scan UPC/GTIN barcodes. 5. Record purchases and prices. 6. Build personal price history. 7. Show typical/low/latest/unit price intelligence. 8. Suggest repeat items that are likely running low. 9. Shop from a simple phone-friendly shopping mode. CartWise must still be useful with **zero retailer API access**. --- ## Architectural Boundaries ### Web `CartWise.Web` - Controllers - Razor Views - ViewModels - HTML/CSS/JS - ASP.NET-specific concerns ### Application `CartWise.Application` - use cases - services - interfaces - validation - DTOs/results ### Domain `CartWise.Domain` - entities - enums - value objects - business rules No EF Core, HTTP, Razor, or provider SDK dependencies here. ### Infrastructure `CartWise.Infrastructure` - DbContext - EF configurations/migrations - PostgreSQL - Open Food Facts/USDA integrations - future retailer adapters Dependency direction should remain clean. --- ## Critical Domain Distinction Never collapse these concepts: ```text GroceryConcept: Peanut Butter Product: Jif Creamy Peanut Butter 16 oz ProductIdentifier: UPC/GTIN identifying that package ``` A shopping list item may exist with only free text / concept data. Product resolution must not be mandatory to make a useful list. UPC/GTIN is never the Product primary key. --- ## Core Entities Implement in the order given in `AGENTS.md`. ### Identity / Household - ApplicationUser - Household - HouseholdMember ### Product Catalog - GroceryConcept - ProductCategory - Brand - Product - ProductIdentifier - HouseholdProductPreference ### Shopping - ShoppingList - ShoppingListItem ### Retail / Location - Retailer - StoreLocation ### History - Purchase - PurchaseItem - PriceObservation See `AGENTS.md` for exact fields, indexes, enums, and relationships. --- ## Required Services Keep controllers thin and use: - `IHouseholdService` - `IShoppingListService` - `IProductService` - `IProductEnrichmentService` - `IPriceService` - `IPurchaseService` - `IReplenishmentService` - `IShoppingModeService` - `IStoreService` Do not create one giant `CartWiseService`. Do not add abstractions without a real responsibility or testability benefit. --- ## Product Provider Rule External provider models stay inside Infrastructure. Use a normalized contract similar to: ```csharp public interface IProductDataProvider { string Name { get; } Task FindByBarcodeAsync( string barcode, CancellationToken cancellationToken = default); Task> SearchAsync( string query, CancellationToken cancellationToken = default); } ``` Lookup is always **local first**, provider second, then normalize and cache. Open Food Facts should be the first packaged-product provider. USDA can enrich generic/nutrition data later. Never expose an external provider's API response object to a controller or Razor view. --- ## Retailer API Rule Retailer integrations are optional. Do not build application logic around specific retailer names. Use capability-aware adapters. Never assume that price, inventory, promotions, or aisle data are available. When data is stale or unavailable, show that state explicitly instead of guessing. --- ## MVC Routes Preserve these route intentions unless existing code requires a compatible adjustment. ```text GET / Home GET /household Household GET /list Active grocery list POST /list/items Add list item POST /list/items/{id}/toggle Toggle purchased POST /list/items/{id}/skip POST /list/items/{id}/delete GET /products/{id} GET /products/search?q= GET /products/barcode/{barcode} GET /scan GET /shopping/start POST /shopping/items/{id}/purchase POST /shopping/items/{id}/skip POST /shopping/items/{id}/unavailable POST /shopping/items/{id}/substitute POST /shopping/complete GET /prices GET /prices/product/{productId} POST /prices/product/{productId}/observe GET /purchases GET /purchases/{id} ``` Use `/api/...` only where browser JavaScript genuinely benefits from JSON. --- ## Razor / JavaScript Rules Razor is primary rendering. jQuery and vanilla JavaScript are both approved. Prefer jQuery for: - DOM selection and manipulation - delegated event handlers - form serialization - AJAX requests - lightweight partial refreshes - shopping-mode UI interactions Prefer vanilla JavaScript for: - barcode camera/scanner browser APIs - `navigator.mediaDevices` - IndexedDB and Service Workers - focused browser-native functionality where jQuery adds no value Organize JavaScript under: ```text wwwroot/js/pages/ wwwroot/js/services/ wwwroot/js/components/ wwwroot/js/utils/ ``` Do not create a global monolithic `app.js`. Do not reinvent client-side framework patterns by hand. Do not mix jQuery and native DOM approaches arbitrarily inside the same function. Use `$.ajax`/`$.get`/`$.post` where jQuery is the clearer choice and `fetch` where native code is more appropriate. Use anti-forgery tokens for every state-changing JavaScript request. --- ## Database Rules - PostgreSQL UUID domain keys. - Identity's normal user key can remain its native string unless deliberately changed project-wide. - UTC timestamps / timestamptz. - decimal/numeric for money and quantities. - no float/double for prices. - explicit EF entity configurations. - no lazy loading. - `AsNoTracking()` for read paths. - protect historical data from accidental cascade deletion. - `PriceObservation` is append-only. - add indexes described in `AGENTS.md`. Every schema change requires an EF Core migration. --- ## Price Intelligence Do not call a stale observation a current price. Every price observation includes: - Product - optional Store - Price/SalePrice - ObservedUtc - SourceType - ConfidenceScore Display source/freshness where material. For a household's typical price, favor median as the robust statistic; average may also be shown. Only label a price “good” after enough history exists. Unit price comparisons must use compatible units. --- ## Replenishment Algorithm v1 No ML or LLM required. Use purchase history: 1. get recent purchase dates 2. calculate intervals 3. use median interval when enough data exists 4. estimate next due date 5. return a suggestion with confidence and reason Never automatically add predicted groceries to the list. The user chooses. --- ## Authorization Household isolation is critical. For every household-scoped resource: - derive or validate household context server-side - verify current user membership - do not trust posted HouseholdId alone - prevent IDOR Use centralized household authorization/service logic. All state-changing MVC requests require anti-forgery protection. --- ## Working Style for Claude Before modifying code: 1. Read `AGENTS.md`. 2. Inspect the relevant existing controller/service/entity/configuration/tests. 3. Identify the smallest vertical change that satisfies the request. 4. Preserve existing architecture unless it conflicts with the specification. While implementing: 1. Keep methods small and intention-revealing. 2. Prefer conventional C#. 3. Use async I/O. 4. Pass `CancellationToken` through external/database-heavy application paths where appropriate. 5. Add validation close to the boundary and invariants in the domain where appropriate. 6. Avoid duplicate normalization or authorization logic. After implementing: 1. Build the solution. 2. Run relevant tests. 3. Run the full test suite when practical. 4. Check migrations when data model changes. 5. Report files changed and any intentionally deferred work. Do not claim a feature works without running the relevant build/tests when the environment permits it. --- ## Exact Build Order Follow this progression: ### 0. Baseline - solution/projects - dependencies - PostgreSQL - Identity - test harness ### 1. Household - household entities - membership - authorization - create/select household ### 2. Grocery List - concepts/categories - list/list items - add/toggle/delete - mobile Razor view ### 3. Products and Scan - brand/product/identifiers - household product preferences - local product lookup - Open Food Facts provider - barcode scan page ### 4. Purchase and Price History - retailer/store - purchase/purchase item - price observations - price service and views ### 5. Shopping Mode - grouped mobile list - purchase/skip/unavailable - optional entered price - complete trip ### 6. Running Low - deterministic replenishment service - suggestions on Home/List ### 7. Polish - accessibility - mobile/responsive testing - performance - PWA/offline only when core workflows are stable Do not jump to Phase 6 features while Phase 2 is incomplete unless the user explicitly requests it. --- ## First End-to-End Slice When asked to begin implementation, build this before broad scaffolding: ```text Register/Login -> Create Household -> Open /list -> Add “Milk” -> Persist item -> Toggle Purchased -> Reload -> Verify correct household-scoped state ``` This proves authentication, household authorization, EF persistence, MVC routing, Razor rendering, and form/JS behavior. --- ## Out of Scope Unless Explicitly Added Do not implement proactively: - meal planning - recipes - AI chat - nutrition optimization - receipt OCR - coupon clipping - retailer loyalty accounts - delivery/checkout - live universal inventory - store aisle maps - indoor navigation - multi-store routing - shrinkflation analysis - push notifications Leave clean seams for future work; do not build speculative infrastructure. --- ## Definition of a Good CartWise Change A good change: - improves the shopper's grocery memory - keeps MVC server-rendered - works on a phone - does not require a retailer API unless specifically implementing one - preserves price source/freshness - maintains household isolation - adds tests for meaningful rules - avoids unnecessary framework or architecture expansion North star: > **CartWise remembers what the household needs, what it buys, and what it normally pays.**