# Android Billing and Pro UX Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Let Android users buy or restore `pro_multi_account`, activate the local entitlement, and add up to five execution accounts while keeping purchase tokens outside JavaScript.

**Architecture:** A registered Capacitor Android plugin owns Google Play BillingClient and calls the verifier directly over HTTPS. JavaScript receives only normalized purchase state or a signed certificate, then binds that certificate to a short-lived local backend challenge. Shared PWA state renders status and purchase UX; backend enforcement remains authoritative.

**Tech Stack:** Android Java 21, Google Play Billing Library 9.1.0, Capacitor 8 local plugin, React 19, Vitest, existing PWA feature architecture.

## Global Constraints

- The purchase token must never cross the Capacitor bridge, enter PWA logs, or reach the backend.
- Show Google Play's localized ProductDetails price; do not hard-code `₩9,900` in purchase UI.
- Purchase cancellation is not an error toast; pending remains pending; already-owned triggers restore.
- All official Codex remote controls remain available for the one free account.
- Mobile controls are at least 48px high, inputs remain 16px, shell stays `100dvh`.
- Verify interactive UI at 390x844. Do not sign or upload an AAB without explicit approval.

---

### Task 1: Native Billing client and Capacitor boundary

**Files:**
- Modify: `apps/pwa/android/app/build.gradle`
- Modify: `apps/pwa/android/app/src/main/java/com/coderemote/manager/MainActivity.java`
- Create: `apps/pwa/android/app/src/main/java/com/coderemote/manager/ProBillingPlugin.java`
- Create: `apps/pwa/android/app/src/main/java/com/coderemote/manager/ProBillingClient.java`
- Create: `apps/pwa/android/app/src/test/java/com/coderemote/manager/ProBillingClientTest.java`

- [ ] Add `com.android.billingclient:billing:9.1.0` and a unit-testable adapter. Register the local
  plugin before `super.onCreate()` in `MainActivity`.
- [ ] Write native tests for Billing connection, `queryProductDetailsAsync`, selecting a one-time
  offer token, purchase launch, purchased/unacknowledged, pending, canceled, already-owned,
  unavailable Play Store, disconnect/retry, and `queryPurchasesAsync` restore.
- [ ] Run `apps\pwa\android\gradlew.bat :app:testDebugUnitTest` from `apps/pwa/android` and confirm
  the new test fails before implementation.
- [ ] Expose only these plugin methods and normalized fields:

```java
getProduct()    // productId, localizedPrice, available
purchase()      // state: activated|pending|canceled|unavailable; certificate?, expiresAt?
restore()       // state: activated|not_owned|pending|unavailable; certificate?, expiresAt?
```

  Native code calls the configured HTTPS verifier with purchase token plus backend thumbprint and
  challenge hash. Never place `purchaseToken` into a `JSObject`.
- [ ] Inject verifier base URL through release `BuildConfig`; fail release builds when absent or
  non-HTTPS. Do not commit a production URL.
- [ ] Run native focused tests and confirm all pass.
- [ ] Commit with `feat(android): add native Pro billing`.

### Task 2: JavaScript adapters and entitlement state

**Files:**
- Create: `apps/pwa/src/platform/pro-billing.js`
- Create: `apps/pwa/src/platform/pro-billing.test.js`
- Create: `apps/pwa/src/features/pro/pro-api.js`
- Create: `apps/pwa/src/features/pro/pro-api.test.js`
- Create: `apps/pwa/src/features/pro/useProEntitlement.js`
- Create: `apps/pwa/src/features/pro/useProEntitlement.test.jsx`

- [ ] Write adapter tests proving web/non-native environments report billing unavailable, native
  responses are strictly normalized, and unexpected fields including `purchaseToken` are dropped.
- [ ] Write API tests for public status, challenge creation, and activation. Write hook tests for
  initial refresh, purchase, restore, expired challenge retry once, activation failure, grace, and
  backend disconnect.
- [ ] Run the focused Vitest files and confirm expected failures.
- [ ] Implement the billing adapter with `registerPlugin('ProBilling')` and an injectable test
  implementation. Implement backend API calls with existing `request()` conventions.
- [ ] In the hook, request a backend challenge first, pass only its challenge hash and backend key
  thumbprint to native, receive a certificate, activate it immediately, then discard it from React
  state and refresh public status.
- [ ] Run focused tests and confirm all pass.
- [ ] Commit with `feat(pwa): add Pro entitlement state`.

### Task 3: Purchase sheet and settings management

**Files:**
- Create: `apps/pwa/src/features/pro/ProPurchaseSheet.jsx`
- Create: `apps/pwa/src/features/pro/ProPurchaseSheet.test.jsx`
- Create: `apps/pwa/src/features/pro/ProSettingsSection.jsx`
- Create: `apps/pwa/src/features/pro/ProSettingsSection.test.jsx`
- Create: `apps/pwa/src/features/pro/pro.css`
- Modify: `apps/pwa/src/features/settings/SettingsWindow.jsx`
- Modify: `apps/pwa/src/features/settings/SettingsWindow.test.jsx`

- [ ] Write UI tests for free description, localized price, buy, restore, pending, cancellation,
  unavailable billing, active Pro, grace warning, expiry, and safe retry. Confirm accessibility
  names and focus return when the sheet closes.
- [ ] Run focused tests and confirm failures.
- [ ] Implement a compact bottom sheet: “모든 원격 기능은 무료, 계정 1개 / Pro는 최대 5개” and
  localized English equivalent. Do not claim subscription or cloud sync.
- [ ] Add settings status, configured-account count, restore action, and a link that opens Google
  Play purchase management. Close popup/sheet immediately after an internal action as required by
  the UI invariants.
- [ ] Run focused tests and confirm all pass.
- [ ] Commit with `feat(pwa): add Pro purchase and restore UI`.

### Task 4: Account-add flow and locked-account UX

**Files:**
- Modify: `apps/pwa/src/App.jsx`
- Modify: `apps/pwa/src/features/accounts/useAccounts.js`
- Modify: `apps/pwa/src/features/accounts/useAccounts.test.jsx`
- Modify: `apps/pwa/src/features/accounts/AccountsPanel.jsx`
- Modify: `apps/pwa/src/features/accounts/AccountsPanel.test.jsx`
- Modify: `apps/pwa/src/features/context/ContextBar.jsx`
- Modify: `apps/pwa/src/features/context/ContextBar.test.jsx`

- [ ] Test that tapping “add account” at the free limit opens the purchase sheet before device
  login, while a backend `402 pro_required` still opens it as the authoritative fallback.
- [ ] Test successful purchase/restore refreshes accounts and resumes the add-account action exactly
  once. Cancellation or pending must not start login.
- [ ] Test excess account rows remain visible with a Pro lock marker; locked selector items cannot
  execute or silently switch selection; history remains openable.
- [ ] Run focused tests and confirm failures.
- [ ] Instantiate Pro state in `App.jsx` before `useAccounts` and pass explicit callbacks/props; keep
  feature logic outside the composition root. Map safe backend error codes, not message strings.
- [ ] Run focused tests and confirm all pass.
- [ ] Commit with `feat(pwa): gate additional accounts with Pro`.

### Task 5: Android and mobile integration gate

**Files:**
- Create: `tools/android-billing-boundary.test.mjs`
- Modify: `docs/PRE_RELEASE_CHECKLIST.md`

- [ ] Add static boundary tests that reject `purchaseToken` in PWA source/backend public fixtures,
  reject a production verifier URL in tracked source, require Billing 9.1.0, and require the plugin
  registration and Android dependency notice.
- [ ] Run native unit tests, focused PWA tests, `npm.cmd test`, PWA production build, and
  `git diff --check`; record exit codes and counts.
- [ ] At 390x844 verify free account use, add-account sheet, purchase cancel, pending, successful
  activation fixture, restore fixture, locked account, settings, composer placement, outside-tap
  dismissal, and focus return.
- [ ] Build an unsigned release AAB and inspect it for private keys, service-account JSON, local
  paths, purchase tokens, and debug endpoints. Signing requires separate operator approval.
- [ ] Update the checklist and advance only to policy/release synchronization.
- [ ] Commit with `test(android): verify Pro purchase boundary`.
