Skip to content

feat(app): GO_TO_SEEKER phases 1–3 — PWA + MWA + TWA scaffold#3

Open
RamirezAlex wants to merge 5 commits into
mainfrom
go-to-seeker-plan
Open

feat(app): GO_TO_SEEKER phases 1–3 — PWA + MWA + TWA scaffold#3
RamirezAlex wants to merge 5 commits into
mainfrom
go-to-seeker-plan

Conversation

@RamirezAlex
Copy link
Copy Markdown
Collaborator

@RamirezAlex RamirezAlex commented Apr 29, 2026

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 on go-to-seeker-plan.

What's in the PR

  • Plan (f2df505) — docs/GO_TO_SEEKER.md, the top-level Solana Seeker / dApp Store distribution plan. Mirrors DEPLOYMENT_PLAN.md style.
  • Phase 1 — PWA shell (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 from app/public/favicon.svg, <UpdateBanner> with prompt-style SW activation, Workbox precache filtered to skip /api/*. dist/manifest.webmanifest + sw.js emit cleanly.
  • Phase 2 — MWA wire-up (e3585cd) — @solana-mobile/wallet-adapter-mobile@2.2.8, SolanaMobileWalletAdapter registered in wallet-provider.tsx inside useMemo([]) with helper-factory defaults. New MWA_CHAIN = "solana:devnet" constant decoupled from RPC_ENDPOINT. Adapter registered unconditionally; readyState self-reports Unsupported off-Android. Bundle delta: ~220 B. M2.1 spike conclusion: Lesson #46 fix is adapter-agnostic — no wallet-bridge.ts changes needed.
  • Plan progress (5d82c41) — docs/GO_TO_SEEKER.md updated to reflect Phase 1 + Phase 2 status, narrowed unknowns, captured M2.1 spike result.
  • Phase 3 prep (881eaea) — twa/ folder scaffolded with .gitignore covering keystores (*.keystore, *.jks), AAB/APK outputs, Gradle/IDE/Bubblewrap state. justfile adds four Bubblewrap wrappers: twa-init (prod URL), twa-init-local (localhost:4173 from pnpm preview, for toolchain validation before prod deploy), twa-build, twa-update.

Decisions made (Open Questions resolved 2026-05-08)

Deferred (not in this PR)

  • Phase 2 runtime acceptance — Saga / Seeker connect flow + signing one joinRound end-to-end + confirming appIdentity.uri matches assetlinks. Blocked on Android hardware/emulator.
  • Prod deploy of the PWA shellbash scripts/deploy-tucker.sh. Required to make https://play.pushflip.xyz/manifest.webmanifest reachable for the final Bubblewrap build. Production currently serves SPA-fallback for PWA assets (manifest, sw.js, pwa-*.png all return text/html — verified).
  • Phase 3 final AAB buildbubblewrap update against the prod URL once the deploy ships, then just twa-build. The current scaffold supports localhost-only validation.
  • assetlinks.json — needs the keystore SHA-256, then deployed via the separate server-config repo to play.pushflip.xyz/.well-known/assetlinks.json.
  • Phase 4 work — publisher keypair gen + funding + custody, 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 build succeeds; dist/ contains manifest.webmanifest, sw.js, full pwa-*.png set.
  • cd app && pnpm preview serves /manifest.webmanifest with application/manifest+json content-type.
  • Chrome's Application → Manifest panel reports green; Install action visible in URL bar.
  • just twa-init-local (after npm i -g @bubblewrap/cli + JDK 17+) scaffolds twa/ against the localhost manifest without error.
  • just twa-build produces a signed AAB inside twa/.
  • twa/.gitignore keeps the generated keystore + AAB out of git status.
  • Phase 2 runtime acceptance on Saga / Seeker — DEFERRED, owed when Android hardware is set up.

…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`.
@RamirezAlex RamirezAlex changed the title docs(plan): add GO_TO_SEEKER plan — Solana Seeker / dApp Store distribution path feat(app): GO_TO_SEEKER phases 1–3 — PWA + MWA + TWA scaffold May 8, 2026
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.

1 participant