GuyStore - Stage 1 Build Conversation

Complete record of the Stage 1 build session · Created 2026-04-28

Table of Contents

  1. User Requirements
  2. Build Plan
  3. Project Scaffold & Packages
  4. Models & Data Layer
  5. Authentication & Roles
  6. SignalR Notifications
  7. Themes (Corporate Blue & Dark Slate)
  8. Product Management
  9. Shopping Cart & PO Checkout
  10. Admin Area
  11. Final Result & Test Accounts
  12. Test Suite (Unit · Integration · E2E)
  13. Stage 2 Notes
👤
User · 2026-04-28

I need a workable ASP.NET Core MVC project with these features in stage 1:

  1. A publicly accessible and private area that requires login before access.
  2. In the private area, define different roles - administrators, registered, and account management. Every account has at least the Registered role. Administrators can access every page; account management can only access account-relevant features.
  3. Use SignalR to communicate with online users - like "system is going to close in 5 minutes." One-way in Stage 1.
  4. Account management: approve to activate, deny access, change password.
  5. The web app can be accessed by mobile devices - mobile friendly.
  6. Give the site a prettier visual look, and make it easy to switch between different visual schemes. Give two schemes at Stage 1.
  7. A feature to manage products in the admin area, and control whether they are published to the public or not.
  8. The front-end page will have a nice menu structure in both areas that new features can be easily added to.
  9. A shopping cart for logged-in users, using Purchase Order payment method. Also need order management in the admin area.
  10. This site will be growing - create all necessary memory/skills for this project so I can follow up without repeating requests.
  11. Dump all the conversation during the creation process in HTML format, revisable to maintain integrity when new stage requests come in.
🤖
Claude · Build Plan

Building the full project in 8 tracked tasks:

  1. ✓ Done Scaffold ASP.NET Core 9 MVC + Identity + EF Core (SQL Server) + SignalR
  2. ✓ Done Auth + Role-based access (Administrator, AccountManagement, Registered)
  3. ✓ Done SignalR one-way notification hub + JS client
  4. ✓ Done Account management (approve/deny/unlock/change password)
  5. ✓ Done Two switchable themes (Corporate Blue + Dark Slate) + Bootstrap 5 responsive
  6. ✓ Done Product management + publish/unpublish toggle
  7. ✓ Done Shopping cart (session) + PO checkout + admin order management
  8. ✓ Done CLAUDE.md, memory files, HTML conversation dump

Project Scaffold & Packages

🤖
Packages added
dotnet new mvc -n GuyStore --framework net9.0
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore --version 9.0.4
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 9.0.4
dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.4
dotnet add package Microsoft.AspNetCore.SignalR --version 1.1.0
dotnet add package Newtonsoft.Json --version 13.0.3
libman install @microsoft/signalr@latest  # JS client
# Set ConnectionStrings:DefaultConnection in appsettings.json to your SQL Server instance
dotnet ef migrations add InitialCreate
dotnet ef database update

Models & Data Layer

🤖
Files created
FilePurpose
Models/ApplicationUser.csExtends IdentityUser - adds FirstName, LastName, IsApproved, RegisteredAt, ApprovedAt, ApprovedBy
Models/Product.csName, Description, Price, StockQuantity, Category, IsPublished, CreatedBy
Models/Order.csOrderStatus enum + full Order model with PO fields
Models/OrderItem.csOrder line items (ProductId, ProductName snapshot, UnitPrice, Quantity)
Models/CartItem.csSession-only cart line item
Models/ViewModels/*Login, Register, ChangePassword, UserManagement, Product, Shop, Checkout, OrderSummary
Data/ApplicationDbContext.csIdentityDbContext<ApplicationUser> + Products, Orders, OrderItems DbSets
Data/DataSeeder.csSeeds 3 roles, 2 demo accounts, 8 products at startup

Authentication & Roles

🤖
Role design
RoleWhat they can do
AdministratorFull access to all admin pages (products, orders, accounts, notifications)
AccountManagementAdmin panel - accounts section only (approve/deny/unlock/change password)
RegisteredAssigned to every user. Required to have IsApproved=true to log in. Shop + cart access.

New user registrations create accounts with IsApproved = false. Login is blocked with a clear message until an AccountManagement user approves the account.


SignalR Notifications

🤖
Architecture

Server: Hubs/NotificationHub.cs - empty hub (no client→server calls in Stage 1). Admin broadcasts via IHubContext<NotificationHub> injected into NotificationsController.

Client: wwwroot/js/notifications.js - auto-connects with reconnect policy on every page (both public and admin layouts). Renders Bootstrap toast overlays in the bottom-right corner.

Admin UI: Admin → Send Notification page with message field, type selector (info/warning/danger/success), and pre-filled quick templates ("System closing in 5 minutes", etc.).

// How admin broadcasts:
await _hub.Clients.All.SendAsync("ReceiveNotification", new {
    message, type, timestamp
});

Themes

🤖
Two themes, cookie-persisted
ThemeFilePrimary ColorFeel
Corporate Bluethemes/corporate.css#1a56dbProfessional, light background
Dark Slatethemes/dark.css#6366f1Modern dark, indigo accents

Theme is stored in a cookie (SiteTheme) that lasts 1 year. Switch via the 🎨 palette dropdown in the navbar. Works on both the public site and the admin panel - both layouts read the same cookie.

Adding a third theme in Stage 2: create the CSS file, add the option to both layout dropdowns, and add the theme name to ThemeController.validThemes.


Product Management

🤖
Admin: CRUD + publish toggle | Public: published-only listing
FeatureLocation
Product list (all including drafts)Admin → Products → Index
Create / Edit productAdmin → Products → Create / Edit
Publish / Unpublish toggleOne-click button on product list row
Delete productWith confirmation dialog
Public product listingShop → Index (published only, search + category filter)
Product detail pageShop → Detail (add-to-cart if logged in)

8 products seeded at startup (7 published, 1 draft "Webcam 1080p").


Shopping Cart & Orders

🤖
Session-based cart + PO checkout + admin order management

Cart: CartService stores items in ASP.NET session as JSON. Quantity update and remove on cart page. Cart count badge shown in navbar.

Checkout: Only available to logged-in users. Requires PO Number, billing company/address, contact name/phone. 10% tax applied. Order placed as OrderStatus.Pending.

Order lifecycle: Pending → Confirmed → Processing → Shipped → Delivered (or Cancelled at any point).

Admin orders: List with status filter tabs. Detail view shows items, billing info, PO number, contact. Status can be updated with a dropdown + save.

My Orders: Logged-in users can view their own order history at Cart → My Orders.


Admin Area

🤖
Sidebar layout, role-gated sections

All admin controllers are in Areas/Admin/ with [Area("Admin")] attribute. The admin layout (_AdminLayout.cshtml) uses a fixed left sidebar on desktop that collapses to a button row on mobile.

Sidebar sections are conditionally rendered with @if (User.IsInRole("Administrator")). AccountManagement users only see the Users and Pending sections.


Final Result

✅ Stage 1 Complete - 2026-04-28

ItemValue
Project locationC:\Guy\Notes\Claud Projects\Guy\GuyStore\
Run commanddotnet run --launch-profile http
Admin account[email protected] / Admin@123
AccountMgr account[email protected] / Acct@123
Build result0 errors, 0 warnings
HTTP 200 verifiedYes - app starts and home page loads
Demo products8 seeded (7 published, 1 draft)
ThemesCorporate Blue, Dark Slate - switchable via navbar 🎨

Stage 2 Notes / Extension Points

🤖
What Stage 2 could include (to be specified by user)
  • Email notifications (account approval, order confirmations) - add SMTP/SendGrid config
  • Two-way SignalR (user-to-admin chat, support tickets)
  • Product images - local upload via IFormFile to wwwroot/uploads/
  • Stock deduction on order placement
  • Invoice PDF generation
  • More roles or fine-grained permissions
  • Pagination on product list and order list
  • User self-service password change
  • Additional themes / CSS variable customisation panel

See CLAUDE.md in the project root for the full extension guide.


🤖
Test Suite - Added after Stage 1 completion

Test Suite Overview

Three separate test projects cover the full application stack: pure logic unit tests, server-side HTTP integration tests, and real-browser E2E tests driven by Playwright. All 97 tests pass against an in-memory database - no SQL Server or external services required.

Project Type Tests What it covers
GuyStore.Tests.Unit Unit 33 CartService, CartItem model, ApplicationUser model, NotificationsController
GuyStore.Tests.Integration Integration (HTTP) 43 AccountController, ShopController, ThemeController, CartController, Admin: Products / Orders / Accounts
GuyStore.Tests.E2E E2E (Playwright) 21 Login/logout flows, shop browsing & search, full checkout, admin dashboard, theme switching

Solution Structure

GuyStore\                          ← main app
GuyStore.Tests.Unit\               ← xUnit + Moq
GuyStore.Tests.Integration\        ← xUnit + WebApplicationFactory
GuyStore.Tests.E2E\                ← xUnit + Microsoft.Playwright
GuyStore.sln                       ← all four projects

Step 1 - One-time Playwright browser install

Playwright needs a local Chromium binary. Run this once after the first build:

cd "C:\Guy\Notes\Claud Projects\Guy"
dotnet build GuyStore.Tests.E2E\GuyStore.Tests.E2E.csproj
pwsh GuyStore.Tests.E2E\bin\Debug\net9.0\playwright.ps1 install chromium

On Windows PowerShell (not pwsh) use powershell instead of pwsh. This step is only needed once per machine.

Step 2 - Run tests

From C:\Guy\Notes\Claud Projects\Guy:

# Run everything at once (all 97 tests)
dotnet test GuyStore.sln

# Run just one project
dotnet test GuyStore.Tests.Unit\GuyStore.Tests.Unit.csproj
dotnet test GuyStore.Tests.Integration\GuyStore.Tests.Integration.csproj
dotnet test GuyStore.Tests.E2E\GuyStore.Tests.E2E.csproj

# Run a single test by name (works for any project)
dotnet test GuyStore.Tests.Unit\GuyStore.Tests.Unit.csproj --filter "CartService_AddItem_SameProduct_IncrementsQuantity"
dotnet test GuyStore.Tests.Integration\GuyStore.Tests.Integration.csproj --filter "Login_WithValidCredentials_RedirectsToHome"
dotnet test GuyStore.Tests.E2E\GuyStore.Tests.E2E.csproj --filter "AdminLogin_SucceedsAndLandsOnHome"

Key Technical Decisions

InMemory database for all test types

Program.cs checks builder.Environment.IsEnvironment("Testing") and registers EF Core's InMemory provider when true - no SQL Server needed. Integration tests set this via WebApplicationFactory.UseEnvironment("Testing"); E2E tests pass it as WebApplicationOptions.EnvironmentName = "Testing". The DB name includes a Guid so each test run gets a fresh store.

Dynamic port for E2E

The PlaywrightFixture binds Kestrel to http://127.0.0.1:0 (port zero = OS chooses a free port), then reads the actual address back via IServerAddressesFeature. This avoids "port already in use" conflicts between test runs.

ApplicationName must match GuyStore

The E2E fixture creates a new WebApplication in the test process. Without ApplicationName = "GuyStore" in WebApplicationOptions, ASP.NET Core's MVC view engine uses the test assembly name and can't locate the precompiled Razor views from GuyStore.dll, causing every page to render a blank/error response.

Anti-forgery token helper (integration tests)

AuthHelper.GetAntiForgeryTokenAsync issues a GET to a login/form page, extracts the __RequestVerificationToken hidden field via regex, and adds it to every POST. Without this, all POST endpoints with [ValidateAntiForgeryToken] return 400.

Bootstrap dropdown buttons are hidden by default

The theme switcher and logout button live inside Bootstrap dropdown-menu elements (display: none). E2E tests avoid clicking them directly; instead they call form.submit() via page.EvaluateAsync and use page.RunAndWaitForNavigationAsync to properly wait for the resulting redirect before reading cookies.

Unit Test Coverage (33 tests)

  • CartServiceTests - GetCart, AddItem (new / same product / different products), UpdateQuantity (positive / zero / negative), RemoveItem, ClearCart, ItemCount, Total
  • CartItemTests - LineTotal = Quantity × Price
  • ApplicationUserTests - FullName concatenation, IsApproved defaults to false
  • NotificationsControllerTests - Index (GET), Send with valid message, Send with empty message, Send with valid type selection

Integration Test Coverage (43 tests)

  • AccountControllerTests - Login GET/POST (valid, wrong password, pending user), Register GET/POST, Profile redirect for unauthenticated users
  • ShopControllerTests - Index shows published products, search by name, category filter, product detail page, image endpoint, out-of-stock handling
  • ThemeControllerTests - Switch sets cookie for valid themes, rejects invalid theme, rejects external returnUrl
  • CartControllerTests - Add to cart, view cart, update quantity, remove item, checkout page, place order (POST), unauthenticated redirect
  • AdminProductsControllerTests - Create/Edit/Delete products, non-admin access denied
  • AdminOrdersControllerTests - Order list, order detail, status update
  • AdminAccountsControllerTests - Account list, approve/reject user, AccountManagement role access

E2E Test Coverage (21 tests)

  • LoginTests - Admin login succeeds, wrong password shows error, pending account shows message, logout redirects to home
  • ShopTests - Published products appear, unpublished hidden, search filters, category filter, detail page loads, all product cards present
  • CheckoutTests - Add to cart shows item, full checkout flow places order, unauthenticated cart redirects to login, My Orders page loads
  • AdminTests - Dashboard shows stats, Products shows all including drafts, send notification, AccountManagement can access accounts, AccountManagement cannot access Products
  • ThemeTests - Switch to dark sets cookie, switch to corporate sets cookie, theme cookie persists across page navigation