Browse documentation

🧭 Start Here

Blackcap Overview ✨ Blackcap Feature Catalog Installation First Run

🚀 Deploy Blackcap

Platform Stacks and Raspberry Pi Hardware Raspberry Pi Deployment Raspberry Pi Client Services GCP Deployment Application Updates Environment Variables and Secrets Reverse Proxy and TLS Background Jobs and Schedules

🛠️ Administer Blackcap

Organizations Users, Permissions, and Authentication Configuration Workspace Backups and Restore Database Administration Regression Testing Performance and Job Status Audit, Access Activity, and Logging GeoIP and Access Location Data Retention and Purge Support Requests API Tester and Postman Instance Reporting

🍽️ Use Recipes

Recipes and the Recipe Library Recipe Import and Discovery Recipe Editing and Cache Artifacts Recipe Sharing Social Recipe Import AI Recipe Image Generation

📅 Plan Meals

Meal Planner

🛒 Use Shopping Lists

Shopping Lists and Shop a List External and Household Shopping 🧩 Chrome Extension Shop With

🧺 Manage Kitchen Inventory

🧺 Kitchen Inventory

🖥️ Use Displays

Displays and Connections Assigning and Scheduling Display Content Remote Pi Client E-Ink Rendering Menu Refresh and Rendering Noun Project Footer Images

🧑‍🍳 Cook with Let’s Cook

🧑‍🍳 Let’s Cook 🧑‍🍳 Let’s Cook Controls and Timers

🤖 Use and Administer AI

🤖 AI in Blackcap 🤖 AI Providers and Connections 🤖 AI Seeds and Usage

🧩 Use the Chrome Extension

🧩 Blackcap Chrome Extension 🧩 Chrome Extension Recipe Capture 🧩 Chrome Extension Shop With 🧩 Chrome Extension Release and Privacy

🎮 Play Games

🎮 Games and Trivia

🔌 Integrations

Email Integration Cloud Storage Integrations Voice Assistants Shop With Integrations Authentication Providers

⚙️ Develop Blackcap

Application Architecture Database Service and Data Access SQLite and PostgreSQL Database Migrations Background Job Architecture Testing API Architecture Security and Organization Scoping UI, Icons, and Documentation Assets Blackcap-Safe Emoji Documentation Standards Terminology

⚠️ Troubleshoot Blackcap

⚠️ Troubleshooting Deployment Troubleshooting Display Troubleshooting Recipe Import Troubleshooting 🤖 AI Troubleshooting Backup Troubleshooting Database Troubleshooting Diagnostic Organization Clones Support Requests

Shopping Lists and Shop a List

Audience: User, Org Admin, Developer, Support Related: Meal Planner · Kitchen Inventory · Household and External Shopping · Data Retention

Shopping Lists can be created from recipes, selected meal-plan scope, or manual items. Ingredient scaling, normalization, source provenance, recipe multipliers, departments, inventory filtering, ownership, and list lifecycle are preserved through editing and Shop a List.

Shop a List provides recipe, department, and flat grouping, quick manual additions, undo behavior, and completion handling. Completed lists are retained or purged according to the configured policy.

This document captures the stabilized shopping-list architecture and UI split after the Shop a List, Edit Shopping List, Kitchen Inventory, and department-management improvements.

Workflow split

Blackcap Pi intentionally separates shopping-list work into three surfaces.

Surface Purpose Primary users
Shopping Lists Manage saved lists, active/completed state, print, reopen, and entry points. Admin users.
Edit Shopping List Compose/repair a list: recipes, multipliers, manual additions, preview, save, rebuild. Admin users.
Shop a List Execute the list while shopping: checkoff, inventory filter, add item, department reassignment, complete. Admin and Mobile users.

The Mobile execution page should be called Shop a List, not simply Shopping.

Shopping-list lifecycle

  • Lists can be created from the Recipe Cart or manually.
  • Recipe-created lists receive consumer-friendly smart names based on list date and recipes.
  • Empty manual lists require a user-provided name.
  • One list can be active at a time for an organization.
  • Completed lists are excluded from Shop a List and Edit Shopping List selectors.
  • Completing an active list clears the active-list state.
  • Completed lists can be reopened from Shopping Lists.
  • Completed lists cannot be made active until reopened.

Meal Planner as a shopping-list source

Meal Planner is another composition source for Shopping Lists. It does not create a parallel shopping system.

When a shopping list is created from Meal Planner:

  • recipe-backed meal entries contribute ingredients using the meal-plan recipe multiplier;
  • manual meal items contribute ingredient-style candidates when marked for shopping inclusion;
  • uncanonicalized manual meal items remain reviewable just like unresolved recipe ingredients;
  • the resulting list is still edited in Edit Shopping List and executed in Shop a List;
  • Kitchen Inventory / On Hand behavior remains in the shopping-list execution layer.

If no specific days/slots are selected in Meal Planner, Create Shopping List defaults to the current configured/working week rather than a whole month view.

Smart list names

Smart names should be friendly for household users rather than developer-style timestamps.

Preferred format:

May 22, 2026 · Cheeseburger Pie +1 Recipe

If the same date/recipe/count combination already exists, append a suffix:

May 22, 2026 · Cheeseburger Pie +1 Recipe -1

Custom/manual names should be preserved. Generic placeholders such as Shopping List should not be used for newly created blank lists.

Edit Shopping List rules

Edit Shopping List is a composition page.

Supported actions:

  • select an editable non-completed list;
  • adjust recipe multipliers using fraction controls;
  • remove recipes from the list;
  • add/remove manual shopping items;
  • save changes;
  • rebuild recipe-derived rows when permitted;
  • print or cancel back to the previous page.

Important boundaries:

  • Recipe-derived ingredient rows are preview-only here.
  • Checkoff happens in Shop a List.
  • Manual-verification or recipe-derived loose rows should not appear as removable manual items.
  • Save should rebuild recipe-derived quantities from the current recipe multipliers.
  • Manual additions should be preserved across save/rebuild.
  • Unsaved-change warnings should appear before switching lists or leaving the page.
  • Completed lists should be reopened from Shopping Lists before editing.

Data Admin, Org Admin, and System Admin users can use Rebuild. The Rebuild action is intentionally role-restricted because it rewrites generated list rows from source recipes/multipliers/manual items.

Shop a List rules

Shop a List is the execution page.

Supported actions:

  • check/uncheck items;
  • filter All items / On hand / Need to shop;
  • group by Recipe, Department, or None;
  • add a manual item without leaving the page;
  • remove manual items with undo;
  • change department assignments;
  • complete the list.

Completing a list marks only checked items as on hand in Kitchen Inventory. Unchecked items are skipped.

When grouped by Recipe or Department, Admin and Mobile Shop a List render each group as a collapsible section. Group headers use real buttons with aria-expanded, show shopped/total counts, and preserve item state when collapsed. Admin shows one intelligent control that says Collapse All when at least one group is expanded and Expand All only when every group is collapsed. Mobile adds a sticky horizontal group strip for Recipe/Department grouping; tapping a chip expands that group if needed, marks the chip active, and scrolls to the group header. The chip/header counts use the intuitive shopped/total direction, such as 3/7 shopped.

Rapid checkoff persistence

Rapid Shop a List checkoffs use an optimistic, single-flight queue. The browser keeps the latest desired checked state per item and coalesces additional taps while a save is already in flight. Checkoff targets are stable shopping-list item_id values, not the visible row index; section/index are retained only as a legacy fallback. This matters because checked rows can move after sorting, grouping, household-list inclusion, or duplicate consolidation.

The server applies the payload with the shopping-list DB service atomic mutation helper, resolves refs by item_id first, reloads the affected refs, verifies that the requested state persisted, and retries once before returning an error. If a coalesced save still fails, the browser retries still-current rows individually and only reverts rows that actually fail.

This pattern avoids launching many overlapping full-list writes, and it avoids targeting the wrong row after normalization/sorting. The route and browser code stay database-backend neutral; SQLite and PostgreSQL locking differences belong behind the DB service boundary.

Shop With extension behavior

The Chrome extension Shop With helper uses the same organization-scoped shopping-list state as Admin/Mobile Shop a List. It can run an assisted session for enabled providers such as Shipt, Target/Walmart-style providers, and Amazon.

Session rules:

  • provider and store selection are scoped to the extension token owner’s organization;
  • providers can expose store modes or a free-form store text field;
  • Shipt supports free-form store text with common-store suggestions, and a blank store falls back to the provider default such as stores;
  • the selected provider/store stays with the active Shop With session until the session is completed, reset, or changed by the user;
  • shopping credentials are not stored by Blackcap; assisted shopping relies on the user’s active browser session with the retailer.

Execution rows are consolidated before they are sent to the extension. Duplicate shopping-list rows with the same normalized shopping/search text are grouped into one assisted item where safe. Matching quantities with the same unit are summed; mixed or uncertain duplicates stay grouped with a count label rather than risking a wrong quantity. The consolidated row keeps source references to all backing shopping-list item rows, so Got It, Already Have It, Review uncheck, and Reshop update every backing row consistently.

Completion behavior is intentionally different from Return behavior. Complete finishes the session, clears the extension shopping state, and closes the side shopping panel without navigating back to Blackcap. Return is the explicit action that brings the user back to Blackcap’s Shop a List page.

Department assignment behavior

Department reassignment should improve both the current list and future lists.

  • Admin: dragging a shopping row into a grocery department changes the visible group and updates the canonical department mapping.
  • Mobile: long-pressing an ingredient opens a department modal. The user can select a department, add a new department, save, or cancel.
  • Department resolution uses item override first, then organization canonical mapping, then platform/default mapping, then Other / Uncategorized.

Undo behavior

Manual item deletion should not require confirmation.

Instead, supported pages show an undo toast:

  • Admin Edit Shopping List.
  • Admin Shop a List.
  • Mobile Shop a List.

This keeps shopping fast while still protecting against accidental taps/clicks.

Persistence boundary

Shopping-list headers are handled by the shopping-list DB service/repository flow. Shopping-list item rows and item-source rows are written together through:

inky_admin/repositories/shopping_list_item_write_repository.py

That repository helper is responsible for:

  • resolving the effective organization id from the sync context or parent shopping list;
  • writing shopping_list_items.organization_id;
  • writing shopping_list_item_sources.organization_id;
  • deleting and replacing item/source rows in one place;
  • dropping stale source_recipe_ingredient_id values that no longer exist, avoiding foreign-key failures during legacy payload rewrites.

Routes and templates should not write directly to shopping_list_items or shopping_list_item_sources.

Admin UI layout expectations

Advanced shopping pages use the newer split-scroll pattern:

  • top/header panels can scroll fully up and out of view;
  • primary content panels fill the visible viewport after the headers clear;
  • internal panel scrollbars stay fully visible, including the bottom/down arrow;
  • panel scroll reaches the top/bottom and hands off smoothly to the page scroll;
  • avoid large blank bottom whitespace by dynamically adjusting scroll range;
  • treat top: 0 as valid, not as a missing value.

This pattern applies to Shop a List, Edit Shopping List, Database Admin-style pages, and similar dual-panel admin workflows.

Smoke coverage

tests/test_shopping_list_item_write_repository.py recreates the failure shape that appeared on the Pi:

  • org-scoped shopping_list_items.organization_id NOT NULL;
  • org-scoped shopping_list_item_sources.organization_id NOT NULL;
  • foreign keys enabled;
  • source attribution payloads that do not carry organization id;
  • stale recipe ingredient references that should not be written.

Run the targeted smoke test with:

python3 -m unittest tests/test_shopping_list_item_write_repository.py

More information

On this page