Release: develop -> main#3771
Merged
Merged
Conversation
All hummingbot Azure container instances have been stopped (dev: 4, prd: 3). Updated README to reflect current state.
…aracter set (#3766) * fix(user-data): preserve UTF-8 umlauts in name and address fields Names and addresses entered via KYC personal-data, name-change, and address-change flows were ASCII-transliterated before persistence (Rüttimann -> Ruttimann, Münchwilen -> Munchwilen), causing PDFs and mails to render without umlauts. The user_data columns are NVARCHAR/character-varying since 2022 and support UTF-8 natively. The transliteration in UserDataService was introduced in #1910 and copied into #3373 and #3376 without a documented external constraint requiring ASCII storage. Comparison call sites (Util.isSameName / Util.removeSpecialChars) already normalise diacritics at compare time, and the realunit BitBox path uses its own toBitboxAscii helper on-the-fly. Storing the originals preserves information for downstream consumers (PDF, mail, support) at no cost to the matching pipelines. Realunit isPersonalDataMatching now transliterates both sides so legacy rows (still ASCII in the DB) continue to match alongside new UTF-8 rows. * feat(user-data): restrict personal fields to Swiss payment character set Add @IsSwissPaymentText() validator on every user-supplied name and address field that lands in user_data. Inputs containing characters outside the SIX SIG IG QR-Bill v2.3 permitted character set (printable ASCII plus the Latin diacritics for the four Swiss national languages) are rejected with 400 BadRequestException. Pairs with the umlaut-preservation fix: now that diacritics survive, we also prevent CJK/Cyrillic/Arabic/emoji input from reaching the DB, where Helvetica/WinAnsi PDF rendering would produce empty .notdef boxes. Validation is restricted to the user-facing input layer (KycPersonalData, KycChangeNameData, KycAddress, UserNameDto); KYC ident-result imports from SumSub/IDnow are unchanged because those providers already deliver Latin names. Validator follows the existing IsDfxPhone pattern (regex held in Config.formats.swissPaymentText, accessed at validate-time) to avoid the let-Config initialisation order issue at decorator evaluation. Existing rows are not re-validated.
…#3772) * feat(user): add createSupportTicket capability with prerequisite hint Narrow follow-up after #3767 was closed. That PR proposed a structured ActionCapability tree (170 LOC, 4 new DTOs, HttpMethod enum); @davidleomay correctly pointed out the endpoint paths are static and belong in Swagger docs, not on every /v2/user response. Pure-error pattern (his alternative suggestion) doesn't fit the actual UX requirement: the realunit-app needs to gate the support tile's tap *before* opening the ticket form, so the user is routed to the email capture step first — a post-submit 400 means the user fills the form for nothing. The middle ground here: - `UserCapabilitiesDto.createSupportTicket: { available, missingPrerequisite? }` — per-user runtime info only. The available flag and the missing- prerequisite discriminator are derived server-side from `userData.mail`. No endpoint paths in the response — those stay in Swagger. - `MissingPrerequisite` is a closed enum (`Email`, `Phone`). The app maps the value to the matching capture flow; the backend owns *which* prerequisite blocks the action, the app owns *how* the prerequisite is rendered. That's where API-as-Decision-Authority draws the line. - Mapper returns a discriminated union (`{ available: true } | { available: false; missingPrerequisite }`) so the compiler pins `!available implies missingPrerequisite defined`. The DTO class stays for Swagger schema generation (NestJS decorators don't model TS unions cleanly). - `@ApiBadRequestResponse` decorator added on `POST /v1/support/issue` per @davidleomay's review — Swagger docs now name the email-prerequisite remediation path. Description deliberately not narrowed to the email case so other 400 causes (DTO validation, etc.) remain covered. Backwards-compatible: `createSupportTicket?` is optional on the schema (`@ApiPropertyOptional`) so client SDKs pinned to older API versions ignore the new field. Other UserCapabilities flags untouched. ## Tests `user-dto.mapper.spec.ts` gains 4 fixtures: mail present, mail null, mail empty string, mail undefined. The empty-string and undefined cases pin the JS-truthy semantics so a future drift in `support-issue.service`'s gate is caught. - type-check: clean - lint: clean - prettier: clean - jest: 944 / 944 passing (940 baseline + 4 new tests) * refactor: drop unused MissingPrerequisite.PHONE YAGNI: the mapper only emits 'Email'. Add 'Phone' (or any other prerequisite) when a backend gate actually requires it — the enum extension would be additive and backwards-compatible. Addresses @davidleomay's review comment on PR #3772.
Synthesised from the #3733 → #3761 → #3767 → #3772 review sequence with @davidleomay. New section under "API Design" makes the eight rules binding for every future capability flag: 1. Heterogeneous capabilities — bool for hide-able, struct for discoverable 2. Static info belongs in Swagger, not in /user response 3. YAGNI for enum members and optional fields 4. Discriminated union for compiler-enforced invariants 5. Pre-tap signal for discoverable actions 6. Pair-PR with a documented trade-off 7. Backend owns business rules; client only maps types to UI 8. Reduction before extension — test the UX requirement first Cross-references the consumer-side mirror in DFXswiss/realunit-app's CONTRIBUTING.md and the api-authority-plan.md roll-out document. Pure documentation — no code changes.
Call `store` on the Monero wallet RPC after each `createAddress` call to flush subaddresses to disk. Without this, subaddresses created via RPC can be lost on wallet container restart, silently dropping deposits.
… PSQL migration (#3776) The PSQL migration prefixed bare column references with the query builder alias but did not add an explicit select alias. PostgreSQL getRawMany returns keys as alias_column (e.g. buyCrypto_usedRef) without one, so the ref array was always [undefined] and no user ref volume was updated.
davidleomay
approved these changes
May 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automatic Release PR
This PR was automatically created after changes were pushed to develop.
Commits: 1 new commit(s)
Checklist