Skip to content

fix(migration): canonical store urls for pwa-sunset launch (TASK-21044) - #2945

Closed
kushagrasarathe wants to merge 4 commits into
devfrom
fix/real-store-urls
Closed

fix(migration): canonical store urls for pwa-sunset launch (TASK-21044)#2945
kushagrasarathe wants to merge 4 commits into
devfrom
fix/real-store-urls

Conversation

@kushagrasarathe

@kushagrasarathe kushagrasarathe commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Two related changes for the pwa-sunset launch, both dark behind the pwa-sunset PostHog flag:

1. Canonical store URLs (TASK-21044). Pins the iOS store + write-review URLs to the official /us/ listing form (https://apps.apple.com/us/app/id6786373552); Google Play unchanged (id=me.peanut.wallet).

2. Removes the custom app-review prompt (TASK-22193). ReviewPromptModal ("Loving Peanut so far?" → store deep link / "Could be better" → support) is a custom review prompt, disallowed verbatim by App Store guideline 5.6.1 ("Use the provided API… we will disallow custom review prompts"). It also routed unhappy users away from the store (5.6.3; Google's In-App Review guidelines forbid the "Do you like the app?" pre-question by name) and fired on the first home view after open — the moment the HIG says not to ask. Removing it clears the 5.6.1 exposure so pwa-sunset can flip to 100% without carrying a violation into App Review.

This is JS-only and OTA-shippable — no binary rebuild. REVIEW_URL, the reviewPromptShownAt pref, the APP_REVIEW modal type and the migration.review.* copy (three source locales + regenerated marketing subsets) go with the component.

The compliant replacement — the native OS review sheet on happy moments — is the follow-on #2952 (stacked on this branch; needs a binary release, cannot ride OTA).

Tasks

Risks

None on web — all migration surfaces are dark behind pwa-sunset (scoped to 11 userIds today). The prompt removal is additive-by-subtraction and OTA-safe.

MIGRATION_CUTOVER_DATE intentionally left as placeholder — set at flip-day decision.

QA

  • npm run typecheck clean; full npm test green (433 suites, 5568 passed); prettier clean.
  • Tests assert against the STORE_URL constant, not literals; REVIEW_URL had no consumer other than the removed modal, so nothing else references it.
  • URL check (curl, 2026-09-03): both listings currently 404 — expected (Android in closed testing, iOS still in review; IOS_APP_STORE_LISTING_LIVE stays false). Re-verify 200 before flag-on.

… launch

the real store ids already landed on dev (ca45419); this pins the ios
store + write-review urls to the canonical /us/ listing form
(apps.apple.com/us/app/id6786373552) so they match the published listing
exactly. play url confirmed unchanged. launch-blocker per TASK-21044 §2.

branch doubles as the handoff branch for slava's review-nudge changes.
@notion-workspace

Copy link
Copy Markdown

@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
peanut-wallet Ready Ready Preview Sep 3, 2026 2:50pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 2a5221c3-9b15-437e-bd41-5c2eba021c85

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 7052.83 → 7056.39 (+3.56)
Findings: -2 net (+77 new, -79 resolved)

🆕 New findings (77)

  • critical complexity — src/app/(mobile-ui)/qr-pay/page.tsx — CC 329, MI 52.65, SLOC 1209
  • critical complexity — src/utils/general.utils.ts — CC 177, MI 58.04, SLOC 663
  • critical method-complexity — src/app/(mobile-ui)/qr-pay/page.tsx:103 — QRPayPage CC 84 SLOC 447
  • critical complexity — src/features/payments/shared/components/PaymentSuccessView.tsx — CC 58, MI 55.69, SLOC 173
  • high hotspot — src/app/(mobile-ui)/qr-pay/page.tsx — 143 commits, +1957/-1649 lines since 6 months ago
  • high hotspot — src/constants/analytics.consts.ts — 67 commits, +475/-27 lines since 6 months ago
  • high hotspot — src/utils/general.utils.ts — 48 commits, +278/-387 lines since 6 months ago
  • high complexity — src/features/home/components/HomeModals.tsx — CC 46, MI 63.08, SLOC 123
  • high complexity — src/components/Claim/Link/Onchain/Success.view.tsx — CC 37, MI 60.1, SLOC 156
  • medium react-long-component — src/app/(mobile-ui)/qr-pay/page.tsx:103 — QRPayPage is 1791 lines — split it
  • medium high-mdd — src/app/(mobile-ui)/qr-pay/page.tsx:103 — QRPayPage: MDD 487.3 (uses across many lines from declarations)
  • medium high-dlt — src/app/(mobile-ui)/qr-pay/page.tsx:103 — QRPayPage: DLT 138 (calls 138 distinct functions — high context load)
  • medium high-mdd — src/features/payments/shared/components/PaymentSuccessView.tsx:91 — PaymentSuccessView: MDD 106.2 (uses across many lines from declarations)
  • medium high-mdd — src/components/Claim/Link/Onchain/Success.view.tsx:33 — SuccessClaimLinkView: MDD 77.3 (uses across many lines from declarations)
  • medium high-mdd — src/app/(mobile-ui)/qr-pay/page.tsx:821 — : MDD 48.2 (uses across many lines from declarations)
  • medium structural-dup — app/(mobile-ui)/dev/shake-test/page.tsx:29 — 46 duplicate lines / 204 tokens with app/(mobile-ui)/qr-pay/page.tsx:1124
  • medium high-mdd — src/components/Profile/views/About.view.tsx:24 — AboutView: MDD 39.7 (uses across many lines from declarations)
  • medium high-dlt — src/components/Claim/Link/Onchain/Success.view.tsx:33 — SuccessClaimLinkView: DLT 38 (calls 38 distinct functions — high context load)
  • medium high-dlt — src/features/payments/shared/components/PaymentSuccessView.tsx:91 — PaymentSuccessView: DLT 31 (calls 31 distinct functions — high context load)
  • medium high-mdd — src/components/Home/HomeCarouselCTA/index.tsx:17 — HomeCarouselCTA: MDD 28.9 (uses across many lines from declarations)

…and 57 more.

✅ Resolved (79)

  • src/app/(mobile-ui)/qr-pay/page.tsx — CC 328, MI 52.66, SLOC 1208
  • src/utils/general.utils.ts — CC 177, MI 58.03, SLOC 663
  • src/app/(mobile-ui)/qr-pay/page.tsx:102 — QRPayPage CC 83 SLOC 446
  • src/features/payments/shared/components/PaymentSuccessView.tsx — CC 58, MI 55.78, SLOC 172
  • src/features/home/components/HomeModals.tsx — CC 52, MI 63.21, SLOC 128
  • src/app/(mobile-ui)/qr-pay/page.tsx — 142 commits, +1952/-1649 lines since 6 months ago
  • src/constants/analytics.consts.ts — 65 commits, +468/-26 lines since 6 months ago
  • src/utils/general.utils.ts — 46 commits, +274/-385 lines since 6 months ago
  • src/components/Claim/Link/Onchain/Success.view.tsx — CC 36, MI 60.24, SLOC 155
  • src/app/(mobile-ui)/qr-pay/page.tsx:102 — QRPayPage is 1787 lines — split it
  • src/app/(mobile-ui)/qr-pay/page.tsx:102 — QRPayPage: MDD 486.3 (uses across many lines from declarations)
  • src/app/(mobile-ui)/qr-pay/page.tsx:102 — QRPayPage: DLT 137 (calls 137 distinct functions — high context load)
  • src/features/payments/shared/components/PaymentSuccessView.tsx:90 — PaymentSuccessView: MDD 105.2 (uses across many lines from declarations)
  • src/components/Claim/Link/Onchain/Success.view.tsx:32 — SuccessClaimLinkView: MDD 76.4 (uses across many lines from declarations)
  • src/app/(mobile-ui)/qr-pay/page.tsx:820 — : MDD 48.2 (uses across many lines from declarations)
  • app/(mobile-ui)/dev/shake-test/page.tsx:29 — 46 duplicate lines / 204 tokens with app/(mobile-ui)/qr-pay/page.tsx:1123
  • src/components/Claim/Link/Onchain/Success.view.tsx:32 — SuccessClaimLinkView: DLT 37 (calls 37 distinct functions — high context load)
  • src/features/payments/shared/components/PaymentSuccessView.tsx:90 — PaymentSuccessView: DLT 30 (calls 30 distinct functions — high context load)
  • src/components/Profile/views/About.view.tsx:21 — AboutView: MDD 27.8 (uses across many lines from declarations)
  • src/app/(mobile-ui)/qr-pay/page.tsx:820 — CC 27 SLOC 152

…and 59 more.

📈 Painscore deltas (top movers)

File Before After Δ
src/utils/app-review.ts 0.0 6.8 +6.8
src/utils/app-review-friction.ts 0.0 4.5 +4.5
src/hooks/useAppReviewNudge.ts 0.0 3.5 +3.5
src/components/Migration/ReviewPromptModal.tsx 6.8 0.0 -6.8

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 5618 ran, 0 failed, 0 skipped, 1.7m

📊 Coverage (unit)

metric %
statements 74.0%
branches 59.4%
functions 67.4%
lines 74.9%
⏱ 10 slowest test cases
time test
🐢 9.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Network failure keeps loading while retries remain, then shows the generic error
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_MERCHANT_RECENT_REFUND fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_SOURCE_OVER_MONTHLY_CAP fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › User KYC not approved fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_USER_NOT_PROVISIONED fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › routes the KYC rejection on its wire code, and does not retry it
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_MERCHANT_VOLUME_NEAR_CAP fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › a refused idempotency key tells the user to scan again, not to contact support
3.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Going offline blames the connection, and reconnecting clears it for the recovered scan
3.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Scan that recovers on the retry lands on the payment screen, not an error
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@chip-peanut-bot chip-peanut-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chip review — no blocking findings — this is not an approval

Clean at the supplied head. The two constants now use the standard US-storefront App Store URL shape while preserving the app ID and write-review query semantics; every consumer remains compatible.

Checked clean

  • Verified the detached worktree HEAD, trusted author, dev base ref, exact base SHA, and merge base.
  • Traced STORE_URL.ios and REVIEW_URL.ios through store badges, smart redirects, deferred handoff helpers, and the native review prompt.
  • Checked Apple's official App Store linking and review deep-link guidance; the product URL shape and action=write-review query are valid.
  • Probed both changed URLs: the listing currently returns 404 as documented because it is not public yet, so the final published destination cannot yet be exercised.
  • Checked CI at the exact head: 13 checks succeeded, 3 were still in progress, 1 was skipped, and none failed.
  • Ran git diff --check and reviewed the file's recent history and surrounding migration constants.

Second opinion by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

Exact head: 2a552d16a02e · Context: repo, apple-developer-docs · Took 6m

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🖼 Visual diff — 1 screen moved

1 of 60 shots changed · 59 identical · baseline c2811a2 → head 036db38

worst % screen widths
2.83% profile 320
new screens (1)
  • reconsent

job summary · before/after/diff images — artifact

Fixture screenshots, no backend. Advisory — this check never blocks a merge. Posted from the default branch by ds-shots-comment.yml; the report it renders is untrusted data.

App Store Review Guidelines 5.6.1 disallows custom review prompts outright:
"Use the provided API to prompt users to review your app ... we will disallow
custom review prompts." ReviewPromptModal is one — our own copy, our own CTA,
deep-linking out to the store's write-review page.

Two further problems on the same modal: routing "Could be better" to the
support drawer filters unhappy users away from the store (5.6.3 Discovery
Fraud; Google's In-App Review guidelines name the "Do you like the app?"
pre-question explicitly), and it fired on the first home view after app open,
which is the moment the HIG tells you not to ask.

Removing it rather than relocating it: the native review sheet
(SKStoreReviewController / Play In-App Review) needs a Capacitor plugin, so it
cannot ride an OTA bundle. This deletion is JS-only and unblocks flipping
pwa-sunset to 100% without carrying a 5.6.1 violation into App Review; the
happy-moment replacement lands with the next binary.

REVIEW_URL, the reviewPromptShownAt preference and the APP_REVIEW modal type
lose their only consumer and go with it. migration.review.* is removed from the
three source catalogs and the marketing subsets regenerated.

@chip-peanut-bot chip-peanut-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chip review — no blocking findings — this is not an approval

The store URL canonicalization and custom review-prompt removal are sound, but the deletion leaves two design-system audit inventories claiming that ReviewPromptModal is still live.

Findings

  • MINOR · src/components/Migration/ReviewPromptModal.tsx:1 · Remove the stale ReviewPromptModal audit rows
    Deleting this component leaves both DS audit inventories reporting ReviewPromptModal as live with one usage and pointing at a source file that no longer exists. The /dev/ds/audit views therefore present a false inventory after this change. Remove the ReviewPromptModal rows from audit-data.ts and audit-components-data.ts, and update any affected modal aggregate counts.

Checked clean

  • Verified the detached worktree HEAD, supplied base commit, merge base, trusted PR author, and dev base ref.
  • Reviewed the complete two-commit diff and surrounding STORE_URL consumers.
  • Confirmed the custom prompt's live import, analytics modal type, preference field, review URL, and locale entries were removed with no remaining product-code references.
  • Checked current Apple App Review 5.6.1 and Google Play in-app review guidance; removing the custom pre-prompt matches both.
  • All exact-head GitHub checks completed successfully; changed locale JSON parses and git diff --check is clean.
  • Security pass found no new secret exposure, input-handling boundary, privilege change, or persistent-state mutation.

Second opinion by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

Exact head: 02acd52457ae · Context: repo, ci, web · Took 11m (queued 9m)

Comment thread src/components/Migration/ReviewPromptModal.tsx
…193)

Replaces the deleted custom prompt with the OS review sheet
(@capgo/capacitor-in-app-review: SKStoreReviewController on iOS, Play In-App
Review on Android), which is the only ask guideline 5.6.1 permits. This is the
binary half of the review-nudge work — it adds native plugins and so cannot ship
over OTA; the JS-only removal is TASK-22193's other PR.

requestAppReview(userId, trigger) is the single entry point. It carries the
whole policy so call sites stay one line:

- native only, skipped in demo mode
- an engagement floor (>=2 qualifying moments) before the first ask, so a
  day-0 depositor is never asked — HIG's "demonstrated engagement"
- a 120-day floor between requests and at most 2 per 365 days, one under
  Apple's silent 3/365 ceiling so a strong moment always has budget. The OS
  reports nothing back, so this stamp is the only control we have.
- a 7-day friction quiet period: any money-flow failure (observed for free in
  posthog before_send) suppresses the ask. This is the honest version of what
  the old "Could be better" branch reached for — suppress the question, never
  filter the answer toward or away from the store.

Wired on the tail of four happy moments, each gated on the success being real
and fired ~2.5s after the celebration settles (never mid-flow, never layered on
our own modal): reward/perk claim (a friend joined + money landed — the
strongest moment), shared payment success, claim-link money-received, and QR
pay. review_requested is captured with the trigger and budget state; there is
deliberately no shown/rated counterpart because neither OS exposes one — measure
against App Store Connect / Play Console.

Also adds a user-initiated "Leave a review" row in Profile -> About. A prompt
built from a write-review deep link would breach 5.6.1, but Apple documents that
exact link for a review the user starts themselves, and it is the release valve
for anyone the OS quota silently skipped. Opens via @capacitor/app-launcher, not
the in-app browser: SFSafariViewController does not follow the universal link, so
?action=write-review would otherwise land on the web listing with no composer.
@innolope-dev
innolope-dev marked this pull request as ready for review September 3, 2026 14:26
feat(review): native app-store review sheet on happy moments (TASK-22193)

@chip-peanut-bot chip-peanut-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chip review — no blocking findings — this is not an approval

The review-prompt removal and native review-nudge rollout are coherent at this head; one previously raised stale DS-audit entry remains and is explicitly deferred to TASK-22226.

Answered by a human, not raised again

These are still present as far as this review can tell. You resolved the thread or deferred the fix, so Chip files them instead of repeating them.

  • MINOR · src/components/Migration/ReviewPromptModal.tsx:1 · Design-system audit data still references deleted ReviewPromptModal — no task filed, please file one

Checked clean

  • Verified HEAD matches 036db38 and diff is against base c2811a2.
  • Reviewed app-review flow end-to-end (useAppReviewNudge, requestAppReview, friction suppression, About screen fallback) and found no additional correctness or security defects in changed runtime paths.
  • Confirmed old custom review prompt wiring was removed (component deletion, HomeModals removal, APP_REVIEW modal type and reviewPromptShownAt usage removed).
  • Checked CI for this exact head via check-runs API: all required gates succeeded.

Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

The usual first reviewer was out of plan, so this review was done by openrouter/openai/gpt-5.3-codex.

Exact head: 036db38aefba · Context: repo, ci · Took 11m (queued 9m)

@innolope-dev

Copy link
Copy Markdown
Collaborator

Superseded by #2995 — same content re-authored onto current dev (this branch could no longer merge after #2956 / the About-view and web-vitals changes). Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants