Wishlist Features and Flows
Developer Resources Wishlist Wishlist Features and Flows Complete feature list, actor journeys, state flows, business rules, edge cases, and diagrams for the Wishlist module.
Use this page for the wishlist domain: what it does for customers, and how each flow behaves from start to finish.
Source Type Files or Docs What Was Extracted API apps/api/src/modules/wishlist/customer/wishlist-customer.controller.tsRoutes, status codes, idempotency semantics Backend wishlist-customer.service.ts, wishlist-response.builder.tsON CONFLICT add, reason precedence, sort tiebreakers Schema packages/db/src/schema/wishlist/wishlist-item.tsUnique constraint, cascades, hard delete, 200 cap Cache @happy-shop/redis CACHE_TTL.VOLATILE30s membership cache Error registry apps/api/src/common/types/error-codes.ts (// WISHLIST)WISHLIST_* codes
Field Value Module wishlistSubmodule N/A Primary user value A customer keeps products they intend to buy, with live prices and stock, and gets told why a saved item is no longer buyable Actors Customer (signed in) Main entry points /api/mobile/wishlist (4 routes)Main outputs Wishlist list with reason per unavailable item, membership id-set, save/remove confirmations Related docs API , Backend
Actor Can Do Cannot Do Auth Requirement Notes Customer List their saved products (filtered/sorted/paginated), read their membership id-set, save a product, remove a product Save a product that is not currently published or unlisted (404 WISHLIST_PRODUCT_NOT_FOUND), exceed 200 saved items (409), see another customer's wishlist JWT CUSTOMER_READ 60/min, CUSTOMER_WRITE 20/min — account-keyedAdmin — — — No admin surface, no permissions
Capability Surface Actor Route/Trigger State Read State Written Linked API Section List wishlist Customer Customer GET /api/mobile/wishlistwishlist rows + live product data — API §4 Membership ids Customer Customer GET /api/mobile/wishlist/product-idswishlist rows — (30s cache) API Save product Customer Customer PUT /products/:productIdwishlist rows, product wishlist row API Remove product Customer Customer DELETE /products/:productId— wishlist row deleted API
A customer taps the heart on a product card. The call is idempotent — tapping twice, or a retry after a timeout, changes nothing and looks the same.
Branch Condition Behavior Error/Result Already saved Row exists No-op success, identical response 200 Concurrent taps Two parallel calls One row (unique constraint) 200 both Not saveable draft/archived/deleted/unknown product 404 — deliberately the same code as nonexistent WISHLIST_PRODUCT_NOT_FOUNDAt 200 cap Adding a genuinely new item 409 WISHLIST_LIMIT_REACHEDAt 200 cap, re-save Re-saving an item already held Succeeds — the call adds nothing 200
The page lists saved items, paginated by default. Every item resolves live product data — price, stock, media — at read time. Items whose product was withdrawn, archived or sold out stay in the list with a reason.
Branch Condition Behavior Error/Result Unavailable item withdrawn/archived/sold out Stays in list with reason status.reason setavailability=availableFilter applied Unavailable items hidden Filtered list availability=unavailableFilter applied Exactly the unavailable items Filtered list Empty wishlist No rows items: [], summary.totalItems: 0, lastUpdated: null200
DELETE always returns 200 — removing something never saved, or a product id that names nothing, is the outcome the caller asked for. The API never 404s on remove.
None. There is no admin surface and no permission — the wishlist is customer-only.
From Event/Action To Guard Condition Side Effects — save (PUT) saved Product currently published or unlisted; cap not reached Unique constraint is the idempotency guarantee saved remove (DELETE) gone (hard delete) None — never a 404 Row deleted; product-ids cache cleared saved product withdrawn/archived/deleted still saved None — the item staysstatus.reason explains why
reasonMeans availablenullBuyable now trueout_of_stockTemporarily unavailable — worth waiting for falsedraftWithdrawn by an admin; may return falsearchivedRetired; will not return falseremovedDeleted from the catalogue false
Precedence runs bottom-up: a product both archived and deleted reads removed, the more final fact and the one the customer can act on. Unlisted products count as available — reachable by direct link and buyable, following the products module's purchasableOf.
Flow DB Writes Cache Effects Jobs Realtime Analytics Notifications Save wishlist row product-ids cache cleared — — — — Remove row deleted product-ids cache cleared — — — — List — — — — — — Membership ids — product-ids read (30s) — — — —
Scenario Trigger User/System Experience Recovery Source Save of unsaveable product draft/archived/deleted/unknown 404 — same code for all Refresh the product anti-enumeration Cap reached 200 items held 409 Remove something first service Cache staleness Write in another tab Heart up to 30s stale Local optimistic state 30s TTL Product hard-deleted Catalogue removal Wishlist row cascade-deleted — FK cascade
Actor capability diagram — §3/§4.
Sequence diagram per major flow — §5.1/§5.2.
State machine diagram — §7.
Data side-effect diagram — §9.
Error branch diagram — §10.
Feature Minor Behavior Actor Trigger User/System Result Backend Side Effect Source Save Idempotent retry Customer Same tap twice No duplicate ON CONFLICT DO NOTHING service Save 200 not 201 Customer Create path Retry never looks like failure @HttpCode(OK)controller Save Cap re-save Customer Re-save at cap No-op success — service List Live data Customer Any read Today's price/stock assembler + inventory seam service List summary.totalItemsCustomer Page/filter Whole-list count, not page separate count service List lastUpdated nullCustomer Empty list null — List Unpaginated bound Customer pagination=false≤200 items cap Membership 30s cache Customer Heart grid One small payload CACHE_TTL.VOLATILEservice Remove Never 404 Customer Unknown product 200 anti-enumeration service Sort Tiebreaker Customer Low-cardinality sort No dup/omit pages buildWishlistOrderBybuilder
Rule Business Reason Actor Impact Enforced In API Impact Backend Impact Tests Unique (customer, product) = idempotency Duplicate taps safe Heart never double-saves DB unique constraint PUT 200 both paths ON CONFLICT DO NOTHING concurrency spec No soft delete Constraint stays simple Remove is final Schema DELETE never 404 hard delete probe Saveable only while visible Anti-enumeration 404 for hidden/unknown alike Service WISHLIST_PRODUCT_NOT_FOUNDsame code both cases spec Stays saved after withdrawal Customer learns why Reason shown Service status.reasonreason precedence spec Unlisted = available Follows purchasableOf Unlisted savable Service — — spec No new stock utility Reuse the seam Consistent availability Architecture — inventory seam reviewed Sort tiebreaker Stable paging No dup/omit Builder — buildWishlistOrderBypaging spec 200 cap approximate under concurrency Abuse bound Rare 201st item Service 409 accepted approximation spec
Product Decision User Benefit Engineering Benefit Alternative Tradeoff Risk Hard delete Re-add is one insert Unique constraint stays simple Soft delete No removal history Accepted Live data on read Always current price/stock No sync Snapshot on save Read cost Batched 30s membership cache Cheap hearts One cache key No cache Cross-device staleness Cleared on own writes Reason on unavailable Customer acts on truth Single source Hide items List shows non-buyable rows availability filter200-item cap Bounded reads Abuse bound No cap Rare legit overflow Approximate under concurrency
Flow Edge Case Trigger Expected Behavior User/System Feedback Source Save Concurrent duplicate Two parallel PUTs One row 200 both unique constraint Save Unknown product Bad id 404 PRODUCT_NOT_FOUND anti-enumeration Save Cap + re-save 200 held, re-save No-op success 200 service Remove Never saved Bad id 200 success deliberate List Product hard-deleted Cascade Item gone from list — FK List Archived product Saved earlier Stays with reason archivedservice Membership Stale cache Other device Up to 30s old heart lag TTL Sort Equal keys name sortTiebreaker orders stable pages builder
Flow Reads Writes Cache Jobs/Events Response Fields List wishlist rows, products, inventory — — — customer, summary, items Membership wishlist rows — product-ids (30s) — productIds, totalItems Save products, wishlist wishlist row clear product-ids — saved item Remove — row deleted clear product-ids — message