Cart Generator is a pnpm monorepo for turning saved recipes into recipe-based carts and derived shopping carts.
The backend is already well past the scaffold stage, and the web app is no longer just a thin dashboard. The current product already has:
- real auth with email/password and Google login
- required onboarding
- account/settings and security
- a planning home
- a dedicated recipe library
- draft/cart creation and editing through large overlays
- persisted
CartDraft,Cart, andShoppingCartresources behind the internal/api/v1contract
The Next.js web app in apps/web now splits product surfaces more explicitly:
/is the authenticated planning home for recent carts and drafts/recipesis the dedicated recipe library surface/shoppingis the dedicated saved shopping-cart library- recipe detail opens as a large overlay
Add to cartfrom recipe detail opens the cart builder preloaded with that recipe- draft creation, cart creation, draft detail, and cart detail all use large overlays instead of being the primary navigation path
- draft/cart detail overlays now support edit and delete flows
- cart detail can now generate a
ShoppingCartand open its retailer-facing detail overlay in place - shopping-cart detail now supports manual editing over the same persisted resource: replace matches, add manual items, delete lines, and save
- saved shopping carts can now be browsed from a dedicated
/shoppingsurface /account/settings/*holds account, preferences, and security- onboarding and account preferences now also persist a neutral
shopping_locationblock (manual first, GPS-ready later)
The NestJS API in apps/api currently supports:
- user and admin identities in the database
- real auth endpoints for email/password, Google login, refresh, logout, and
/me /api/v1/me/preferencesfor auth-backed cuisine and tag preferences/api/v1/me/preferencesalso carries a neutralshopping_locationprofile block/api/v1/me/onboarding/completefor explicit onboarding completion- a global controlled cuisine catalog exposed at
/api/v1/cuisines - hybrid tags with explicit
/api/v1/tagsendpoints - global system recipes and user-owned recipes
- recipe CRUD for user-owned recipes
- optional
cover_image_urlandnutrition_dataon recipes - explicit dietary badge tags through
Tag.kind = dietary_badge - an explicit fork flow for copying a system recipe into a user-owned editable recipe
- persisted
cart-drafts,carts, andshopping-carts - deterministic conversion from recipe selections into recipe-based carts
- persisted retailer context on drafts and carts
- derived aggregated ingredient overviews on cart reads
- deterministic ingredient aggregation and provider-backed retailer matching behind shopping-cart generation
- a mock retailer provider for local/dev fallback
- a Walmart provider boundary that can be enabled later with real credentials
- retailer product search and shopping-cart editing APIs behind the same shopping-cart boundary
- internal
/api/v1route families forrecipes,recipe-forks,cart-drafts,carts, andshopping-carts - internal
/api/v1/tagsfor visible system tags and user-owned tags - Swagger UI at
/docs - request tracing via
x-request-id
packages/shared contains the current TypeScript domain contracts for:
- recipes
- cuisines
- selection and cart models
- aggregation
- matching
- users
The API uses Prisma + PostgreSQL.
- Prisma schema: apps/api/prisma/schema.prisma
- Migrations: apps/api/prisma/migrations
- Seed data: apps/api/prisma/seed
- Local Docker stack: infra/docker/docker-compose.yml
The main architecture and design notes live in:
Those docs now describe the implemented v1 direction, the current web product state, and the next product/backend milestones.
cart-generator/
|-- apps/
| |-- api/
| `-- web/
|-- docs/
|-- infra/
| `-- docker/
|-- packages/
| `-- shared/
|-- package.json
|-- pnpm-lock.yaml
`-- pnpm-workspace.yaml
Install dependencies:
pnpm installRun both apps:
pnpm devRun one app:
pnpm dev:api
pnpm dev:webBuild the workspace:
pnpm buildRun workspace checks:
pnpm lint
pnpm test
pnpm typecheckRoot shortcuts:
pnpm api:setup
pnpm api:up
pnpm api:resetWhat they do:
-
pnpm api:setupPrepares the local backend without starting the server. Starts Postgres, generates Prisma client, applies existing migrations, and seeds local data. -
pnpm api:upStarts Postgres if needed and then runs the API in dev mode. -
pnpm api:resetDestructive. Resets the local API database, reapplies migrations, and reruns seed through Prisma.
Start PostgreSQL:
docker compose -f infra/docker/docker-compose.yml up -dApply migrations:
cd apps/api
pnpm prisma:migrate:devSeed the database:
pnpm db:seedStart the API:
pnpm start:devRecommended first-time local flow:
pnpm api:setup
pnpm api:upUseful API commands:
pnpm build
pnpm test --runInBand
pnpm test:e2e
pnpm test:e2e:ci
pnpm prisma:generate
pnpm prisma:studioSwagger:
- UI: http://localhost:3001/docs
- OpenAPI JSON: http://localhost:3001/docs/openapi.json
- system recipes are global and immutable
- user-created recipes are private by default
- unauthenticated recipe reads only see global system recipes
- authenticated users see global recipes plus their own recipes
- writes require authentication
/api/v1/meis the authenticated profile boundary- cuisines are now explicit global resources with
kind-based curation - recipe writes now use
cuisine_id, and recipe reads return bothcuisine_idand expandedcuisine - tags are now explicit resources with
systemanduserscope - tags now also carry
kind, so dietary badges likehalal,vegan, andgluten-freeare explicit curated system tags withkind = dietary_badge - recipe writes now use
tag_ids, and recipe reads return bothtag_idsand expandedtags - forking a system recipe creates a user-owned editable copy
- duplicate forks of the same source recipe are prevented per user
CartDraftis editable incomplete intent, not the main product objectCartis the stable recipe-based meal plan snapshot with retailer context and a derived ingredient overviewShoppingCartis the retailer-facing basket derived from aCart- aggregation and retailer matching remain deterministic
ShoppingCartcan now be manually corrected without regenerating a new planning artifact- dietary badges should come from tag metadata, not hardcoded booleans on recipes
nutrition_datais optional recipe detail metadata, not something every compact recipe card needs to show- generating a cart from an existing draft should consume that draft so recent work does not duplicate the same planning run
The clean internal v1 contract is now the implemented direction under /api/v1.
Resource families:
recipesrecipe-forkscart-draftscartsshopping-carts
Approved conceptual flow:
Recipe -> CartDraft -> Cart -> ShoppingCart
Interpretation:
CartDraftis editable user intentCartis the stable recipe-based meal plan snapshot with retailer context and derived ingredient overviewShoppingCartis the retailer-facing purchase basket derived from aCart
This separation is intentional:
Cartanswers "what do I want to cook?"ShoppingCartanswers "what do I need to buy?"- retailer matching and purchasable-product state still belong behind
ShoppingCart - real auth and future tags should be built on top of this API shape, not by reshaping it again
/api/v1is now the active internal API contract.- auth persistence now includes
AuthIdentityandRefreshToken. - cuisine persistence now includes a global
Cuisinecatalog. - tags persistence now includes
TagandRecipeTag. /api/v1/auth/register,/login,/google,/refresh,/logout,GET /me, andPATCH /meare implemented./api/v1/cuisinesnow exposes the global cuisine catalog./api/v1/me/preferencesnow supports read/replace for user cuisine and system-tag preferences./api/v1/me/preferencesnow also supportsshopping_location(zip_code,label,latitude,longitude) for future retailer store resolution./api/v1/me/onboarding/completenow marks onboarding completion independently from preferences./api/v1/tagsnow supports list/create/update/delete./api/v1/tagsnow returnskindso clients can distinguish general taxonomy tags from dietary badge tags.POST /api/v1/recipe-forksreplaced the old save-style route.- recipes now require
cuisine_idand return expandedcuisineobjects. - carts now require
retaileron write and return derivedoverviewingredient data on read. cart-drafts,carts, andshopping-cartsare separate resources in API, shared models, and database schema.- Prisma migration
20260319113000_split_cart_and_shopping_cart_v1materializes the newCart/ShoppingCartsplit. - Prisma migration
20260319124500_add_cuisine_catalogmaterializes the controlled cuisine catalog and recipe relation. - Prisma migration
20260321130500_add_cart_retailermaterializes retailer persistence onCart. - the web app dashboard in apps/web now reads the
/api/v1endpoints and reflects the new model vocabulary. - the web app now separates planning home from recipe browsing:
/focuses on planning state and recent work, while/recipesowns the recipe library. /recipesnow has recipe detail overlays with ingredients, steps, andnutrition_data- recipe detail now uses
Add to cartinstead of creating drafts immediately - the cart builder is now the central planning composer, and drafts are treated as secondary persistence for incomplete work
- draft/cart detail overlays now support edit flows by reopening the same composer with hydrated selections, retailer, and name
- draft/cart detail overlays now support delete flows
- generating a cart from an existing draft now deletes that draft after successful cart creation
- cart detail now supports
Generate shopping cart, which opens a retailer-facing shopping-cart detail overlay on top of the same workspace - shopping-cart detail now supports manual correction on the same persisted resource
/api/v1/retailers/:retailer/products/searchnow exposes provider-backed product search behind the shopping-cart editor- the matching module now supports
MockRetailerProductProviderandWalmartRetailerProductProvider, with Walmart disabled by default until credentials are present - new API envs:
WALMART_USE_REAL_PROVIDER=true|falseWALMART_CLIENT_IDWALMART_CLIENT_SECRETWALMART_ENV=sandbox|production
PATCH /api/v1/shopping-carts/:idnow persists manual shopping-cart edits
The next high-signal work is now more product-shaped than before.
- Add GPS-assisted shopping-location setup on top of the new manual
shopping_locationprofile block. - Decide the first real store resolver/provider path after Walmart friction, most likely Kroger or another easier self-serve retailer API.
- Expand the shopping-cart workspace further with quantity editing, repeat-generation strategy, and first-class history/revisit flows.
- Add a clearer draft -> cart conversion affordance inside draft detail, beyond the generic composer action.
- Expand recipe library actions with
Fork/Editand a stronger owner/system distinction in the UI. - Harden Google OAuth for production secret management and deploy configuration.
- recipe variants and AI-assisted adaptation are not implemented yet
- the real Walmart provider is implemented but still disabled until credentials are configured
- delete flows exist, but recovery/versioning does not
- drafts and carts can now be edited, but there is still no broader history/timeline model for planning runs
- shopping-cart history exists in API but is not yet wired into the main web flow as a first-class revisit surface
If you want the current truth of the system:
- Read docs/architecture.md for the layered system and the approved
CartvsShoppingCartsplit. - Read docs/decisions.md for the policy and API-shape decisions.
- Read docs/models.md for the conceptual model vocabulary.
- Read Swagger at
/docsfor the live implemented/api/v1contract.