원클릭으로
android-migrate-payment-method-v6
Plan and execute the migration of a v5 payment method to the v6 component architecture.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Plan and execute the migration of a v5 payment method to the v6 component architecture.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create a branch with correct prefix and base.
Run compile, lint, and unit test checks.
Create a commit with pre-commit checks and conventions.
Create a draft PR with title, body, and checklist.
| name | android-migrate-payment-method-v6 |
| description | Plan and execute the migration of a v5 payment method to the v6 component architecture. |
Migrate a v5 payment method to the v6 architecture, using the Google Pay migration as the canonical reference. This skill produces an ordered, test-driven execution plan and drives the migration phase by phase, with small commits and stacked PRs.
Invoke this skill when migrating an existing v5 payment method (e.g. ideal, sepa, twint) to v6. The input is the payment method / module name. The skill is method-agnostic: every payment method differs (Google Pay, for instance, has no input fields and hands off to an external SDK), so treat the steps as a checklist to adapt, not a rigid template.
Throughout this skill,
Xstands for the payment method (e.g.Ideal), andx/modulefor its module.
Each v6 payment method is a small set of collaborators wired by a factory. No single module is a complete reference — use all three migrated methods: Google Pay (external SDK, no input fields), MBWay (input fields + secondary screen, no params/mapper), and Card (input fields + stored variant):
| Layer | Type (reference) | Responsibility |
|---|---|---|
| Core details | XDetails : PaymentMethodDetails (core) | Serializable paymentMethod body for /payments. Must be registered in PaymentMethodDetails.getChildSerializer and have a PaymentMethodTypes constant. |
| Params (optional) | XComponentParams + XComponentParamsMapper | Map CheckoutParams + PaymentMethod + config → typed params. Only when the method derives config; simple methods pass CheckoutParams values straight through (MBWay has no params/mapper). |
| State | XComponentState, XComponentStateFactory, XIntent (sealed), XComponentStateReducer, XComponentStateValidator | Immutable state + intent-driven reducer + validity. |
| State → payment | XPaymentComponentState, toPaymentComponentState() ext | Map component state → PaymentComponentData<XDetails>. |
| View state | XViewState + XViewStateProducer | Map component state → UI model. |
| View | XContent (Compose) + pure-UI sub-composables | XContent holds effects/flow collection; a private composable holds pure UI + @Preview. |
| Component | XComponent : PaymentComponent | Owns ComponentStateFlow, derives viewState, exposes eventFlow, Content(), submit(), setLoading(). |
| Factory | XFactory : PaymentComponentFactory<XComponent> | Builds the component from a PaymentMethod. Also implements StoredPaymentComponentFactory<StoredXComponent> when the method supports stored payments (see Card). |
| Registration | XInitializer : Initializer<Unit> + module AndroidManifest.xml | Registers the factory via PaymentMethodProvider.register(txVariant, factory) for each supported type. |
| Public API | XConfiguration + CheckoutConfiguration.x { } DSL | The only public surface; everything else is internal. |
| Stored variant (if supported) | StoredXComponent + parallel stored state/view-state/reducer/validator/intent + StoredXContent | Separate stack for stored payments, built by the same factory (see Card). |
| Secondary screen (optional) | SecondaryScreenComponent → SecondaryContent(identifier, modifier) + PaymentComponentEvent.SecondaryScreen/CloseSecondaryScreen | For pickers/bottom sheets, e.g. MBWay's country-code picker. |
AGENTS.md. This skill defers to it for visibility/API rules, sealed-vs-abstract, styles/strings, external-SDK handling, and TDD.AGENTS.md, write <METHOD>_V6_MIGRATION_PLAN.md, get it approved, and do not start coding until then. Keep it updated as phases complete. Do not commit the plan file.XDetails already existed) so you don't recreate it.compileOnly + runCompileOnly/checkCompileOnly + ProGuard dontwarn), availability pre-checks, action/redirect handling, and any bridging of out-of-composition events into the Composable (see Google Pay's viewEventChannel). Also decide which optional capabilities apply: a params/mapper, input fields (validation + error display), a stored variant, and a secondary screen (pickers/sheets).architecture-guardian when a phase introduces or changes public API, new abstractions, or module boundaries.old/ move; state + view-state + view; component + factory + registration). Cadence is a reviewer preference, so confirm it during planning.Follow this loop for each phase below:
internal visibility.android-check skill scoped to the touched module(s) (./gradlew :<module>:check, plus :core:check when core changed).android-commit skill (one logical change per commit, COSDK-XXXX ticket). Never bundle multiple phases.Use the android-branch-create skill to create a chore/ branch (base main during v6). For a multi-phase migration, chain branches and open a stacked draft PR per branch so reviewers can review incrementally, at the cadence agreed with the developer (see Before you start — default is one branch/PR per cohesive group of phases, not per commit). Keep the same prefix and extend the name (e.g. chore/v6-ideal-state, chore/v6-ideal-view).
old/ package)old/ package. Move the matching v5 tests into the corresponding old/ test packages in the same commit.:module:check. Commit.XDetails : PaymentMethodDetails in core if it does not already exist.PaymentMethodTypes constant(s), then register the type(s) in PaymentMethodDetails.getChildSerializer → XDetails.SERIALIZER. Skipping this causes a runtime ClassCastException (it falls back to GenericDetails).XDetails through PaymentMethodDetails.SERIALIZER for every supported type, asserting the fields survive (this is the exact regression the fallback causes).:core:test; :core:apiCheck (XDetails is public — run :core:apiDump only if the API change is intentional and commit the .api file). Commit.CheckoutParams values (e.g. shopperLocale) straight to the state factory, as MBWay does.XComponentParams and XComponentParamsMapper (CheckoutParams + PaymentMethod + config → params).:module:test. Commit.XComponentState, XComponentStateFactory (initial state), XIntent (sealed updates), XComponentStateReducer (intent → state), XComponentStateValidator, XPaymentComponentState, and the toPaymentComponentState() extension.TextInputViewState (value + focus + error), add update/focus intents, and a HighlightValidationErrors intent that submit() dispatches when the state is invalid (see MBWay/Card).:module:test. Commit.XViewState and XViewStateProducer (component state → UI model); map validation results to localized error text using the shopper locale.:module:test. Commit.XContent: a wrapper that collects the view-state flow and hosts effects/launchers, delegating to a private pure-UI composable. Reuse shared composables from the ui module (ComponentScaffold, PayButton, input fields, ValuePickerField) instead of building from scratch.SecondaryContent composable (e.g. XSecondaryContent) to render the component's SecondaryScreenComponent.SecondaryContent() slot (see MBWay's picker).@Preview composables for the meaningful UI cases, not just one happy path — e.g. default/empty, loading, validation error, available vs unavailable, and any method-specific variants (light/dark via uiMode, RTL, different styles). Previews take the ViewState (or a small UI model) directly so each case is rendered in isolation.AGENTS.md and other payment methods for styles and strings.:module:check. Commit.XComponent : PaymentComponent wiring ComponentStateFlow(initialState, reducer, validator), viewState(producer), eventFlow, Content(), submit(), setLoading(), requiresUserInteraction(). For input methods, submit() validates first and dispatches HighlightValidationErrors when invalid instead of emitting Submit (see MBWay).SecondaryScreenComponent (SecondaryContent()) and emit PaymentComponentEvent.SecondaryScreen/CloseSecondaryScreen to open/close it.AnalyticsManager/GenericEvents (submit and error events, render where applicable and other analytics events which were already firing on v5).XFactory : PaymentComponentFactory<XComponent>.XInitializer : Initializer<Unit> (@Keep) that registers the factory via PaymentMethodProvider.register(txVariant, factory) for each supported type, and wire it into the module AndroidManifest.xml under the androidx-startup InitializationProvider.:module:check; :module:apiCheck. Commit.StoredXComponent, StoredXComponentState + StoredXComponentStateFactory/Reducer/Validator, StoredXIntent, StoredXViewState + StoredXViewStateProducer, and StoredXContent.XFactory implement both PaymentComponentFactory<XComponent> and StoredPaymentComponentFactory<StoredXComponent> (two create() overloads). PaymentMethodProvider.register registers it under both the regular and stored maps automatically — no extra registration needed (see CardFactory).:module:check; :module:apiCheck. Commit.XConfiguration and the CheckoutConfiguration.x { } DSL extension. Everything else stays internal or @RestrictTo(LIBRARY_GROUP). Prefer abstract classes over sealed for merchant-facing when safety (see AGENTS.md).:module:apiDump and commit the .api files. Commit.CheckoutConfiguration.x { } config, plus a host Activity/screen if needed.android-check for the module and :core (compile, lint, unit tests, apiCheck).android-pr-create skill, following the cadence agreed during planning (earlier phase groups may already have open PRs). Use a checklist covering: serializer registration, tests per layer, v5 preserved under old/, public API reviewed, styles/strings, stored variant + secondary screen (if applicable), and example wiring.android-commit. PRs do not have to be per commit — group cohesive phases into stacked draft PRs (android-branch-create + android-pr-create), and agree the per-phase vs per-group cadence with the developer during planning.PaymentMethodDetails.getChildSerializer.internal. Only the configuration/DSL is public. Discuss any breaking change before proceeding.