Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

42KB

CartWise Scrum Backlog

Purpose

This document translates the product and implementation guidance from AGENTS.md into a Scrum-friendly backlog for CartWise v1. It organizes work into epics, user stories, and implementation tasks that align with the required phased delivery order.

This backlog is optimized for a solo founder + AI delivery model targeting a local MVP by September 10, 2026.

Product Vision

CartWise is a mobile-first grocery companion web app that helps households remember what to buy, what they bought, what they paid, and what they may need again soon.

Scrum Workflow

Solo Cadence

  • Planning cadence: weekly
  • Delivery rhythm: one active story at a time
  • Daily check-in: review top 3 priorities and blockers
  • Backlog refinement: once per week
  • Review/demo: every Friday
  • Retrospective: every 2 weeks

Working Model

  • Founder / Product Owner: prioritizes scope, clarifies acceptance criteria, reviews AI output, and decides trade-offs
  • AI Development Partner: scaffolds, implements, documents, and proposes follow-up tasks within approved scope
  • Primary QA: founder validates behavior locally before marking stories done

Board Columns

  • Backlog
  • Ready
  • In Sprint
  • In Progress
  • Code Review
  • Verify
  • Done

Estimation

  • Use XS, S, M, and L sizing on stories
  • Split any story larger than L before implementation
  • Track tasks as checklist items and keep them aligned with the repository state

Definitions

Definition of Ready

A story is ready when:

  • Business value is clear
  • Acceptance criteria are written
  • Dependencies are identified
  • UI, domain, and data impact are understood
  • Test approach is known
  • The story is small enough to deliver in a sprint

Definition of Done

A story is done when:

  • Code is implemented
  • Tests are added or updated
  • Build passes
  • Authorization and validation are enforced where applicable
  • Logging is added where useful
  • User-facing behavior is verified
  • Work remains aligned with AGENTS.md architecture and scope

Tracking Conventions

  • Use - [ ] for not started tasks
  • Use - [x] for completed tasks
  • Update story acceptance criteria or add a short status note when a story is fully delivered
  • Keep task state aligned with the actual repository state

Release Strategy

  • Release: MVP means required for the local launch target by September 10, 2026
  • Release: Post-MVP means explicitly deferred until after MVP is stable
  • Release: Deferred means do not implement unless scope changes
  • Priority: P0 means must ship for MVP
  • Priority: P1 means valuable next but can slip
  • Priority: P2 means later or exploratory
  • Effort: XS under 2 hours, S about half a day, M about a day, L 2 or more days
  • Decision Gate calls out places where the founder must make a product or architecture decision before implementation continues

Epic Roadmap

MVP Release

  1. CW-EPIC-01 Platform Foundation
  2. CW-EPIC-02 Household and Access Control
  3. CW-EPIC-03 Smart Shopping List
  4. CW-EPIC-05 Stores, Purchases, and Price Intelligence
  5. CW-EPIC-07 Running-Low Suggestions
  6. Selected hardening work from CW-EPIC-08

Post-MVP Release

  1. CW-EPIC-04 Product Catalog and Barcode Resolution
  2. CW-EPIC-06 Shopping Mode
  3. Remaining polish work from CW-EPIC-08

CW-EPIC-01 Platform Foundation

Goal: establish the solution structure, authentication, SQLite wiring for MVP, and baseline engineering standards.

CW-STORY-01.1 Create solution skeleton

Release: MVP
Priority: P0
Effort: S User story: As a developer, I want the CartWise solution scaffolded so the app follows a clean modular architecture.

Acceptance criteria

  • CartWise.sln exists
  • src/ and tests/ project layout matches the spec
  • Project references follow approved dependency direction
  • Nullable reference types are enabled

Tasks

  • Create CartWise.sln
  • Create src/CartWise.Web
  • Create src/CartWise.Application
  • Create src/CartWise.Domain
  • Create src/CartWise.Infrastructure
  • Create tests/CartWise.Domain.Tests
  • Create tests/CartWise.Application.Tests
  • Create tests/CartWise.Web.Tests
  • Add project references
  • Enable nullable reference types

Status: Done — solution builds and baseline template tests pass across all three test projects. CartWise.Web references CartWise.Infrastructure in addition to CartWise.Application for DI/startup registration (allowed per AGENTS.md §22 Phase 0).

CW-STORY-01.2 Configure application startup

Release: MVP
Priority: P0
Effort: M User story: As a developer, I want a runnable MVC shell so the team can build on a working baseline.

Acceptance criteria

  • ASP.NET Core MVC app starts locally
  • Shared layout and static assets load correctly
  • Environment-based configuration is wired
  • SQLite connection is configurable for MVP
  • PostgreSQL migration path remains possible later

Tasks

  • Configure MVC services and middleware
  • Add base layout and navigation shell
  • Organize wwwroot structure
  • Add configuration bindings
  • Wire SQLite connection string for MVP
  • Note PostgreSQL transition path in docs
  • Verify local app startup

Status: Done — app starts and serves the rebranded layout and static assets on a local port (verified via dotnet run + curl smoke check). CartWiseDbContext (empty for now — entities land in CW-EPIC-02) is wired to SQLite through CartWise.Infrastructure.InfrastructureServiceCollectionExtensions.AddInfrastructure, using ConnectionStrings:DefaultConnection in appsettings.json. PostgreSQL transition path documented in docs/decision-log.md under DEC-005.

CW-STORY-01.3 Add Identity authentication

Release: MVP
Priority: P0
Effort: M User story: As a user, I want to sign in so my household data is protected.

Acceptance criteria

  • Registration and sign-in are available
  • Authenticated routes can be protected
  • Identity persistence is configured

Tasks

  • Add ASP.NET Core Identity
  • Create ApplicationUser
  • Configure Identity persistence
  • Scaffold auth UI
  • Verify login and logout flow

Status: Done — ApplicationUser : IdentityUser (DisplayName, CreatedUtc) lives in CartWise.Infrastructure.Identity; CartWiseDbContext is now IdentityDbContext<ApplicationUser>. Identity is registered via AddInfrastructure (AddIdentity + AddEntityFrameworkStores<CartWiseDbContext>). Auth UI is a conventional MVC AccountController (Register/Login/Logout) with matching Razor views under Views/Account, anti-forgery on all POSTs, open-redirect guarded via Url.IsLocalUrl. HomeController.Privacy carries [Authorize] as the protected-route proof. Initial InitialIdentity EF Core migration created in CartWise.Infrastructure/Data/Migrations; the Development environment auto-applies pending migrations on startup (Program.cs) so local setup needs no manual dotnet ef database update step. Verified end-to-end via a live dotnet run + curl pass: anonymous access to a protected route redirects to /Account/Login?ReturnUrl=..., register auto-signs-in, logout clears the session, login re-authenticates, and a wrong password is rejected with a clear error.

CW-STORY-01.4 Establish engineering baseline

Release: MVP
Priority: P1
Effort: S User story: As a team, we want build and test standards so changes remain stable over time.

Acceptance criteria

  • Build can run consistently
  • Basic test execution is available
  • Logging defaults are configured

Tasks

  • Add analyzer and formatting settings
  • Configure structured logging baseline
  • Add smoke test coverage
  • Add CI-oriented build and test commands to docs

Status: Done — Directory.Build.props centralizes Nullable, ImplicitUsings, and .NET analyzers (EnableNETAnalyzers, AnalysisLevel=latest-recommended, EnforceCodeStyleInBuild) across all 7 projects; per-project .csproj files no longer duplicate those settings. Root .editorconfig added (generated via dotnet new editorconfig), with a scoped override so CA1707 doesn't fight the xUnit Method_Scenario_Expected naming convention under tests/. Logging defaults tuned in appsettings.json (quiet Microsoft.EntityFrameworkCore/Identity categories) and appsettings.Development.json (Microsoft.EntityFrameworkCore.Database.Command: Information to see generated SQL locally). Smoke coverage added where there's real behavior to smoke — a CartWiseWebApplicationFactory-based integration suite (tests/CartWise.Web.Tests/SmokeTests.cs) boots the full app (DI, EF Core/SQLite, Identity, routing) against an isolated temp SQLite file and asserts: home page loads, an anonymous request to an [Authorize] route redirects to /Account/Login, and both auth pages load. CartWise.Domain.Tests/CartWise.Application.Tests still carry only the template placeholder test — there's no real domain/application logic yet to smoke-test; meaningful coverage there starts with CW-STORY-02.1. CI-oriented commands documented in README.md (dotnet restore/build/test against CartWise.sln; analyzers enforced at build time, not a separate lint step).


CW-EPIC-02 Household and Access Control

Goal: enable household creation, membership, and household-scoped authorization.

CW-STORY-02.1 Model households and membership

Release: MVP
Priority: P0
Effort: S User story: As a developer, I want household entities persisted so household features have a secure foundation.

Acceptance criteria

  • Household and membership entities exist
  • Roles are defined
  • EF configurations and migration are created

Tasks

  • Create Household entity
  • Create HouseholdMember entity
  • Add role enum
  • Add EF configurations
  • Create migration
  • Add domain tests

Status: Done — Household and HouseholdMember live in CartWise.Domain.Entities, HouseholdRole (Owner/Member) in CartWise.Domain.Enums. Household is the aggregate root: its constructor auto-creates an Owner membership for the creator, AddMember rejects duplicate users, and HouseholdMember's constructor is internal so members can only be created through the aggregate — Domain stays free of any ASP.NET Core/Identity reference (CreatedByUserId/UserId are plain strings, not ApplicationUser navigations). HouseholdConfiguration/HouseholdMemberConfiguration in CartWise.Infrastructure/Data/Configurations establish the real FK to AspNetUsers (Restrict on Household.CreatedByUserId to protect household history from user-deletion cascades; Cascade on HouseholdMember rows), a composite PK on (HouseholdId, UserId), and an index on HouseholdMember.UserId for “which households does this user belong to” lookups. AddHousehold migration created and verified applying cleanly against a scratch SQLite database (and implicitly on every Web smoke test run, since those auto-migrate on boot). 11 domain tests added covering the invariants above.

CW-STORY-02.2 Implement household service

Release: MVP
Priority: P0
Effort: M User story: As a developer, I want household operations centralized so controllers stay thin and rules stay testable.

Acceptance criteria

  • Household creation is supported
  • Current household can be resolved
  • Membership checks are reusable

Tasks

  • Create IHouseholdService
  • Implement HouseholdService
  • Add create household use case
  • Add get current household use case
  • Add membership verification logic
  • Add application tests

Status: Done — IHouseholdService/HouseholdService live in CartWise.Application.{Interfaces,Services}, exposing CreateHouseholdAsync (returns Result<Household>), GetCurrentHouseholdAsync, and IsMemberAsync (the reusable membership check CW-STORY-02.4 will build authorization on top of). One household per user is enforced at this layer — see DEC-009. Data access goes through a new IApplicationDbContext abstraction (CartWise.Application.Interfaces, exposing just the DbSet<Household>/DbSet<HouseholdMember> needed) rather than a generic repository, since AGENTS.md explicitly rules out “generic repository abstractions added only for pattern compliance” — CartWiseDbContext implements it directly and is registered against the interface in AddInfrastructure. Time comes from the built-in TimeProvider (registered as TimeProvider.System) rather than a bespoke clock abstraction, keeping CreateHouseholdAsync deterministically testable without extra packages. AddApplication() (new CartWise.Application DI extension) is called from Program.cs alongside AddInfrastructure. 6 application tests added using EF Core's InMemory provider against the real CartWiseDbContext (via a new CartWise.Infrastructure reference in CartWise.Application.Tests, scoped to tests only — production CartWise.Application still has zero reference to CartWise.Infrastructure).

CW-STORY-02.3 Build household UI

Release: MVP
Priority: P0
Effort: S User story: As a user, I want to create and view my household so I can begin using CartWise.

Acceptance criteria

  • Household create page is available
  • Household overview page is available
  • Validation errors are shown clearly

Tasks

  • Create HouseholdController
  • Create household view models
  • Build Views/Household/Create.cshtml
  • Build Views/Household/Index.cshtml
  • Add validation messaging
  • Add redirect flow after creation

Status: Done — HouseholdController ([Authorize], attribute-routed to /household and /household/create per AGENTS.md §11) with HouseholdIndexViewModel/HouseholdMemberViewModel/CreateHouseholdViewModel in CartWise.Web.ViewModels.Household. Index resolves member display names via UserManager<ApplicationUser> in the controller (not the Application layer, to keep CartWise.Application free of Identity references) and redirects to Create when the signed-in user has no household yet; Create redirects back to Index if a household already exists (enforcing DEC-009's one-per-user rule at the UI layer too, on top of the service-layer guard). Added a “Household” nav link, visible only when authenticated. Only Create + Index were built — member invite/remove (/household/members/*) are explicitly out of scope per AGENTS.md, which marks invite [future/simple v1 if desired], and HouseholdService has no add/remove-member use case yet to back them. Verified live end-to-end via dotnet run + curl: anonymous-to-registered-to-household-created-to-overview-shown flow, member display name and Owner role render correctly, revisiting /household/create after a household exists redirects to /household, and an empty-name submission redisplays the form with visible validation errors (200, not a redirect).

CW-STORY-02.4 Enforce household authorization

Release: MVP
Priority: P0
Effort: S User story: As a user, I want household data isolated so other users cannot access it.

Acceptance criteria

  • Household membership is enforced on household-scoped resources
  • Unauthorized requests are blocked
  • Resource isolation is covered by tests

Tasks

  • Add household authorization policy or helper
  • Enforce membership checks in services
  • Add integration tests for access control
  • Add tests for unauthorized and cross-household access

Status: Done — added a reusable resource-based "HouseholdMember" authorization policy: HouseholdMemberRequirement + HouseholdMemberAuthorizationHandler (CartWise.Web.Authorization), backed by the IHouseholdService.IsMemberAsync check already built in CW-STORY-02.2, registered via AddAuthorizationBuilder() in Program.cs. Note on current scope: HouseholdController's existing actions (Index/Create) never accept a client-supplied household id — they always resolve “my household” from the authenticated user's own membership — so there's no IDOR surface to protect on them today; the new policy exists so the first household-scoped resource that does take an id (starting with CW-EPIC-03's shopping list) can apply [Authorize(Policy = "HouseholdMember")]/resource-based AuthorizeAsync immediately instead of hand-rolling the check. Verified with: a unit-style test exercising the policy through the real DI container (HouseholdAuthorizationTests — two real users/households, confirms the policy succeeds for the owning member and fails for a user from a different household), and Web integration tests (HouseholdAccessControlTests) proving an anonymous request to /household redirects to login, and that two independently-registered users each only ever see their own household's name on /household — never each other's.


CW-EPIC-03 Smart Shopping List

Goal: allow household members to maintain a shared grocery list, including unresolved free-text items.

CW-STORY-03.1 Model shopping list and grocery concepts

Release: MVP
Priority: P0
Effort: M User story: As a developer, I want shopping list entities defined so shared list workflows can be persisted.

Acceptance criteria

  • Grocery concept, category, shopping list, and shopping list item entities exist
  • Item statuses are defined
  • Optimistic concurrency is supported for list items

Tasks

  • Create GroceryConcept
  • Create ProductCategory
  • Create ShoppingList
  • Create ShoppingListItem
  • Add list status enums
  • Add row version concurrency token
  • Add EF configurations
  • Create migration

Status: Done — ProductCategory, GroceryConcept, ShoppingList (aggregate root with an Items backing-field navigation, mirroring Household/HouseholdMember), and ShoppingListItem added in CartWise.Domain.Entities; ShoppingListStatus (Active/Completed/Archived) and ShoppingListItemStatus (Needed/Purchased/Skipped/Unavailable/Substituted) in CartWise.Domain.Enums. Concurrency: ShoppingListItem.RowVersion is a Guid configured with .IsConcurrencyToken() rather than .IsRowVersion() — SQLite has no native auto-generated rowversion column, and IsConcurrencyToken() works identically on SQLite and a future PostgreSQL move (EF includes the original value in the WHERE clause either way); regenerating it on mutation is deferred to CW-STORY-03.4, which is where mutation methods land. Scope note: unlike Household.AddMember, no ShoppingList.AddItem(...) aggregate method exists yet — ShoppingListItem's constructor is public for now since 03.1 is pure modeling and CW-STORY-03.3 owns the add-item use case; that story should consider tightening ShoppingListItem's constructor to internal behind an aggregate method, matching the Household pattern. ShoppingListItem.PreferredProductId from the AGENTS.md §5.4 spec was intentionally omitted — Product doesn't exist until the post-MVP CW-EPIC-04, and MVP explicitly doesn't require product resolution; it will be added via a future migration once Product exists. AddShoppingList migration created and verified applying cleanly against a scratch SQLite database.

CW-STORY-03.2 Implement active shopping list service

Release: MVP
Priority: P0
Effort: S User story: As a user, I want my household to have an active grocery list so shared planning is easy.

Acceptance criteria

  • Active list can be retrieved
  • Default active list can be created
  • Household rule for default active list is enforced

Tasks

  • Create IShoppingListService
  • Implement get active list
  • Implement create list
  • Enforce one default active list rule
  • Add application tests

Status: Done — IShoppingListService/ShoppingListService in CartWise.Application.{Interfaces,Services}, following the exact pattern established by HouseholdService in CW-STORY-02.2: GetActiveListAsync (read, includes Items) and CreateListAsync (returns Result<ShoppingList>, rejects a second active list per the AGENTS.md §5.4 v1 rule with a clear error message). IApplicationDbContext extended with ShoppingLists/ShoppingListItems DbSets. Registered in AddApplication(). 6 application tests added (EF InMemory, same harness as HouseholdServiceTests), including a cross-household isolation check mirroring the pattern from CW-STORY-02.4. Also fixed a CA1861 warning surfaced by the AddShoppingList migration's composite-column indexes by scoping a suppression to Data/Migrations/** in .editorconfig — migrations are generated code and shouldn't be hand-edited to satisfy analyzers.

CW-STORY-03.3 Add grocery items quickly

Release: MVP
Priority: P0
Effort: S User story: As a household member, I want to add free-text grocery items quickly so I do not lose shopping intent.

Acceptance criteria

  • Free-text item entry is supported
  • Quantity and unit are optional
  • Item appears on the active list
  • Product resolution is not required to add an item

Tasks

  • Implement add item use case
  • Support DisplayName, quantity, and unit
  • Add validation rules
  • Add item partial view
  • Add controller POST action
  • Add tests

Status: Done — ShoppingList.AddItem(...) aggregate method added (mirrors Household.AddMember; ShoppingListItem's constructor is now internal), computing SortOrder and rejecting adds to a non-active list. IShoppingListService.AddItemAsync added. ShoppingListController (GET /list, POST /list/items) auto-provisions a household's first list (named “Groceries”) on first visit — no separate “create list” UI step, matching AGENTS.md's “one active list is enough for MVP” and the First End-to-End Slice in CLAUDE.md. Views/ShoppingList/Index.cshtml + _ListItem.cshtml built (functional, Bootstrap-styled; the dedicated mobile-first/touch-friendly pass is CW-STORY-03.5). Scope note carried from CW-STORY-03.1's status resolved: the constructor tightening happened here as anticipated.

Two real bugs found and fixed via testing, not just the earlier apostrophe-encoding test bug:

  1. EF Core state-tracking bug: adding a new ShoppingListItem purely by mutating the already-tracked parent ShoppingList's backing-field collection (list.AddItem(...)) left the new item's state ambiguous to EF Core's change tracker — since ShoppingListItemId is a client-generated Guid (not store-generated), EF couldn't reliably infer Added vs Modified, and attempted an UPDATE on a row that didn't exist yet, throwing DbUpdateConcurrencyException. Fixed by explicitly calling _db.ShoppingListItems.Add(item) in ShoppingListService.AddItemAsync after list.AddItem(...).
  2. Model-binding prefix mismatch: Views/ShoppingList/Index.cshtml's tag helpers generate field names like NewItem.DisplayName (based on ShoppingListViewModel.NewItem's property path), but ShoppingListController.AddItem bound a bare, unprefixed AddShoppingListItemViewModel model parameter — so nothing bound, DisplayName silently came through empty, and (surprisingly) no validation error surfaced either. Fixed with [Bind(Prefix = "NewItem")] on the action parameter.

Both were caught by genuine integration tests (ShoppingListAccessControlTests, real HTTP + real SQLite) written for this story, not by the weaker EF-InMemory application tests alone — worth remembering for future controller/view-model pairs that use a nested form-section pattern like this one. Extracted WebTestHelpers (register/create-household/extract-antiforgery-token) out of HouseholdAccessControlTests into a shared file so ShoppingListAccessControlTests didn't duplicate it. Verified live end-to-end via dotnet run + curl, matching CLAUDE.md's First End-to-End Slice exactly: register → create household → /list auto-creates “Groceries” → add “Milk” (2 gal) → reload shows it with Needed status; empty-name submission correctly redisplays the form with a visible validation error (200, not a redirect).

CW-STORY-03.4 Update shopping list items

Release: MVP
Priority: P0
Effort: M User story: As a household member, I want to toggle, skip, and delete items so the list stays accurate.

Acceptance criteria

  • Items can be marked purchased
  • Items can be skipped and unskipped
  • Items can be deleted
  • Concurrency conflicts are handled safely

Tasks

  • Implement toggle purchased
  • Implement skip and unskip
  • Implement delete item
  • Handle concurrency exceptions
  • Add progressive enhancement with jQuery
  • Preserve server-post fallback
  • Add tests

CW-STORY-03.5 Deliver a mobile-first list UI

Release: MVP
Priority: P0
Effort: S User story: As a shopper, I want a touch-friendly grocery list so it works well on my phone.

Acceptance criteria

  • List page is readable on mobile
  • Quick add is prominent
  • Tap targets are appropriate for shopping use

Tasks

  • Build Views/ShoppingList/Index.cshtml
  • Build Views/ShoppingList/_ListItem.cshtml
  • Add quick-add UI
  • Add touch-friendly styles
  • Add wwwroot/js/pages/shopping-list.js

CW-EPIC-04 Product Catalog and Barcode Resolution

Goal: support product identity, household product preferences, and local-first barcode resolution with provider fallback.

CW-STORY-04.1 Model product catalog entities

Release: Post-MVP
Priority: P1
Effort: M
Decision Gate: Confirm whether a product catalog is still needed before barcode work begins. User story: As a developer, I want product and identifier entities modeled so products can be resolved independently of UPC.

Acceptance criteria

  • Brand, product, identifier, and household preference entities exist
  • Identifier uniqueness rules are defined
  • EF configurations and migration are created

Tasks

  • Create Brand
  • Create Product
  • Create ProductIdentifier
  • Create HouseholdProductPreference
  • Add source type enums
  • Add indexes and normalized fields
  • Add EF configurations
  • Create migration

CW-STORY-04.2 Search and view products

Release: Post-MVP
Priority: P1
Effort: M User story: As a user, I want to search and view products so I can understand and choose preferred items.

Acceptance criteria

  • Local product search works
  • Product details page displays key product information
  • Household price insights can be shown later on the details page

Tasks

  • Create IProductService
  • Implement local catalog search
  • Create ProductController
  • Build Views/Product/Search.cshtml
  • Build Views/Product/Details.cshtml
  • Add product view models
  • Add tests

CW-STORY-04.3 Implement barcode lookup flow

Release: Deferred
Priority: P2
Effort: M
Decision Gate: Barcode scanning is out of MVP scope. User story: As a shopper, I want a barcode lookup flow so known products can be resolved quickly.

Acceptance criteria

  • Barcode input is normalized
  • Local identifier lookup runs first
  • Provider fallback runs when local lookup misses
  • Accepted results persist locally

Tasks

  • Define IProductDataProvider
  • Implement barcode normalization
  • Implement local-first lookup flow
  • Persist imported products and identifiers
  • Add unit and application tests

CW-STORY-04.4 Integrate Open Food Facts

Release: Deferred
Priority: P2
Effort: M
Decision Gate: External providers are out of MVP scope. User story: As a developer, I want a provider fallback for unknown products so barcode resolution remains useful.

Acceptance criteria

  • Open Food Facts provider can query by barcode
  • Provider models remain isolated to infrastructure
  • Provider errors are logged safely

Tasks

  • Implement OpenFoodFactsProductDataProvider
  • Map provider responses to internal DTOs
  • Add configuration and secrets support
  • Add error handling and logging
  • Add tests with mocked provider behavior

CW-STORY-04.5 Build scan page

Release: Deferred
Priority: P2
Effort: M
Decision Gate: Camera scan flow is out of MVP scope. User story: As a shopper, I want a camera-based scan page so I can identify products with my phone.

Acceptance criteria

  • Scan page requests camera permission
  • Barcode result can resolve product details
  • User can add scanned product to the list or record a price

Tasks

  • Create ScanController
  • Build Views/Scan/Index.cshtml
  • Add camera permission flow
  • Add barcode JS integration
  • Add add-to-list and record-price actions

CW-EPIC-05 Stores, Purchases, and Price Intelligence

Goal: record where purchases happened and build a trustworthy append-only price history.

CW-STORY-05.1 Model retailers and store locations

Release: MVP
Priority: P1
Effort: S
Decision Gate: Decide whether store tracking in MVP is minimal or omitted from first purchase flow. User story: As a developer, I want retailer and store entities so purchases can be tied to real locations.

Acceptance criteria

  • Retailer and store entities exist
  • Location fields support practical v1 store data
  • EF configurations and migration are created

Tasks

  • Create Retailer
  • Create StoreLocation
  • Add EF configurations
  • Create migration
  • Add tests for basic persistence rules

CW-STORY-05.2 Model purchases and purchase items

Release: MVP
Priority: P0
Effort: M User story: As a developer, I want purchase history modeled so shopping outcomes can be stored.

Acceptance criteria

  • Purchase and purchase item entities exist
  • Purchase source types are defined
  • EF configurations and migration are created

Tasks

  • Create Purchase
  • Create PurchaseItem
  • Add source type enum
  • Add EF configurations
  • Create migration
  • Add tests

CW-STORY-05.3 Model append-only price observations

Release: MVP
Priority: P0
Effort: S User story: As a developer, I want append-only price observations so historical price facts are preserved.

Acceptance criteria

  • Price observation entity exists
  • Useful indexes are defined for history queries
  • Older observations are not overwritten by newer ones

Tasks

  • Create PriceObservation
  • Add indexes for product, household, and store history
  • Add EF configuration
  • Create migration
  • Add tests for append-only behavior

CW-STORY-05.4 Record household purchases

Release: MVP
Priority: P0
Effort: M
Decision Gate: Decide whether MVP purchase entry must link directly to shopping list items or can begin as a manual flow. User story: As a shopper, I want to record purchases so CartWise can remember what I bought and what I paid.

Acceptance criteria

  • Purchase flow can start and complete
  • Purchase items can be added
  • Shopping list items can be linked when relevant

Tasks

  • Create IPurchaseService
  • Implement start purchase flow
  • Implement add purchase item flow
  • Implement complete purchase flow
  • Link purchase items to shopping list items where applicable
  • Add tests

CW-STORY-05.5 Derive price intelligence

Release: MVP
Priority: P0
Effort: M User story: As a user, I want price history and price insights so I can make better grocery decisions.

Acceptance criteria

  • Purchase items can create price observations
  • Latest, average, median, lowest, and unit price calculations are supported when data allows
  • Freshness and source can be displayed

Tasks

  • Create IPriceService
  • Derive observations from purchase items
  • Implement latest price calculation
  • Implement average and median calculations
  • Implement lowest recent price calculation
  • Implement unit price calculation
  • Add tests for price statistics

CW-STORY-05.6 Build price views

Release: MVP
Priority: P0
Effort: S User story: As a user, I want a price history screen so I can review what my household typically pays.

Acceptance criteria

  • Prices index page exists
  • Product-specific price history page exists
  • Product details can show historical price insight

Tasks

  • Create PriceController
  • Build Views/Price/Index.cshtml
  • Build Views/Price/Product.cshtml
  • Add price history to product details view
  • Add filtering and sorting UI
  • Add freshness and source display

CW-EPIC-06 Shopping Mode

Goal: provide a simple, touch-friendly in-store workflow for marking progress and recording purchases.

CW-STORY-06.1 Implement shopping mode service

Release: Post-MVP
Priority: P1
Effort: S
Decision Gate: Decide whether a dedicated shopping mode is needed beyond the list page. User story: As a developer, I want shopping-mode orchestration so in-store behavior is consistent and testable.

Acceptance criteria

  • Shopping mode view can be prepared from list data
  • Items can be grouped for easier shopping
  • Remaining and purchased counts are available

Tasks

  • Create IShoppingModeService
  • Implement shopping mode preparation
  • Group by category-based sections
  • Calculate remaining and purchased counts
  • Add tests

CW-STORY-06.2 Build shopping mode UI

Release: Post-MVP
Priority: P1
Effort: M User story: As a shopper, I want a low-noise mobile shopping view so I can use CartWise during a real trip.

Acceptance criteria

  • Shopping mode works well on a phone
  • Groups and counts are clear
  • Key actions are easy to reach

Tasks

  • Create ShoppingController
  • Build Views/Shopping/Start.cshtml
  • Build Views/Shopping/_ShoppingItem.cshtml
  • Add touch-friendly controls
  • Add wwwroot/js/pages/shopping-mode.js

CW-STORY-06.3 Support in-store item actions

Release: Post-MVP
Priority: P1
Effort: M User story: As a shopper, I want to mark items purchased, skipped, unavailable, or substituted so the trip stays accurate.

Acceptance criteria

  • Item transitions are supported
  • Anti-forgery is enforced on state changes
  • Actions update the shopping workflow correctly

Tasks

  • Add purchase action
  • Add skip action
  • Add unavailable action
  • Add substitute action
  • Add anti-forgery for AJAX and form posts
  • Add tests

CW-STORY-06.4 Record prices while shopping

Release: Post-MVP
Priority: P1
Effort: S User story: As a shopper, I want to optionally enter prices in shopping mode so price history stays current.

Acceptance criteria

  • Optional price entry is available during purchase actions
  • Money input is validated
  • Captured values feed purchase and price history logic

Tasks

  • Add optional per-item price input
  • Validate price and quantity inputs
  • Persist captured values through purchase service
  • Add tests

CW-EPIC-07 Running-Low Suggestions

Goal: use deterministic purchase history to suggest what a household may need soon.

CW-STORY-07.1 Build replenishment engine

Release: MVP
Priority: P0
Effort: M User story: As a developer, I want deterministic running-low logic so suggestions are explainable and testable.

Acceptance criteria

  • Last N purchase dates can be evaluated
  • Median interval is used when sufficient history exists
  • Minimum-history and tolerance rules are enforced

Tasks

  • Create IReplenishmentService
  • Gather recent purchase dates
  • Calculate purchase intervals
  • Implement median interval logic
  • Add minimum-history thresholds
  • Add tolerance window logic
  • Return score and reason data
  • Add tests

CW-STORY-07.2 Show suggestions on home and list views

Release: MVP
Priority: P0
Effort: S
Decision Gate: Confirm the minimum launch dashboard: active list count, recent prices, and running-low suggestions. User story: As a user, I want running-low suggestions surfaced in context so I can act on them quickly.

Acceptance criteria

  • Home page can display suggestions
  • Shopping list page can display suggestions
  • Suggestions include reason or confidence context

Tasks

  • Extend HomeViewModel
  • Add suggestions to home controller flow
  • Add running-low partial views
  • Render suggestions on list page
  • Add tests

CW-STORY-07.3 Add suggestion-to-list workflow

Release: MVP
Priority: P1
Effort: S User story: As a user, I want to add a running-low suggestion to my list so I can convert insight into action quickly.

Acceptance criteria

  • Suggestion can be added to the active list
  • Existing list workflows are reused
  • Duplicate accidental adds are reasonably controlled

Tasks

  • Add controller action to add suggestion
  • Reuse shopping list add-item workflow
  • Add duplicate-prevention rules if needed
  • Add tests

CW-EPIC-08 UX Polish, Security, and Release Readiness

Goal: harden the v1 experience for real-world use and release confidence.

CW-STORY-08.1 Improve mobile usability and accessibility

Release: MVP
Priority: P1
Effort: S User story: As a user, I want the app to be easy to use on my phone and accessible across core workflows.

Acceptance criteria

  • Key pages are responsive
  • Labels, focus states, and contrast meet baseline usability needs
  • Error handling is understandable

Tasks

  • Review responsive layouts
  • Improve form labels and focus states
  • Improve contrast and tap sizes
  • Validate keyboard navigation
  • Validate error summaries

CW-STORY-08.2 Harden security coverage

Release: MVP
Priority: P0
Effort: S User story: As a team, we want security-sensitive paths reviewed so household data remains protected.

Acceptance criteria

  • Anti-forgery coverage is verified
  • Authorization coverage is verified
  • Secrets handling is consistent with app rules

Tasks

  • Review anti-forgery coverage
  • Review authorization enforcement
  • Review validation across state-changing flows
  • Review secrets and configuration handling
  • Add integration tests for protected routes

CW-STORY-08.3 Add diagnostics and logging

Release: MVP
Priority: P1
Effort: S User story: As a team, we want actionable diagnostics so failures can be understood and fixed quickly.

Acceptance criteria

  • External provider failures are logged
  • Barcode misses can be diagnosed
  • Authorization failures are logged safely

Tasks

  • Add structured logging for provider failures
  • Log unresolved barcode outcomes
  • Log authorization failures safely
  • Add basic health-check strategy if included

CW-STORY-08.4 Seed realistic development data

Release: Post-MVP
Priority: P2
Effort: M User story: As a developer, I want realistic sample data so workflows can be tested quickly during development.

Acceptance criteria

  • Development-only seed data exists
  • Seed data covers household, products, stores, and price history
  • Production is not polluted with fake data

Tasks

  • Seed one household
  • Seed grocery concepts and categories
  • Seed brands and products
  • Seed product identifiers
  • Seed store locations
  • Seed purchase and price history
  • Restrict seeding to development only

CW-STORY-08.5 Harden HTML assertions in Web integration tests

Release: MVP
Priority: P2
Effort: XS
User story: As a developer, I want Web integration test assertions to be resilient to HTML encoding so tests don't produce false negatives on ordinary characters in test data.

Acceptance criteria

  • Web integration test assertions against rendered HTML compare against HTML-decoded content, not raw encoded output
  • Test data is not artificially restricted to avoid HTML-special characters (apostrophes, ampersands, quotes)

Tasks

  • Add an HTML-decoding assertion helper to CartWise.Web.Tests
  • Update HouseholdAccessControlTests to use realistic household names (including an apostrophe) via the new helper
  • Note the pattern so future integration tests use it by default

Status: Done — added HtmlAssert.Contains/DoesNotContain (tests/CartWise.Web.Tests/HtmlAssert.cs), which runs WebUtility.HtmlDecode before comparing. HouseholdAccessControlTests now uses "Alice's Household" / "Bob's Household" (real apostrophes) through the new helper and passes. Future Web integration tests asserting against rendered HTML should use HtmlAssert rather than raw Assert.Contains/DoesNotContain.

Origin: Discovered during CW-STORY-02.4 verification — EachUser_OnlySeesTheirOwnHousehold failed against "Alice's Household" because Razor correctly HTML-encodes ' as &#x27; in @Model.Name, but the test asserted a literal apostrophe. The immediate fix (switching to apostrophe-free test data) papered over the real issue: any test data with &, ', ", <, or > would hit the same false negative. This story is the real fix.


Suggested 30-Day Delivery Sequence

Week 1 - Foundation

  • CW-EPIC-01 Platform Foundation
  • Start CW-EPIC-02 Household and Access Control

Week 2 - Shared List

  • Finish CW-EPIC-02 Household and Access Control
  • Start and finish core stories in CW-EPIC-03 Smart Shopping List

Week 3 - Purchases and Price History

  • Deliver CW-EPIC-05 MVP stories

Week 4 - Running Low and Hardening

  • Deliver CW-EPIC-07 MVP stories
  • Deliver selected CW-EPIC-08 hardening stories
  • Run local MVP release checklist

After MVP

  • Resume CW-EPIC-04 Product Catalog and Barcode Resolution
  • Resume CW-EPIC-06 Shopping Mode
  • Complete remaining polish work in CW-EPIC-08

Story Template

Use this format for new backlog items:

### `CW-STORY-XX.X` Story Title
**User story:** As a `user type`, I want `capability` so that `benefit`.

**Acceptance criteria**
- Criterion 1
- Criterion 2

**Tasks**
- [ ] Task 1
- [ ] Task 2

Notes

  • Keep v1 scope tightly aligned to the grocery-memory goals
  • Avoid introducing speculative architecture or out-of-scope features
  • Reprioritize stories only when dependencies or product value clearly require it
  • Preserve the implementation order unless a small change is needed to unblock progress

Powered by TurnKey Linux.