feat(#36): Investor-Friendly UI with Sparklines, Backers, and Momentum Metrics#39
Conversation
…m metrics Backend: - Add GET /campaigns/:pid/history endpoint (14-day default, 30-day max) - Returns campaign snapshots for trend visualization iOS: - Add backers_count display with person icon - Show 24h dollar changes ($50K) instead of just percentages - Add state badges (Funded ✓, Failed, Canceled) - Expand detail stats to 4 columns (Goal, Pledged, Backers, Days) - Add expandable project blurb (collapses at 150 chars) - Add momentum section with sparkline chart and metrics - Create SparklineView with green/red gradient trends - Implement 5-min history cache in APIClient Visual design: Color-coded badges, SF Symbol icons, glanceable metrics for investors. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Jing-yilin
left a comment
There was a problem hiding this comment.
Codex Review
[High] CampaignDTO's new backers_count field breaks the watchlist build path
Adding backers_count to CampaignDTO changed the memberwise initializer, but WatchlistView.toCampaignDTO(_:) still calls the old signature. A clean simulator build now fails with missing argument for parameter 'backers_count' in call, so this PR is not buildable as-is.
Refs: ios/KickWatch/Sources/Views/WatchlistView.swift:48, ios/KickWatch/Sources/Services/APIClient.swift:3
[Medium] The detail view now renders a momentum section even when there is no momentum data
CampaignDetailView gates the new section with if let velocity, let delta, but the API payloads for discover/search results come from model.Campaign, where velocity_24h and pledge_delta_24h are concrete float64 fields that serialize as 0, not null. In practice that makes campaigns with no computed history show a red 24h Change $0 / Growth Rate 0.0% panel, which is misleading and contradicts the PR's stated behavior that the section only appears when momentum data exists.
Refs: ios/KickWatch/Sources/Views/CampaignDetailView.swift:65, backend/internal/model/model.go:27
[Medium] GET /campaigns/:pid/history accepts invalid days values and turns them into empty history windows
strconv.Atoi errors are ignored here, so ?days=abc becomes 0, and negative values move the cutoff into the future. Both cases silently return an empty history array instead of falling back to the documented 14-day default or rejecting the request.
Refs: backend/internal/handler/campaigns.go:143
Verification
cd backend && go test ./...✅cd ios && xcodegen generate✅cd ios && xcodebuild -project KickWatch.xcodeproj -scheme KickWatch -destination 'platform=iOS Simulator,name=iPhone 17' CODE_SIGNING_ALLOWED=NO build❌ (WatchlistView.swift:56:44: missing argument for parameter 'backers_count' in call)
1. Add missing backers_count parameter in WatchlistView toCampaignDTO 2. Prevent showing $0/0% momentum section for campaigns with zero velocity/delta 3. Handle strconv.Atoi errors properly in GetCampaignHistory, default to 14 days Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Summary
Transform KickWatch iOS app into an investor-friendly visual experience following the principle: "Investors need visualization, not complexity". This PR adds color-coded badges, trend charts, sparklines, and intuitive metrics to help hardware investors make quick decisions.
Key Changes
Backend (Phase 1)
GET /campaigns/:pid/historyiOS Data Layer (Phase 2)
backers_counttoCampaignDTOHistoryDataPointandCampaignHistoryResponsemodelsAPIClientfetchCampaignHistory()methodList View Enhancements (Phase 3)
Detail View Stats & Content (Phase 4)
Chart Visualization (Phase 5)
Visual Design
Color Coding:
SF Symbols Icons:
person.2.fill→ Backersbolt.fill→ Momentumdollarsign.circle.fill→ Money metricsarrow.up.right/down.right→ Trend directioncheckmark.circle.fill→ Successtarget→ Goalcalendar→ Time remainingScreenshots
Before → After
List View:
Detail View:
Performance Optimizations
Testing Checklist
Related Issues
Closes #36
🤖 Generated with Claude Code