Repository navigation
fix: stop registration leaving accounts nobody can use - #26
Merged
Merged
Conversation
Registration writes to two systems: a Firebase Auth account, then a Firestore profile. Only the first was durable. If the profile write failed, the account stayed — and an account without a profile is a dead end. The person is registered as far as Firebase is concerned, so they cannot sign up again with that address; and every screen needs the profile, so the feed stays locked, upload has no department to file under, and the profile tab is blank. There is no way out from inside the app. Two changes, because one is not enough. **The account is rolled back.** `RegisterViewModel` deletes the auth account it just created when the profile write fails. The rollback swallows its own errors: if deleting fails too, the message the user sees does not change, because from where they stand the outcome is identical — registration did not happen. What changes is that the account is still there, and that is what the second half is for. **A session with no profile is routed to a recovery screen.** `MainViewModel` resolves the session on startup into signed-out, ready, or needs-profile, and `CompleteProfileActivity` writes the missing document from the session's own uid and address — asking only for the department, since the security rule compares the address against `request.auth.token.email` anyway and a client-supplied one would be refused. "Cannot read the profile" and "there is no profile" are deliberately not the same branch. A dropped connection must not push someone into a screen where they cannot write either, so a read failure lets the app open normally and the existing per-screen retry messages handle it. This was not hypothetical: an account created earlier in this session for verification turned out to have no profile document, and it was recovered through this exact screen on the device — routed automatically on launch, department chosen, profile written, app opened. Why the original write left no document was not established; the logcat from that run had been cleared. That is itself the argument for the recovery screen rather than the rollback alone. Tests: 126 -> 139. The rollback, the rollback failing, and the auth step failing with nothing to roll back; the recovery ViewModel's write, missing session, double tap and failed write; and the three-way startup route including the read-failure branch that must not be mistaken for an absent profile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Registration writes to two systems: a Firebase Auth account, then a Firestore profile. Only the first was durable.
If the profile write failed, the account stayed — and an account without a profile is a dead end. The person is registered as far as Firebase is concerned, so they cannot sign up again with that address; and every screen needs the profile, so the feed stays locked, upload has no department to file under, and the profile tab is blank. There is no way out from inside the app.
Two changes, because one is not enough.
The account is rolled back
RegisterViewModeldeletes the auth account it just created when the profile write fails. The rollback swallows its own errors deliberately: if deleting fails too, the message the user sees does not change, because from where they stand the outcome is identical — registration did not happen. What changes is that the account is still out there, and that is what the second half is for.A session with no profile is routed to a recovery screen
MainViewModelresolves the session on startup into signed-out, ready, or needs-profile.CompleteProfileActivitywrites the missing document from the session's own uid and address, asking only for the department — the security rule compares the address againstrequest.auth.token.emailanyway, so a client-supplied one would be refused."Cannot read the profile" and "there is no profile" are deliberately different branches. A dropped connection must not push someone into a screen where they cannot write either, so a read failure lets the app open normally and the existing per-screen retry messages handle it.
This was not hypothetical
An account created earlier in this session for verification turned out to have no profile document — a real half-account in the live project. It was recovered through this exact screen on the device: routed automatically on launch, department chosen, profile written, app opened, confirmed in Firestore.
Why the original write left no document was not established — the logcat from that run had been cleared. That is itself the argument for the recovery screen rather than the rollback alone: the rollback only helps when you know the write failed.
Tests
126 → 139.
Rules suite unchanged at 107 green; lint clean.
🤖 Generated with Claude Code