|
|
@@ -0,0 +1,482 @@ |
|
|
|
|
|
# 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<ProductLookupResult?> FindByBarcodeAsync( |
|
|
|
|
|
string barcode, |
|
|
|
|
|
CancellationToken cancellationToken = default); |
|
|
|
|
|
|
|
|
|
|
|
Task<IReadOnlyList<ProductSearchResult>> 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.** |