Skip to content

Release: develop -> main#3753

Merged
TaprootFreak merged 4 commits into
mainfrom
develop
May 23, 2026
Merged

Release: develop -> main#3753
TaprootFreak merged 4 commits into
mainfrom
develop

Conversation

@github-actions
Copy link
Copy Markdown

Automatic Release PR

This PR was automatically created after changes were pushed to develop.

Commits: 1 new commit(s)

Checklist

  • Review all changes
  • Verify CI passes
  • Approve and merge when ready for production

…GISTERED status (#3733)

* feat(user/realunit): expose user capabilities + structured ALREADY_REGISTERED status

Wave 3 of the realunit-app API-as-Decision-Authority plan
(`DFXswiss/realunit-app:docs/api-authority-plan.md`). Two changes that let
the realunit-app stop interpreting backend state into UI affordances:

UserV2Dto.capabilities
----------------------

New `UserCapabilitiesDto` field on the `/v2/user` response. Surfaces
per-action flags the realunit-app cubits were re-deriving locally from
KYC step status (`settings_user_data_page.dart:239`,
`settings_edit_name_cubit.dart:22`, `settings_contact_page.dart:54-67`):

- `canEditName` / `canEditAddress`: false once PersonalData is in any
  review or completed state (data is locked to keep client and KYC
  attestation aligned).
- `canEditMail` / `canEditPhone`: false only on KYC-terminated accounts.
- `supportAvailable`: requires a verified mail.

`UserDtoMapper.computeCapabilities` mirrors the rules the cubits encode
today. A separate app-side PR consumes the field and drops the local
interpretation.

RealUnitRegistrationStatus.ALREADY_REGISTERED
---------------------------------------------

New enum value. `completeRegistration` and `completeRegistrationForWalletAddress`
return it instead of throwing `BadRequestException` when the wallet is
already registered for the user. The realunit-app currently catches the
400 and treats it as a success — surfacing the success as a structured
status removes the "papering over an error" pattern and lets the app
distinguish the merge / retry path cleanly from other 400s.

Backwards compatibility
-----------------------

Both changes are additive. Old clients ignore the new `capabilities`
field and continue to derive editability locally. The `ALREADY_REGISTERED`
status is a new enum value — existing clients that switch-fall-through
will treat it the same as `FORWARDING_FAILED` (no behaviour change worse
than a generic failure).

Tests
-----

- `user-dto.mapper.spec.ts` adds a `mapUser: capabilities` block covering
  all five flags across happy path, PersonalData-locked, KYC-terminated,
  and no-mail fixtures.
- Existing tests cover the two `return RealUnitRegistrationStatus.ALREADY_REGISTERED`
  call sites by absence of any new throw (`completeRegistration` /
  `completeRegistrationForWalletAddress` did not have happy-path tests for
  the already-registered branch; PR #3731 addresses the idempotency
  semantics in the same area and adds dedicated coverage).

Local verification
------------------

- `npm run type-check` — clean
- `npm run lint` — clean
- `npm test` — **943 / 943 passing**

* style: prettier

* fix(realunit): return 201 for ALREADY_REGISTERED like COMPLETED

ALREADY_REGISTERED fell through to 202 ACCEPTED. The idempotent retry
path returned 201 before (via COMPLETED); keep the HTTP status stable
and let the structured status field carry the distinction.

---------

Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
TaprootFreak and others added 3 commits May 22, 2026 14:44
* feat(realunit): add DEV-only request/response tracing

Adds an Express middleware that logs full request/response detail for
calls originating from the realunit-app, scoped via the X-Client header
or a /v{n}/realunit/* path. Active only in the DEV environment.

Secrets (auth header, JWT tokens, signatures, credentials) are masked
and long string values truncated; KYC/PII bodies are kept intact for
the internal test phase. Output goes to stdout for container logs.

* feat(realunit): enable API tracing on PRD in addition to DEV

The internal testers run the mainnet app build, which talks to the PRD
API — DEV-only gating would capture nothing. Tracing now runs on both
DEV and PRD. On PRD this writes real customer KYC/PII to the container
logs by design (secrets stay masked).
* feat(support): add support issue templates (DEV-4571)

* fix(support): allow clearing english template content

* fix(support): rename template content column to contentDe

* fix: migrate support issue template to PostgreSQL

- Entity: length 'MAX' → type 'text'
- Migration: regenerated with PostgreSQL syntax

---------

Co-authored-by: David May <david.leo.may@gmail.com>
…nts can stop re-implementing routing locally (#3732)

* feat(kyc): expose decision fields so clients can stop re-implementing routing locally

The realunit-app's `KycCubit` (`lib/screens/kyc/cubits/kyc/kyc_cubit.dart`)
was rebuilding the API's own routing rule client-side: a hardcoded
`_requiredStepNames` set, an `actionableStatuses` set, and a
`_minLevelForActions = 30` threshold. That setup misroutes any high-level
user whose Ident step has been re-issued by `checkDfxApproval` (2026-05-21
incident — user_data 338759, kycLevel 53 + Outdated Ident + InProgress
Ident@seq 1 → app stuck on KycIdentPage).

The app shouldn't be deciding that. Surface the three signals it needs
directly in the DTOs so it can render verbatim:

- `KycStepDto.isRequired: boolean` — populated from
  `requiredKycSteps(userData)` at mapping time. Clients drop their own
  duplicate sets and iterate `kycSteps.filter(s => s.isRequired)` instead.
- `UserKycDto.canTrade: boolean` (`/v2/user`) — authoritative
  trading-permission flag, computed from kycLevel + required-step
  completion + non-blocking Ident/FinancialData state. A level-50 user with
  an Outdated Ident now correctly reports `canTrade: false`.
- `KycLevelDto.processStatus: KycProcessStatus`
  (`InProgress | PendingReview | Completed | Failed`) — high-level KYC
  process state for clients that don't need step granularity.

All additions are optional / nullable-shaped on the wire: existing clients
keep working, new clients consume the new fields and delete their local
logic in the matching app-side PR.

Mapper-side change in one spot:

- `KycInfoMapper.toDto` computes `requiredStepNames` once and threads it
  through `KycStepMapper.toStep(..., isRequired)` + the new
  `computeProcessStatus` helper. `KycStepMapper.toStep` gains a
  third (optional) `isRequired` parameter — defaulted to `false` so the
  ~hundred existing call sites compile unchanged.
- `UserDtoMapper.computeCanTrade` mirrors the cubit's routing semantics
  exactly (level ≥ LEVEL_30 + all required steps Completed + no
  Outdated/InProgress/OnHold Ident or FinancialData step). Comment links
  back to the app-side `docs/api-authority-plan.md` Wave 2.

Tests:

- `user-dto.mapper.spec.ts` adds a fixture-based regression block that
  reproduces the 2026-05-21 user_data 338759 shape (level 50 + completed
  Ident + outdated Ident + in-progress Ident@seq 1 → `canTrade: false`)
  and the surrounding cases (clean level 50, level 20, outdated
  FinancialData, terminated KYC).
- `new ConfigService()` in `beforeAll` to wire the `Config` singleton
  for sub-LEVEL_50 `tradingLimit` resolution.

Local verification:

- `npm run type-check` — clean
- `npm run lint` — clean
- `npm test` — **943 / 943 passing** (5 new tests; 938 baseline kept green)

Wave 2.1 of the realunit-app API-as-Decision-Authority plan
(`DFXswiss/realunit-app:docs/api-authority-plan.md`).

* style: prettier

* fix(kyc): address review feedback on decision fields

- Make requiredStepNames a required param in KycStepMapper.toStep so no
  caller can silently omit it and default every step to isRequired=false
- Add FINISHED, PARTIALLY_APPROVED, PAUSED to computeProcessStatus
  pending set — they were falling through to Completed
- Simplify computeCanTrade to match actual trade-endpoint gates
  (level >= 30, not terminated, not blocked) instead of duplicating
  stricter step-status logic the endpoints don't enforce
- Update @ApiProperty doc and tests accordingly

* fix: remove stale comment on computeCanTrade

* fix(kyc): move DATA_REQUESTED to pending set in computeProcessStatus

Aligns with isInReview on the KYC step entity. A step in
DataRequested is waiting, not user-actionable.

* fix(kyc): remove canTrade field

Not used by any client. The app routes on processStatus + isRequired;
the trade endpoints themselves are the authority for whether a request
succeeds.

* test(kyc): cover computeProcessStatus and isRequired

Add a kyc-info.mapper spec exercising the processStatus verdict
(terminated, not-started, in-review, actionable, DataRequested and the
multi-sequence ident shape) and the isRequired step flag. The canTrade
removal had dropped the only tests this PR carried.

---------

Co-authored-by: David May <david.leo.may@gmail.com>
Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
@TaprootFreak TaprootFreak merged commit 4850226 into main May 23, 2026
14 checks passed
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.

3 participants