This is an AI-powered Grocery Shopping assistant that turns an imprecise list of items like "milk, bread, eggs" into a Kroger cart full of groceries. It relies on the Kroger API to search each item, then uses an LLM to decide which specific UPC to add to the cart (again, using the Kroger API). Once an item is selected, we store the UPC in the database so we can avoid consulting the LLM for that item again.
Households have preferences for which items to buy, and what priorities they have for each item. For example, we prefer to buy free range eggs and poultry, but don't particularly care whether they are organic or not. These details are stored in a database, which should also be consulted to add context to the LLM's decisions.
The application now includes a complete OAuth2 flow for Kroger authentication:
Set these in your Val Town environment:
KROGER_CLIENT_ID
- Your Kroger API client IDKROGER_CLIENT_SECRET
- Your Kroger API client secretKROGER_REDIRECT_URI
- Your registered redirect URI (e.g.,https://your-val.web.val.run/auth/callback
)
- Login: User clicks "Connect with Kroger" → redirected to
/auth/login
- Authorization: App redirects to Kroger's OAuth endpoint with proper parameters
- Callback: Kroger redirects back to
/auth/callback
with authorization code - Token Exchange: App exchanges code for access/refresh tokens
- Profile Fetch: App gets user's Kroger profile ID
- Session: User is logged in with session cookie
- Secure Sessions: HTTP-only cookies with proper security settings
- Token Refresh: Automatic refresh of expired access tokens
- State Validation: CSRF protection using state parameter
- User Management: Create/update users based on Kroger profile ID
The database consists of the following tables:
id
- Unique user ID (primary key)krogerProfileId
- Kroger's unique user identifieraccessToken
- Current OAuth access tokenrefreshToken
- OAuth refresh tokentokenExpiresAt
- Token expiration timestamppreferredLocationId
- User's preferred Kroger store locationcreatedAt
/updatedAt
- Timestamps
id
- Unique guidance ID (primary key)userId
- Foreign key to kroger_users_1itemName
- Name of the item (e.g., "milk", "bread")guidance
- Textual preferences (e.g., "prefer free range eggs")createdAt
/updatedAt
- Timestamps
id
- Unique selection ID (primary key)userId
- Foreign key to kroger_users_1itemName
- User's free text item nameupc
- Selected product UPC codeproductName
- Full product name from KrogercreatedAt
/updatedAt
- Timestamps- Unique constraint on (userId, itemName)
GET /auth/login
- Start OAuth flowGET /auth/callback
- OAuth callback handlerPOST /auth/logout
- Logout userGET /api/user
- Get current user infoPUT /api/user/location
- Update preferred store location
GET /api/guidance
- Get all guidance for current userGET /api/guidance/search?q=item
- Search guidance by item namePOST /api/guidance
- Create new guidancePUT /api/guidance/:id
- Update guidanceDELETE /api/guidance/:id
- Delete guidance
GET /api/selections
- Get all selections for current userGET /api/selections/item/:itemName
- Get selection for specific itemPOST /api/selections
- Create/update selectionPUT /api/selections/:id
- Update selectionDELETE /api/selections/:id
- Delete selection
- The user supplies a list of items they want to buy.
- We search the Kroger API, getting a list of products that match the free text name.
- For each item, we:
- Try to find it in selections. If we can't find it there,
- Use full-text search to find the most relevant guidance. Then ask the LLM to decide which specific UPC to add to the cart. Store this in the selections table for next time.
- We use the Kroger API to add the item to the cart.
- Repeat for each item.
There is no need to check out the cart, as the user will review the cart in the app and make any necessary changes.
- The user can add new items to the guidance table.
- The user can CRUD their selections.
- The user can change their Kroger location ID.
- The user can log out.
- TypeScript
- Val.Town with SQLite integration
- Hono for the API
- TailwindCSS for styling
- Kroger API for product data and cart management
├── backend/
│ ├── index.ts # Main HTTP handler with OAuth routes
│ ├── database/
│ │ ├── migrations.ts # Database schema setup
│ │ └── krogerQueries.ts # Database query functions
│ └── services/
│ └── krogerAuth.ts # Kroger OAuth service
├── frontend/
│ └── index.html # Single-page application
├── shared/
│ └── types.ts # Shared TypeScript interfaces
└── docs/ # Kroger API documentation
See .cursorrules for more details.