| name | registry-checklist |
| description | Designs and maintains BabyPickr's Smart Registry Checklist: tier-based budget envelopes (minimum / comfortable / premium), cross-page product selection, consumable Amazon slots, budget tracking, curated auto-picks, and print/export. Use when editing the new-parent checklist blog, lib/registry/*, checklist UI, browse-page "Add to checklist" flows, or integrating new catalog products into registry slot eligibility. |
Smart Registry Checklist
BabyPickr's checklist is not a Babylist clone. It is a situation-aware, budget-bounded registry brain tied to our catalog, journey filters, and editorial tiers.
Canonical UX: standalone tool at /checklist (app/checklist/page.tsx, components/checklist/ChecklistToolLayout.tsx, ChecklistPageContent.tsx) + components/registry/RegistryChecklistShell.tsx. The blog article embeds the same shell with returnTo pointing at its #budget-checklists anchor. Slot copy and tier lists live in lib/blog/budgetChecklists.ts.
Return path default: REGISTRY_CHECKLIST_RETURN_PATH in lib/registry/browseLinks.ts → /checklist#budget-checklists. Browse "Add to checklist" flows return here unless a page passes a different returnTo.
Shareable tier links: On /checklist only, RegistryChecklistShell sets syncTierInUrl so ?tier=minimum|comfortable|premium tracks the active tab (same babypickr_registry_v1 state as the blog embed).
Journey banner: ChecklistPageContent reads babypickr_journey_done and shows SituationBar when present; otherwise a Gear Finder CTA card.
Nav: CategoryTopNav includes Checklist between Guides and the Gear Finder pill.
Read matrix.md for tier × slot × category mapping, Amazon links, and bucket ceilings. Read phases.md for implementation order. Read decisions.md for editorial rules that are easy to break when updating links or products.
Three modes (always)
| Mode ID | Label | Gear envelope | Total envelope (gear + consumables) |
|---|
minimum | Minimum viable | ~$540 | ~$700 |
comfortable | Comfortable | ~$1,318 | ~$1,500 |
premium | Premium | ~$3,430 | ~$3,685 |
Minimum tier label in budgetChecklists.ts: "~$540 to $700". Gear $540 + consumables $160 = $700 total.
Comfortable tier label: "~$1,318 to $1,500". Gear $1,318 + consumables $182 = $1,500 total.
Premium tier label: "~$3,430 to $3,685". Gear $3,430 + consumables $255 = $3,685 total.
Envelopes are editorial targets, recalibrated when catalog floor prices shift. Spent/remaining uses live catalog prices for selected products + fixed estimates for external consumables.
Mental model
/checklist (or blog embed)
→ pick tier (+ optional Gear Finder journey in localStorage)
→ preloaded slot list (template)
→ optional "Suggest picks for me" (auto-fill catalog products)
→ user browses category with deep-linked filters
→ "Add to checklist" on product card
→ checklist updates + budget bar moves
→ print / copy summary / (later) email
Two checklist layers:
- Template slots — editorial list (car seat, crib, diapers…). Always visible.
- Selections — optional catalog product or external Amazon link per slot. Drives budget math.
Parents never build the template from scratch. They fill slots and check off progress.
Slot types
| Type | Source | Budget |
|---|
catalog | data/*.ts product by id | product.price from catalog |
external | data/registryExternals.ts | priceEstimate (editorial) |
manual | Template only (sheets, onesies) | $0 or small estimate |
Catalog categories: strollers, car-seats, cribs, monitors, high-chairs, bottles.
External consumables (Amazon affiliate URLs in data/registryExternals.ts): diapers, wipes, cream, nursing pads, storage bags, formula starter, swaddles, onesies, changing mat, sheets, crib mattress.
Do not put feeding-path Amazon items (nursing pads, storage bags, formula) in the consumables bucket — see Feeding path below.
Feeding path (Breastfeeding | Formula | Combo)
Slots: min-feeding, comf-diapers-feeding, prem-bottles. UI: components/registry/FeedingPathPicker.tsx. Logic: lib/registry/feedingPath.ts.
| Path | Amazon items shown | Est. cost | Budget bucket |
|---|
| Breastfeeding | nursing pads + storage bags | ~$27 | bottles |
| Formula | formula starter | ~$35 | bottles |
| Combo | all three | ~$62 | bottles |
- State:
feedingPathByTier on RegistryStateV1 (lib/registry/types.ts), persisted in babypickr_registry_v1, cleared on tier reset.
- Catalog bottle picks also count toward bottles bucket when path is formula or combo (
feedingPathUsesBottles).
- Minimum bottles ceiling is $90 — combo + a bottle pick may slightly exceed; intentional nudge toward leaner picks (see matrix.md).
- Comfortable bundled row
comf-diapers-feeding includes diapers + wipes + cream (consumables) plus feeding-path items (bottles bucket).
When updating Amazon links for feeding items, edit data/registryExternals.ts and keep feedingPath: "breastfeeding" | "formula" on the item.
Crib mattress (conditional sub-row)
Catalog cribs are often frames only — mattress sold separately.
- Sub-row UI:
components/registry/SleepMattressSubRow.tsx
- Eligibility:
lib/registry/sleepMattress.ts — show when parent picks a convertible/nursery crib; skip for playards/bassinets with included sleep surface.
- Slot ids:
min-crib-mattress, comf-crib-mattress, prem-crib-mattress
- External id:
ext-crib-mattress (~$100, amzn.to/43D6Rph)
- Budget bucket: cribs, not consumables (
checklistExternals.ts + budgetAllocation.ts)
URL contract (browse deep links)
Every checklist → browse link MUST include:
| Param | Purpose |
|---|
registryTier | minimum | comfortable | premium |
registrySlot | Slot id, e.g. min-car-seat |
budget | Maps tier → catalog filter: budget / mid / premium |
sort | Category-specific value sort (see matrix) |
returnTo | Encoded path back to checklist anchor |
Tier → filter mapping (default):
| Tier | budget param | Sort bias |
|---|
| minimum | budget | value / lowest price |
| comfortable | mid | best-match |
| premium | premium | rating or best-match |
Examples:
- Minimum car seat:
/car-seats?budget=budget&priority=value®istryTier=minimum®istrySlot=min-car-seat&returnTo=...
- Comfortable stroller:
/?budget=mid&sortBy=best-match®istryTier=comfortable®istrySlot=comf-stroller&returnTo=...
- Premium crib:
/cribs?budget=premium®istryTier=premium®istrySlot=prem-crib&returnTo=...
Implement URL builder in lib/registry/browseLinks.ts — single source; blog and checklist UI import it.
Cross-page "Add to checklist"
When registrySlot is present on a browse page:
- Show ChecklistSessionBar (sticky): tier name, slot label, "Back to checklist".
- ProductCard shows Add to checklist (primary) beside Amazon / BabyPickr CTAs.
- On add: persist to
localStorage key babypickr_registry_v1, clear slot conflict if replacing.
- Toast: "Added [name] · $449 · $251 left in gear budget" + link to checklist.
Do not auto-add on Amazon click. Explicit opt-in only.
Budget UI
Show on checklist page:
- Total envelope vs spent vs remaining
- Gear vs consumables split
- Per-category bucket bars (car seat $160 of $160 ✓, stroller $0 of $350)
Single source of truth: computeSpentByBucket() in lib/registry/budgetAllocation.ts. Total spent = sum of all buckets (no drift between total and bucket bars). Used by budget bar, print export, and toasts.
If user exceeds bucket: soft warning + "Show cheaper options" deep link with value sort.
If user exceeds total: suggest downgrade tier or swap one premium pick.
Bucket defaults live in lib/registry/budgetEnvelopes.ts. See matrix.md.
Curated auto-picks ("Suggest my setup")
Yes — Phase 2 feature. After tier + short profile:
| Question | Affects |
|---|
| Apartment or house? | stroller, monitor, high chair filters |
| Compact car? | car seat vehicleFit |
| Breastfeeding, formula, or both? | bottle slot weight / skip |
| Due date urgency | timing sort only |
Algorithm (reuse journey — do not duplicate):
- Load slot list for tier.
- For each catalog slot, run category filter fn with tier budget + profile situations.
- Score with existing
*JourneyBoost fns where applicable.
- Pick rank #1 under bucket price ceiling.
- Write selections to registry state; user can swap any pick.
New products enter auto-picks automatically when registrySlotEligible(product, slot, tier) passes rules in lib/registry/slotEligibility.ts.
Print / export
Shipped: Branded print via components/registry/ChecklistPrintSheet.tsx (portaled to document.body) + lib/registry/formatExport.ts + print CSS in app/globals.css.
Print includes: BabyPickr logo (/logo.svg), green header band, tier title, budget table, all rows with ☐/☑, catalog picks, Amazon links + estimates, mattress sub-rows, feeding path label.
Print CSS requirements:
@media print: hide body > *:not(#registry-checklist-print) to avoid blank pages
print-color-adjust: exact on colored elements (browsers default to B&W without it)
- Footer tip: user must enable Color + Background graphics in print dialog
Phase 2 (not yet): "Copy checklist" → markdown/plain text (formatChecklistPlainText exists).
Phase 3 (optional): Email via subscribe API + checklist snapshot.
Skip PDF generation library until print proves insufficient.
File layout (target)
lib/registry/
types.ts # RegistryState, SlotId, Selection, feedingPathByTier
storage.ts # localStorage read/write/migrate; getDefaultRegistryState
budgetEnvelopes.ts # tier totals + category buckets
budgetAllocation.ts # computeSpentByBucket — single source of truth
feedingPath.ts # breastfeeding | formula | combo → Amazon ids + estimates
checklistExternals.ts # slot → external id map + bucket overrides
sleepMattress.ts # when mattress sub-row appears
browseLinks.ts # buildBrowseHref(slot, tier, profile)
slotEligibility.ts # product ↔ slot ↔ tier rules
suggestPicks.ts # auto-curation orchestrator (Phase 4)
formatExport.ts # print document + clipboard text
data/registryExternals.ts # consumables + Amazon affiliate URLs
components/registry/
RegistryChecklistShell.tsx
ChecklistPrintSheet.tsx
FeedingPathPicker.tsx
SleepMattressSubRow.tsx
ChecklistExternalLinks.tsx
ChecklistSessionBar.tsx
BudgetSummaryBar.tsx
SlotCard.tsx
AddToChecklistButton.tsx
app/checklist/page.tsx, layout.tsx
components/checklist/ChecklistToolLayout.tsx, ChecklistPageContent.tsx
lib/registry/*.test.ts
hooks/useRegistryState.ts # hydrate from localStorage after mount (no SSR mismatch)
Catalog integration (when adding products)
After any data/*.ts edit, ask: does this product fill a registry slot for any tier?
- Product must have valid
budgetTier and category.
- Run
slotEligibility rules (no manual per-SKU list unless exception).
- If new category or new flag (e.g.
isTravelFriendly), update rules + matrix.md + tests.
- Run
npm test -- lib/registry/*.test.ts.
Cross-skill: Update the matching journey skill (strollers, car-seats, …) with one line pointing here if the new flag affects slot eligibility.
Testing (required)
| When | Command |
|---|
| Registry logic | npm test -- lib/registry/*.test.ts |
| Browse link + storage | above + manual smoke on /checklist |
| Full suite before done | npm test |
Tests must cover: tier→URL mapping, bucket math, suggestPicks respects ceilings, storage round-trip, eligibility for new catalog fixture product.
External Amazon links (maintainer)
Single file: data/registryExternals.ts — id, label, priceEstimate, amazonHref, optional feedingPath.
Slot mapping: lib/registry/checklistExternals.ts — which externals attach to which checklist slot when checked.
When updating a link or price:
- Edit
data/registryExternals.ts
- If slot mapping changes, edit
checklistExternals.ts
- If bucket routing changes (mattress → cribs), edit
EXTERNAL_SLOT_BUCKET_OVERRIDE and budgetAllocation.ts
- Update matrix.md § External consumables table
- Run
npm test -- lib/registry/*.test.ts
Full link table: see matrix.md. Until a link is provided, show slot with checkbox only (no broken href).
Anti-patterns
- Do not hand-build browse URLs in blog copy; use
browseLinks.ts.
- Do not duplicate journey filter logic in suggestPicks; call
filterStrollers, filterCarSeats, etc.
- Do not store prices in localStorage without product id (always re-read price from catalog on load for catalog selections).
- Do not make checklist depend on account/login for v1.