Follow-up to RED-1 (#371 / PR #373). Filed so the regression that PR
introduces is accepted knowingly rather than discovered by a user.
Problem
RED-1 stops getOrCreateMerchantConfig from auto-creating a merchant config for
users who are not enrolled providers, which is correct: reading settings should
not silently publish someone as a cash provider. The service now throws
BadRequestError for provider_status = 'not_enrolled', and the migration
backfills every existing user to that state.
The retail app has no concept of enrollment yet, so the merchant settings screen
simply breaks. MerchantSettings.tsx:36-57 loads getMerchantConfig() and
getCurrentUser() together in one Promise.all, catches whatever fails and
renders a generic error string. After RED-1 lands, every non-enrolled user
opening Ajustes gets that error and an empty form, with nothing telling them
enrollment exists or how to start it.
The same 400 reaches updateMerchantConfigWithOfflineSupport
(api.ts:548-556) and the offline queue's direct fetch('/merchants/me/config')
(offlineQueueManager.ts:74).
Why this is a separate issue
The proper fix is the provider onboarding UI, which is RED-2, and RED-2 sits
behind RED-3, KYC-1 and CASH-7 in the queue. That is a long time to leave a
screen erroring. This issue is the smaller, unblocked piece: make the app
explain the state instead of failing into a generic error, without waiting for
the full onboarding flow.
In scope
- Represent "not an enrolled provider" as a first-class state in the merchant
settings screen, distinct from a network or server failure.
- Show what the state means and what the user would gain from enrolling, in
plain language, per docs/UX_MANIFESTO.md.
- Stop
MerchantSettings.tsx from collapsing both requests into one anonymous
failure: a 400 from the config endpoint is a known state, not an error toast.
- Do not queue config mutations offline for a user the backend will reject
anyway (offlineQueueManager.ts:74).
- Replace the read of the nonexistent
verification_status field
(MerchantSettings.tsx:44) with the real provider_status / availability
the backend now returns.
Out of scope
- The enrollment flow itself, its screens and its KYC steps — that is RED-2.
- Calling
POST /providers/enroll from the app. A link or a disabled
"próximamente" affordance is enough here; wiring the action belongs with RED-2.
- Any backend change. RED-1 owns the backend contract.
Source ownership at 312e921
| Range |
This issue owns |
micopay/frontend/src/pages/MerchantSettings.tsx:30-57 |
load path and the not-enrolled state |
micopay/frontend/src/pages/MerchantSettings.tsx:44 |
replacing verification_status with the real fields |
micopay/frontend/src/services/offlineQueueManager.ts:74 |
not queueing mutations that will be rejected |
Do not change micopay/backend/src/services/merchant.service.ts or the
/providers/* routes; RED-1 owns those.
Acceptance criteria
Dependencies
Blocked on #373 (RED-1) merging — the backend contract has to exist first.
Superseded in part by RED-2 when that lands.
Campaign
Not labelled for Drips by default. Campaign eligibility follows the same review
as the rest of the 2026-08-26 queue (docs/AUDITORIA_CASHOUT_AGENTE_2026-08-26.md §10).
Follow-up to RED-1 (#371 / PR #373). Filed so the regression that PR
introduces is accepted knowingly rather than discovered by a user.
Problem
RED-1 stops
getOrCreateMerchantConfigfrom auto-creating a merchant config forusers who are not enrolled providers, which is correct: reading settings should
not silently publish someone as a cash provider. The service now throws
BadRequestErrorforprovider_status = 'not_enrolled', and the migrationbackfills every existing user to that state.
The retail app has no concept of enrollment yet, so the merchant settings screen
simply breaks.
MerchantSettings.tsx:36-57loadsgetMerchantConfig()andgetCurrentUser()together in onePromise.all, catches whatever fails andrenders a generic error string. After RED-1 lands, every non-enrolled user
opening Ajustes gets that error and an empty form, with nothing telling them
enrollment exists or how to start it.
The same 400 reaches
updateMerchantConfigWithOfflineSupport(
api.ts:548-556) and the offline queue's directfetch('/merchants/me/config')(
offlineQueueManager.ts:74).Why this is a separate issue
The proper fix is the provider onboarding UI, which is RED-2, and RED-2 sits
behind RED-3, KYC-1 and CASH-7 in the queue. That is a long time to leave a
screen erroring. This issue is the smaller, unblocked piece: make the app
explain the state instead of failing into a generic error, without waiting for
the full onboarding flow.
In scope
settings screen, distinct from a network or server failure.
plain language, per
docs/UX_MANIFESTO.md.MerchantSettings.tsxfrom collapsing both requests into one anonymousfailure: a 400 from the config endpoint is a known state, not an error toast.
anyway (
offlineQueueManager.ts:74).verification_statusfield(
MerchantSettings.tsx:44) with the realprovider_status/availabilitythe backend now returns.
Out of scope
POST /providers/enrollfrom the app. A link or a disabled"próximamente" affordance is enough here; wiring the action belongs with RED-2.
Source ownership at
312e921micopay/frontend/src/pages/MerchantSettings.tsx:30-57micopay/frontend/src/pages/MerchantSettings.tsx:44verification_statuswith the real fieldsmicopay/frontend/src/services/offlineQueueManager.ts:74Do not change
micopay/backend/src/services/merchant.service.tsor the/providers/*routes; RED-1 owns those.Acceptance criteria
a generic error message.
on screen.
verification_statusno longer appears in the frontend.Dependencies
Blocked on #373 (RED-1) merging — the backend contract has to exist first.
Superseded in part by RED-2 when that lands.
Campaign
Not labelled for Drips by default. Campaign eligibility follows the same review
as the rest of the 2026-08-26 queue (
docs/AUDITORIA_CASHOUT_AGENTE_2026-08-26.md§10).