RFD: Weekly Forecast — Implementation Analysis
RFD: Weekly Forecast — Implementation Analysis
Section titled “RFD: Weekly Forecast — Implementation Analysis”Status: Research
Author: Steve Hollinger
Date: 2026-04-07
PRD: Weekly Forecast PRD
Epic: PLT-536
1. Executive Summary
Section titled “1. Executive Summary”The Weekly Forecast is a personalized shopping list generated inside the AI Rewards Assistant that predicts what users will buy each week and surfaces the highest-value earning opportunities. This document scopes what it takes to build Phase 1 (MVP) using only existing components — offer-shelf, product-card, and text — with no new UI widget development.
Key finding: ~80% of the capability exists today. The forecast is delivered as a structured episode composed of text blocks + existing offer-shelf/product-card components. The main new work is (1) forecast generation logic in consumer-graph-worker and (2) an episode template that assembles the forecast from existing building blocks.
2. Existing Capability Map
Section titled “2. Existing Capability Map”2.1 Data Sources (all exist today)
Section titled “2.1 Data Sources (all exist today)”| Capability | Service | Status | Notes |
|---|---|---|---|
| Purchase history | Neo4j via consumer-graph-worker | Ready | PURCHASED relationships with timestamps, interval, likelihood |
| Repurchase predictions | consumer-graph-worker scheduler | Ready | Candidate scoring with probability, expected value |
| Product enrichment | consumer-context-service | Ready | FPS + FIDORA + Button (name, image, price, merchant) |
| Active offers | Offer Guardian via rover-mcp | Ready | Full offer catalog, eligibility via Neli |
| Fetch Shop availability | Button merchant service via CCS | Ready | IsButtonCommissioned, PPD points, merchant data |
| Offer search (semantic) | Offer Search ML via CCS/rover-mcp | Ready | Match products to offers |
| Location/retailer data | LIDAR via CCS/rover-mcp | Ready | Nearby retailers with distance |
| Category taxonomy | Category service (Python sidecar) | Ready | 2740 categories, UUID hierarchy |
| User profile/timezone | Profile service via consumer-graph-worker | Ready | Timezone for shopping day detection |
2.2 UI Components (all exist today, no new components)
Section titled “2.2 UI Components (all exist today, no new components)”| Component | How It’s Used in Forecast |
|---|---|
| offer-shelf | Groups of 3+ items that have active offers — renders as scrollable shelf with offer details |
| product-card | Individual high-value items (stacked tier) get their own card with full enrichment |
| text (episode body) | Section headers, points summary, tier explanations, call-to-action |
| prompt-suggestion | Landing page entry point: “See your weekly forecast” |
| Episode system | Forecast is a persistent episode with structured content |
2.3 Delivery Infrastructure (exists today)
Section titled “2.3 Delivery Infrastructure (exists today)”| Capability | Service | Status |
|---|---|---|
| Push notifications | notification-service | Ready |
| Episode creation | consumer-agent builder API | Ready |
| DM delivery | consumer-graph-worker | Ready |
| Feature flags | Feature Flipper | Ready |
3. Forecast Episode Structure (no new components)
Section titled “3. Forecast Episode Structure (no new components)”The forecast is delivered as a consumer-agent episode assembled from text + existing components:
Episode: "Your Weekly Forecast"│├── Text: "Here's your personalized shopping forecast for this week.│ You could earn up to 12,450 points."│├── Text: "Best Deals — Offer + Fetch Shop"├── offer-shelf: [offer_id_1, offer_id_2, offer_id_3] ← stacked tier items│ (renders existing offer shelf with images, points, "Offer + Shop" badge)│├── Text: "Active Offers"├── offer-shelf: [offer_id_4, offer_id_5, offer_id_6] ← offer-only tier items│ (renders existing offer shelf)│├── Text: "Available on Fetch Shop"├── product-card: {fido_id, title, price, ppd_points, merchant} ← shop-only item├── product-card: {fido_id, title, price, ppd_points, merchant} ← shop-only item│├── Text: "Tap any item to activate its offer or shop through Fetch."Why this works: The offer-shelf already renders offer images, point values, and activation CTAs. The product-card already renders product images, prices, and Shop links. Text provides the narrative structure. No new rendering code needed on iOS/Android.
4. Architecture: Build on What Exists
Section titled “4. Architecture: Build on What Exists”4.1 Forecast Generation
Section titled “4.1 Forecast Generation”Maps directly onto the existing repurchase candidate pipeline:
Neo4j (purchase graph) → get_repurchase_candidates query (already exists) → Filter: probability > 0.6 (configurable threshold) → Enrich via CCS (product metadata, offers, Shop availability) → Tier classification: Stacked = offer_active AND is_on_fetch_shop Offer = offer_active AND NOT is_on_fetch_shop Shop = NOT offer_active AND is_on_fetch_shop None = excluded from forecast → Sort by tier priority, then expected_value → Build episode from text + offer-shelf + product-card components → Persist forecast to DynamoDB + create episodeWhat already exists: The scheduler’s BatchEnrichCandidates + EvaluateEligibility pipeline does steps 1-3. The CCS enrichment already returns OfferActive, IsOnFetchShop, PPDPoints, OfferPoints.
4.2 Proposed Service Ownership
Section titled “4.2 Proposed Service Ownership”| Concern | Owner | Rationale |
|---|---|---|
| Forecast generation | consumer-graph-worker | Already has Neo4j access, enrichment pipeline, scheduler |
| Forecast persistence | DynamoDB (new table) | {env}-weekly-forecasts, keyed by user_id + week |
| Forecast delivery (push) | consumer-graph-worker scheduler | Extend existing notification pipeline |
| Forecast episode creation | consumer-agent | Existing episode builder with text + offer-shelf + product-card |
| Forecast retrieval | consumer-context-service | New REST endpoint for re-hydration |
4.3 Data Flow
Section titled “4.3 Data Flow”Weekly (per-user shopping day):
consumer-graph-worker ForecastHandler → Neo4j: get candidates for user (existing query) → CCS: batch enrich (existing) → Tier classify + rank (new, ~50 lines) → consumer-agent: create episode with: - text blocks (summary, section headers) - offer-shelf components (stacked + offer tiers, using real offer IDs) - product-card components (shop-only tier) → DynamoDB: persist forecast metadata (for refresh/analytics) → notification-service: push "Your weekly forecast is ready — earn up to X points"
On user tap:
iOS app deeplink → rover-agent → consumer-agent → GET episode (existing) → Renders text + offer-shelf + product-card (all existing components, zero new UI)5. Tier Classification Logic
Section titled “5. Tier Classification Logic”Using fields already available in the CCS enrichment response:
func classifyTier(e *ProductEnrichResponse) string { hasOffer := e.OfferActive onShop := e.IsOnFetchShop
switch { case hasOffer && onShop: return "stacked" // Best: offer + Shop points case hasOffer: return "offer" // Good: offer points anywhere case onShop: return "shop" // OK: Shop points only default: return "" // Excluded }}Points calculation (already in enrichment response):
- Stacked:
OfferPoints + PPDPoints - Offer only:
OfferPoints - Shop only:
PPDPoints
6. Shopping Day Detection
Section titled “6. Shopping Day Detection”New Neo4j query (lightweight, run once per user per month):
MATCH (u:User {userId: $userId})-[p:PURCHASED]->()WHERE p.lastPurchaseDate > datetime() - duration('P90D')WITH u, datetime(p.lastPurchaseDate).dayOfWeek AS dow, count(*) AS freqRETURN dow, freqORDER BY freq DESCLIMIT 1Generate forecast 2 days before the user’s peak shopping day. Cache in DynamoDB user profile.
7. Gap Analysis
Section titled “7. Gap Analysis”7.1 Must Build
Section titled “7.1 Must Build”| Gap | Effort | Details |
|---|---|---|
| ForecastHandler | ~3 days | New handler in consumer-graph-worker (like NotificationHandler). Reuses Neo4j queries + CCS enrichment. Builds episode from text + existing components. |
| Episode template builder | ~1 day | Assembles text blocks + offer-shelf + product-card into a forecast episode via consumer-agent builder API. |
| Shopping day detection | ~1 day | Neo4j query for peak day-of-week. Cache result. |
| DynamoDB forecast table | ~0.5 day | {env}-weekly-forecasts. PK=user_id, SK=week_start. Metadata for refresh/analytics. |
| CCS forecast endpoint | ~1 day | GET /v1/users/{user_id}/forecast — reads DynamoDB, returns forecast metadata. |
| Push notification template | ~0.5 day | ”Your weekly forecast is ready — earn up to X,XXX points this week” |
| Feature flag | Trivial | weekly_forecast_enabled in Feature Flipper |
| Testing + staging | ~2 days | End-to-end with sample users |
7.2 Reuse Directly (no changes)
Section titled “7.2 Reuse Directly (no changes)”- Neo4j purchase graph + repurchase candidate queries
- CCS product enrichment (FPS, FIDORA, Button, Offer Guardian, Neli)
- offer-shelf component (renders offer-tier items as-is)
- product-card component (renders shop-only items as-is)
- Episode system (persistence, history)
- Notification-service (push delivery)
- Profile service (timezone)
- Category resolver (display names)
- LLM short title generation (concise product names in text)
- DynamoDB infrastructure (already have short-title table pattern)
7.3 Total Effort
Section titled “7.3 Total Effort”| Days | |
|---|---|
| ForecastHandler | 3 |
| Episode template | 1 |
| Shopping day detection | 1 |
| DynamoDB + CCS endpoint | 1.5 |
| Push template + flag | 1 |
| Testing | 2 |
| Total Phase 1 MVP | ~9-10 days |
8. Example Forecast Push + Episode
Section titled “8. Example Forecast Push + Episode”Push notification:
Your weekly forecast is ready Earn up to 12,450 points on 8 items you’re likely to buy this week
Episode content (markdown text + existing components):
Since text supports markdown, the forecast episode uses formatted text for structure, emphasis, and readability — no new components needed for headers, tables, or summaries.
# Your Weekly Forecast**Week of April 7** · Based on your purchase history
You could earn up to **12,450 points** this week across 8 items.
| Tier | Items | Points ||------|-------|--------|| Offer + Shop | 3 | 5,200 || Active Offers | 4 | 4,750 || Fetch Shop | 2 | 2,500 |
---
## Best Deals — Offer + Shop ⭐*These items have an active offer AND are available on Fetch Shop for maximum points.*[offer-shelf: 3 stacked-tier items with real offer IDs]
## Active Offers*Buy these anywhere and scan your receipt to earn.*[offer-shelf: 4 offer-only items with real offer IDs]
## Available on Fetch Shop*No active offer, but you can earn points buying through Fetch Shop.*[product-card: Shop-only item 1] [product-card: Shop-only item 2]
---*Tap any item to activate its offer or add it to your Fetch Shop cart.*9. Open Questions
Section titled “9. Open Questions”- Forecast size: Suggest 8-15 items max. Offer-shelf needs min 3 per shelf.
- Cold start: Users with
<4receipts — skip forecast or use popular items + active offers? - Relationship to repurchase nudges: Should forecast supersede individual nudges? Or coexist? Recommend coexist initially — nudges are daily, forecast is weekly.
- Manual refresh: User says “refresh my forecast” in chat → consumer-agent re-runs forecast generation for that user via CCS? Or just re-query the persisted forecast?
- Offer expiration mid-week: Stale offers in the episode. Options: (a) ignore for MVP, (b) re-hydrate offer-shelf on episode open (rover-agent already does this for product-card enrichment).
10. Risk Assessment
Section titled “10. Risk Assessment”| Risk | Impact | Mitigation |
|---|---|---|
| Neo4j load from per-user forecast generation | Medium | Batch during off-peak (3 AM UTC). Same pattern as nudges. |
| CCS enrichment volume | Medium | Existing caches (FPS, FIDORA, Button). Batch enrich. |
| Offer-shelf with expired offers | Low | Offer-shelf already handles missing/expired offers gracefully. |
| Episode size (8-15 components) | Low | Existing episode rendering handles this. |
11. Recommendation
Section titled “11. Recommendation”Build Phase 1 as a new ForecastHandler in consumer-graph-worker, composing episodes from text + offer-shelf + product-card — all existing components. No new UI development required. The forecast is structurally just a richer version of the repurchase nudge episode, with multiple items grouped by earning tier instead of a single product.
Estimated timeline: ~9-10 days to first forecast delivered in staging.