feat(flipcash): wire SetUsername through the profile service layer - #1320
Merged
Conversation
Adds the Profile service's SetUsername RPC with its request and response messages. Vendored from flipcash2-protobuf-api at HEAD; opencode was already current.
Adds the Api, Service, Repository, and Controller methods for the new SetUsername RPC, following the setDisplayName chain. On success the controller merges the username into the locally cached profile so observers see it without waiting for a refresh. SetUsernameError covers each non-OK result: InvalidUsername, Denied, AlreadyTaken, FailedModerated (carrying the flagged category), InsufficientBalance, ReservedWord, plus Unrecognized and Other. InternalProfileRepository skips ErrorUtils.handleError for the results that are the server answering a user's choice of handle rather than a fault — InvalidUsername, AlreadyTaken, ReservedWord, FailedModerated, InsufficientBalance. setDisplayName gets the same treatment for InvalidDisplayName and FailedModerated; its only caller, NameEntryViewModel, already renders its own alert for every failure, so this drops a duplicate report path rather than user-facing feedback.
bmc08gt
added a commit
that referenced
this pull request
Aug 24, 2026
* chore(protos): update flipcash protobuf definitions Adds UserFlags.username_min_balance, the USDF amount in quarks a user must hold across all currencies before setting a username. Vendored from flipcash2-protobuf-api at HEAD; opencode was already current. * feat(userflags): surface the username minimum balance flag Maps UserFlags.username_min_balance through to the domain model and the debug flag editor as a read-only entry. It gates the username claim flow added in #1320, which has no UI yet, so nothing reads it so far. The default is Fiat.Zero rather than Fiat.MAX_VALUE. This is a minimum balance to hold, like minimumHolderValue, not a price to pay like newCurrencyPurchaseAmount. An absent flag should leave the gate open and let the server answer with INSUFFICIENT_BALANCE, not hard-block a claim the server would have allowed. CachedFlags also carries the field, since its toDomain() reconstructs the whole UserFlags. It defaults to zero quarks so payloads cached before this change still decode -- UserFlagsCoordinator drops the entire cached flag set when decodeFromString fails, so an undefaulted field would blank the flags on the first launch after upgrade. ReadOnlyEntry holds a Boolean, so the amount goes in readOnlyTextEntries formatted with Fiat.FormattingRule.Truncated, matching WithdrawalFeeAmount.
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.
The Profile service gained a
SetUsernameRPC upstream. This vendors the proto change and builds out the write path;UserProfile.usernameand the read path already landed in #1316.Proto
profile/v1/profile_service.proto—SetUsername(SetUsernameRequest) → SetUsernameResponse, re-vendored fromflipcash2-protobuf-apiat HEAD.opencodewas already current. The responseResultenum isOK,INVALID_USERNAME,DENIED,ALREADY_TAKEN,FAILED_MODERATED,INSUFFICIENT_BALANCE,RESERVED_WORD, withflagged_categoryset only onFAILED_MODERATED.Service layer
Api → Service → Repository → Controller, following the existing
setDisplayNamechain (closest analogue: same auth, same moderation-category shape).ProfileController.setUsernamemerges the new handle into the locally cached profile on success, so anything observing the profile — a setup flow deciding which steps remain, for instance — sees it without waiting for a refresh.SetUsernameErrorhas a case per non-OK result.UnrecognizedandOtherareNotifiableError; the rest are not.No Hilt changes —
ProfileRepositoryis already bound inFlipcashModule.Error reporting change to
setDisplayNameInternalProfileRepository.setUsernameskipsErrorUtils.handleErrorfor the five results that represent the server answering a user's choice of handle rather than a fault:InvalidUsername,AlreadyTaken,ReservedWord,FailedModerated,InsufficientBalance.AlreadyTakenin particular will be routine once a claim UI exists, and routing it through error tracking would be noise.setDisplayNamenow does the same forInvalidDisplayNameandFailedModerated, so the two paths behave alike. This is a behavior change to existing code: those two cases previously reachedErrorUtils.handleError, which drives aTopBarManagertoast whenisDisplayErrorsis on, alongside the Bugsnag report. Its only caller,NameEntryViewModel, already handles every failure itself — a per-category alert forFailedModeratedand a catch-allelse— so what this removes is a duplicate report, not the user's feedback.Denied,Unrecognized, andOtherstill report on both paths.Not included
No UI. Nothing calls
ProfileController.setUsernameyet — this is the plumbing for a username-claim flow, andINSUFFICIENT_BALANCEsuggests that flow will need a price and a payment step to design against.