# Corner Mart — Product Requirements (v1.0)

Corner Mart is a grocery delivery shop with admin-approved accounts. Customers register, wait for an admin to approve them, sign in, browse a catalogue with stock limits, fill a cart, pick a delivery slot and place orders that they can cancel until packed. Admins approve or reject registrations.

**Problem.** A delivery shop must only serve vetted customers, keep sessions and redirects predictable, and charge delivery and enforce minimums exactly as promised. Wrong rules cost money or lock out good customers.

## Users
- **Customer** — Sign in once, stay signed in, order groceries into a delivery slot and know the exact total.
- **Admin** — Approve or reject new registrations with a reason the applicant can read.
- **Applicant** — Know whether the registration is pending or rejected and why.

## Goals
- Only approved accounts can sign in or call the API.
- A signed-in session survives a reload and ends on logout.
- Minimum order, free-delivery and stock rules are applied exactly at their boundaries.
- Delivery slots never exceed their capacity.

## Sign in, session and redirect (AUT)

Approved customers sign in, are redirected to the page they asked for and stay signed in.

- **FR-AUT-01** (Must) Valid credentials show the browser alert "✅ Login successful"; accepting it opens the Shop with the customer name and a Logout button.
  - The Login page has Username and Password fields and the password is masked.
  - After accepting the alert the header reads "Hi, Asha" and shows Logout.
- **FR-AUT-02** (Must) The session survives a page reload.
  - After a reload the user is still on Shop, still "Hi, Asha" with Logout; the Login page is not shown.
- **FR-AUT-03** (Must) Invalid or empty credentials never show the success alert, and the error does not reveal which part was wrong.
  - Both fields empty: "Please enter username and password".
  - Wrong password or unknown username: the same "Invalid username or password"; still on Login.
- **FR-AUT-04** (Should) Opening a protected page while signed out redirects to Login with "Please log in to continue" and, after sign-in, returns to the requested page.
  - Opening My orders signed out goes to /mart/?next=%2Forders with "Please log in to continue".
  - After sign-in My orders is shown (not Shop) listing CM-2057 and CM-2041.
  - Opening the Cart signed out and signing in shows the Cart page.
- **FR-AUT-05** (Should) Logout ends the session; protected pages require sign-in again, including through the Back button and a reload.
  - Logout shows Login with "You have been logged out." and no Logout in the header.
  - Back does not show Shop; Login shows "Please log in to continue"; a reload stays on Login.

## Registration and approval (REG)

New accounts stay pending until an admin approves or rejects them.

- **FR-REG-01** (Must) A registration is accepted but stays pending, and a pending account cannot sign in.
  - Registering shows "Registration received" with the account "pending approval".
  - Signing in as a pending account shows "Your account is awaiting approval. You can sign in once an admin approves it." with no alert and stays on Login.
- **FR-REG-02** (Must) A rejected account cannot sign in and sees the rejection reason.
  - Sign-in shows "Your registration was rejected: Address is outside our delivery area".
- **FR-REG-03** (Should) Each invalid registration field shows its own message.
  - All empty: "Full name is required", "Username is required", "Password must be at least 4 characters", "Phone must look like 555-0123", "Delivery address is required".
  - An existing username shows "That username is taken".
  - Different confirmation shows "Passwords do not match".
  - Username "pr" shows "Username must be 3–20 letters, digits, dots or underscores".
- **FR-REG-04** (Must) An admin approves a pending registration and the user can then sign in.
  - The Account approvals page opens with "Pending (2)" listing Ravi Kumar and Lena Fischer.
  - Approve on Lena Fischer shows "Lena Fischer approved — they can sign in now." and "Pending (1)".
  - Lena then signs in with "✅ Login successful" and sees "Hi, Lena".
- **FR-REG-05** (Should) Rejecting requires a reason, and the reason reaches the applicant.
  - Confirm reject with an empty reason shows "Give a reason for the rejection"; Ravi stays pending.
  - Reason "Phone number not reachable" shows "Ravi Kumar rejected." and the All customers list shows "rejected" with that reason.
  - Ravi's sign-in shows "Your registration was rejected: Phone number not reachable".
- **FR-REG-06** (Could) Customers do not see the approvals page.
  - A customer has no "Approvals" link and /mart/admin redirects to Shop.

## Catalogue and stock (CAT)

The catalogue has categories, search, an in-stock filter and sorting with per-item limits.

- **FR-CAT-01** (Should) Quantities stop at the stock level or 10, whichever is lower, and out-of-stock items cannot be added.
  - Vine Tomatoes and Salted Butter say "Out of stock" with disabled Add buttons.
  - Avocados show "Only 3 left" and the quantity stops at 3 with + disabled.
  - Bananas (stock 40) stop at 10.
- **FR-CAT-02** (Should) Search, category tabs, the in-stock filter and sorting combine correctly.
  - The full catalogue reads "24 products"; "Dairy & Eggs" reads "5 products"; "In stock only" reads "4 products" without Salted Butter.
  - "Price: high to low" starts with Aged Cheddar ($6.25) and ends with Whole Milk ($2.89).
  - Search "oil" finds only Extra Virgin Olive Oil; "zzz" shows "0 products" and "No products match your filters."

## Cart, minimum and delivery fee (CRT)

The cart enforces a $10.00 minimum order and free delivery from $35.00.

- **FR-CRT-01** (Must) An order below $10.00 cannot be placed and the cart states the shortfall.
  - Gala Apples × 1 ($3.49) and Penne Pasta × 2 ($3.78): Subtotal (3 items) $7.27, Delivery $2.99, Total $10.26.
  - "Add $2.73 more to reach the $10.00 minimum order." and Place order is disabled.
  - Penne Pasta at 4 gives Subtotal $11.05, "Add $23.95 more for free delivery." and an enabled Place order.
- **FR-CRT-02** (Must) Delivery is free when the subtotal is $35.00 or more (inclusive); below that it costs $2.99.
  - A subtotal of exactly $35.00 (6 items) shows Delivery "Free" and Total $35.00.
  - Reducing to Subtotal $26.01 shows Delivery $2.99, Total $29.00 and "Add $8.99 more for free delivery."

## Checkout, slots and orders (ORD)

Orders are placed into delivery slots with limited capacity and can be cancelled until packed.

- **FR-ORD-01** (Must) Placing an order needs a delivery slot and a payment choice; the order appears in history and can be cancelled while not yet packed.
  - Basmati Rice × 2: Subtotal $15.98, Delivery $2.99, Total $18.97, address prefilled "48 Harbour Lane".
  - Place order with no choices shows "Choose a delivery slot".
  - After placing, My orders shows "Order CM-2064 placed…", status Placed, $18.97, above CM-2063 (Packed); the cart badge is 0.
  - CM-2063 (Packed) has no Cancel order button; "Cancel order" then "Yes, cancel it" on CM-2064 makes it Cancelled.
- **FR-ORD-02** (Should) Slot capacity decreases with every order, and a slot with no places left is Full and cannot be chosen.
  - "Today · 18:00–20:00" is Full and disabled; "Tomorrow · 12:00–14:00" has 1 left.
  - After one order in "Tomorrow · 12:00–14:00" it says Full and cannot be selected.
- **FR-ORD-03** (Should) Order history lists orders newest first with correct lines, delivery fee and total.
  - CM-2057 (Delivered, $37.15) is above CM-2041 (Delivered, $16.84).
  - CM-2057: Basmati Rice 2 × $7.99 = $15.98, Extra Virgin Olive Oil 1 × $11.99, Free-range Eggs 2 × $4.59 = $9.18; Delivery Free; Total $37.15.
  - CM-2041: Whole Milk, Sourdough Loaf, Bananas; Delivery $2.99; Total $16.84.

## Login API (API)

The API applies the same approval rules as the screen.

- **FR-API-01** (Must) The login API returns a token only for approved accounts, refuses pending accounts and requires a token for private resources.
  - Login for an approved account returns 200 with a token and user.status "approved".
  - GET /api/mart/me with the token returns 200 and the name "Asha Menon".
  - Login for a pending account returns 403 with code "pending".
  - GET /api/mart/cart without a token returns 401 "Please log in to continue".

## Non-functional requirements

- **NFR-01** (Must) Account approval, minimum order and delivery rules are enforced by the server, not only by the screen.
  - The API refuses a pending account exactly as the Login page does.

## Glossary and rules

- **Pending** — A registration waiting for an admin decision.
- **Slot** — A delivery window with a limited number of places.
- **Packed** — An order stage after which cancellation is no longer offered.

## Out of scope

- Real payments
- Sessions shared between browser tabs (each tab is its own store)
