feat(app): GO_TO_SEEKER phases 1–3 — PWA + MWA + TWA scaffold#3
Open
RamirezAlex wants to merge 5 commits into
Open
feat(app): GO_TO_SEEKER phases 1–3 — PWA + MWA + TWA scaffold#3RamirezAlex wants to merge 5 commits into
RamirezAlex wants to merge 5 commits into
Conversation
…bution path New top-level plan doc at docs/GO_TO_SEEKER.md. Captures the Solana Mobile distribution route as a deliberate alternative to a generic Play Store TWA, which the prior PWA/TWA discussion flagged as policy-blocked for crypto/gambling categories. Mirrors the DEPLOYMENT_PLAN.md style: status header at top, phased plan with concrete file paths + hour estimates, ranked risks, open questions needing user input, deploy-day checklist at the bottom. Why-Seeker-over-Play comparison: removes the Play policy ban-risk for crypto/gambling apps, routes through Seed Vault instead of fighting Chrome's extension-only wallet model, takes 0% revenue cut, costs ~0.05 SOL on-chain to publish vs $25 + Play Console signing infra, and reaches the right audience (crypto-native users on the ~150K Saga + Seeker installed base rather than generic Android). Six prerequisites captured before any Seeker-specific work: - PWA shell shipped (~5-6 hr from the prior PWA plan). - Mobile Wallet Adapter integration shipped (~6-11 hr from the prior plan; on Seeker this routes through Seed Vault natively, no third-party wallet app needed). - Dealer deployed to production (currently code-complete per Pre-Mainnet 5.2, gated on operator action). Block Seeker submission until full gameplay works end-to-end. - Mainnet decision (Open Question #1) - dApp Store users expect mainnet by default; devnet-only listing is a reputation risk. - Brand asset upgrade - feature graphic 1920x1080, >=4 screenshots at 1080x1920, full description <=4000 chars, short description <=80 chars. PWA-quality icons aren't enough for the dApp Store listing. - Publisher keypair - separate from dealer, faucet, and CLI wallet keypairs. Same blast-radius separation pattern as Pre-Mainnet 5.0.7 (faucet) and 5.2 (dealer), but with the important caveat that the dApp Store publisher PDA cannot be reassigned: losing the keypair = losing the listing. Five phases (0 prerequisites, 1 PWA ~5-6 hr, 2 MWA ~6-11 hr, 3 TWA wrap ~3-5 hr, 4 dApp Store submission ~3-5 hr active + 1-14 day moderation queue, 5 optional Seeker-native polish). Total active work ~17-25 hr plus moderation wait. Phases 1, 2, 3 are sequential; brand assets and publisher keypair work can be parallelized with Phase 1. Six ranked risks. The top three are decision-shaped, not implementation-shaped: - Mainnet vs devnet listing (Open Question #1) gates everything downstream. - Publisher keypair custody - same gravity as the program upgrade authority, requires hardware wallet + multi-location backup before submission. - Moderation rejection - Solana Mobile's review is softer than Play but still real; common rejection reasons in 2025 were incomplete metadata + screenshots that didn't reflect actual gameplay. The remaining three (MWA wire-format bug shape per Lesson #46, brand-asset polish, Seeker hardware availability for testing) are all bounded implementation costs. Five open questions captured, the most important being whether the first dApp Store release targets devnet (faster to ship, weaker first impression) or mainnet (right audience, much bigger prerequisite scope including upgrade authority lockdown + multisig + pot custody). Reference checklist at the bottom mirrors the DEPLOYMENT_PLAN.md runbook style for the actual submission session: keypair gen + funding + backup, AAB build via Bubblewrap, assetlinks.json deployed via the server-config repo, four `npx dapp-store ...` on-chain txs in sequence, moderation queue, real-device acceptance test on Seeker (or Saga as fallback). Not done in this commit: cross-reference line in EXECUTION_PLAN.md's Phase 5 section pointing at the new doc. Gated on plan-content review before adding pointers from the live execution plan into the new file.
… (GO_TO_SEEKER Phase 1) Adds the PWA foundation that the Solana Seeker / dApp Store TWA path inherits (per docs/GO_TO_SEEKER.md prerequisite #1). - vite-plugin-pwa@1.2.0 with registerType:"prompt" — SW activates only on user confirmation via <UpdateBanner>, avoiding surprise reloads mid-game. devOptions disabled so HMR doesn't fight the cache. - Web manifest matches the brand spine (#0a0a0f), display:standalone, orientation:portrait (per Pre-Mainnet 5.0.x responsive sweep), categories:["games"]. Workbox precache filtered to skip /api/* so RPC + dealer + faucet calls bypass any stale-cache hit. - Icon set generated from public/favicon.svg via @vite-pwa/assets-generator (config in pwa-assets.config.ts; reproducible via `pnpm pwa-assets`). Adds 64/192/512/1024 + maskable-512 + apple-touch-180 + favicon.ico. The 1024 source asset is what the Solana dApp Store listing expects in Phase 4 (GO_TO_SEEKER.md). - <UpdateBanner> uses useRegisterSW from virtual:pwa-register/react; emerald palette to distinguish from <DemoStageBanner> (slate, info) and <ClusterHint> (amber, warning). No dismissal persistence — a user who clicks X sees the banner reappear on the next deploy, since stale code can mean wrong tx semantics in a crypto app. - index.html: standardized mobile-web-app-capable meta (apple-prefixed form is deprecated in Chrome ≥122) — both included for backward iOS compat. Apple-touch-icon link added explicitly since vite-plugin-pwa only auto-injects <link rel="manifest">. - workbox-window added as explicit devDep — pnpm doesn't hoist peer deps, and virtual:pwa-register/react imports it. Verified: typecheck + lint + production build all clean. dist/ now emits sw.js + workbox-*.js + manifest.webmanifest + the icon set; Chrome's Application → Manifest panel reports all fields green and offers the Install action in the URL bar. Lighthouse PWA install audit not yet run end-to-end (requires VITE_DEALER_URL / FAUCET_URL / NICKNAME_URL set at build time to bypass the production guards in preview).
…O_TO_SEEKER Phase 2) Adds the MWA adapter to the wallet provider so a TWA-wrapped pushflip running on Seeker / Saga can authorize via Seed Vault, satisfying prerequisite #2 of `docs/GO_TO_SEEKER.md`. - `@solana-mobile/wallet-adapter-mobile@2.2.8` added as runtime dep. RN peer-dep warning is harmless: the package has separate browser and react-native conditional exports; we only resolve the browser bundle. Bundle delta is ~220 bytes (most code was already pulled in via shared @Solana deps). - `wallet-provider.tsx` constructs `SolanaMobileWalletAdapter` inside `useMemo([])` — `BaseWalletProvider` tears down internal state when the wallets array reference changes, so a stable instance is load- bearing. Defaults from the adapter's helper factories (`createDefaultAddressSelector` / `createDefaultAuthorizationResultCache` / `createDefaultWalletNotFoundHandler`) cover the Seeker happy path without bespoke config. - `appIdentity.uri = window.location.origin` so dev (localhost:5173) and production (play.pushflip.xyz) both work without an env-var step. MUST match the assetlinks.json domain Phase 3 publishes — mismatch fails the MWA handshake silently (same shape as Lesson #46). - Adapter is registered unconditionally — its `readyState` reports `Unsupported` on non-Android contexts, so the wallet modal hides it automatically. Following Solana Mobile's documented pattern; gating ourselves would duplicate detection the adapter already does. - New `MWA_CHAIN = "solana:devnet"` constant in `lib/constants.ts` decoupled from `RPC_ENDPOINT` (a private mainnet RPC + `solana:mainnet` is a valid combo). Becomes a build-time env when the mainnet decision (Open Question #1 in GO_TO_SEEKER.md) lands. Spike conclusion (the M2.1 question that blocked starting Phase 2): **Lesson #46 fix is adapter-agnostic.** `wallet-bridge.ts` rebuilds `lifetimeConstraint` from the original Kit message, not from the signed result, so MWA-returned `VersionedTransaction` instances flow through the same `compile → sign → fromVersionedTransaction → re-merge lifetime` path as Phantom/Solflare. No bridge changes required. Verified: typecheck + full-repo lint + production build + 5/5 tests all clean. Bundle size: 930.32 → 930.54 KB (gzip 286.27 → 286.27 KB). Deferred to Phase 2 acceptance (per GO_TO_SEEKER.md, requires Android hardware/emulator): - Real-device test on Saga (compatibility floor). - M2.1 spike's runtime validation — sign one joinRound tx end-to-end via the MWA fake-wallet emulator. - Confirm `appIdentity.uri` matches assetlinks.json once Phase 3 publishes it.
Status flips from PLANNED to IN PROGRESS. Adds a "Where we are (2026-05-08)" section per the EXECUTION_PLAN living-status pattern; marks prerequisites #1 (PWA shell) and #2 (MWA code-side) as ✅ DONE with commit refs (f132dcb, e3585cd); appends ✅ DONE markers to the Phase 1 + Phase 2 section headings. Phase 2 section gains an implementation-deviations subsection documenting two intentional departures from the original spec, each with reason: 1. appIdentity.uri derived from window.location.origin instead of a hardcoded play.pushflip.xyz — strictly more flexible (dev + prod + future staging hosts auto-track), same security property since the assetlinks contract is enforced at the production deploy domain level. 2. Adapter registered unconditionally instead of behind an Android- detection gate — adapter's readyState reports Unsupported on non-Android, modal hides it; gating ourselves would duplicate detection the adapter already does. M2.1 spike conclusion captured: Lesson #46 fix is adapter-agnostic (wallet-bridge.ts rebuilds lifetimeConstraint from the original Kit message, not the signed result), so MWA-returned VersionedTransaction flows through the same path as Phantom/Solflare. No bridge changes required. "Biggest unknowns at draft time" → "Biggest unknowns now"; the Seed Vault integration cost item is downgraded to "partially answered" with strikethrough preserving the original — code-level integration is mechanical (~30 lines + one constant); runtime cost still unverified pending Android hardware. Phase 5 brand-asset prerequisite gets a partial-credit note: the 1024×1024 source asset called out as a Phase 4 dApp Store requirement is already generated as part of the Phase 1 icon set (app/public/pwa-1024x1024.png), ahead of schedule.
…_TO_SEEKER Phase 3 prep) Isolated twa/ folder for the Seeker TWA build. Keeps the Java/Gradle toolchain out of the Node/pnpm workspace and isolates the keystore (must never be committed — losing it orphans every existing TWA install on Android). - twa/.gitignore — excludes keystores (*.keystore, *.jks), build outputs (*.aab, *.apk), Gradle caches, IDE files, Bubblewrap state. - justfile — four Bubblewrap wrappers: `twa-init` (prod URL), `twa-init-local` (localhost:4173 from `pnpm preview`, for toolchain validation before prod manifest is live), `twa-build`, `twa-update`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Expanded beyond the original plan-doc-only commit. The PR now bundles
docs/GO_TO_SEEKER.md+ Phase 1 (PWA shell) + Phase 2 code-side (MWA wire-up) + plan-progress updates + Phase 3 prep (TWA workspace scaffold + just recipes). Five commits ongo-to-seeker-plan.What's in the PR
f2df505) —docs/GO_TO_SEEKER.md, the top-level Solana Seeker / dApp Store distribution plan. MirrorsDEPLOYMENT_PLAN.mdstyle.f132dcb) —vite-plugin-pwa@1.2.0, web manifest matching brand spine (#0a0a0f), full icon set (64/192/512/1024 + maskable + apple-touch + favicon) generated fromapp/public/favicon.svg,<UpdateBanner>with prompt-style SW activation, Workbox precache filtered to skip/api/*.dist/manifest.webmanifest+sw.jsemit cleanly.e3585cd) —@solana-mobile/wallet-adapter-mobile@2.2.8,SolanaMobileWalletAdapterregistered inwallet-provider.tsxinsideuseMemo([])with helper-factory defaults. NewMWA_CHAIN = "solana:devnet"constant decoupled fromRPC_ENDPOINT. Adapter registered unconditionally;readyStateself-reportsUnsupportedoff-Android. Bundle delta: ~220 B. M2.1 spike conclusion: Lesson #46 fix is adapter-agnostic — nowallet-bridge.tschanges needed.5d82c41) —docs/GO_TO_SEEKER.mdupdated to reflect Phase 1 + Phase 2 status, narrowed unknowns, captured M2.1 spike result.881eaea) —twa/folder scaffolded with.gitignorecovering keystores (*.keystore,*.jks), AAB/APK outputs, Gradle/IDE/Bubblewrap state.justfileadds four Bubblewrap wrappers:twa-init(prod URL),twa-init-local(localhost:4173 frompnpm preview, for toolchain validation before prod deploy),twa-build,twa-update.Decisions made (Open Questions resolved 2026-05-08)
MWA_CHAINalready matches.Deferred (not in this PR)
joinRoundend-to-end + confirmingappIdentity.urimatches assetlinks. Blocked on Android hardware/emulator.bash scripts/deploy-tucker.sh. Required to makehttps://play.pushflip.xyz/manifest.webmanifestreachable for the final Bubblewrap build. Production currently serves SPA-fallback for PWA assets (manifest, sw.js, pwa-*.png all return text/html — verified).bubblewrap updateagainst the prod URL once the deploy ships, thenjust twa-build. The current scaffold supports localhost-only validation.server-configrepo toplay.pushflip.xyz/.well-known/assetlinks.json.dapp-store/config.yaml, brand assets (feature graphic + ≥4 screenshots + optional video), on-chain publish txs. Out of scope here.Test plan
cd app && pnpm buildsucceeds;dist/containsmanifest.webmanifest,sw.js, fullpwa-*.pngset.cd app && pnpm previewserves/manifest.webmanifestwithapplication/manifest+jsoncontent-type.just twa-init-local(afternpm i -g @bubblewrap/cli+ JDK 17+) scaffoldstwa/against the localhost manifest without error.just twa-buildproduces a signed AAB insidetwa/.twa/.gitignorekeeps the generated keystore + AAB out ofgit status.