Skip to content

fix: stop registration leaving accounts nobody can use - #26

Merged
duuyguyiilmaz merged 1 commit into
mainfrom
fix/half-created-accounts
Sep 1, 2026
Merged

duuyguyiilmaz merged 1 commit into
mainfrom
fix/half-created-accounts

Conversation

@duuyguyiilmaz

Copy link
Copy Markdown
Owner

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 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

MainViewModel resolves the session on startup into signed-out, ready, or needs-profile. CompleteProfileActivity writes the missing document from the session's own uid and address, asking only for the department — the security rule compares the address against request.auth.token.email anyway, 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.

  • Rollback: the account is deleted when the profile write fails; nothing is deleted when the auth step itself failed; and when the rollback fails the user still sees the profile error.
  • Recovery: the write takes uid and address from the session rather than the request, a missing session writes nothing, a double tap saves one profile, a failed write leaves the screen usable.
  • Routing: the three-way startup decision, including the read-failure branch that must not be mistaken for an absent profile.

Rules suite unchanged at 107 green; lint clean.

🤖 Generated with Claude Code

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>
@duuyguyiilmaz
duuyguyiilmaz merged commit 1686e51 into main Sep 1, 2026
2 checks passed
@duuyguyiilmaz
duuyguyiilmaz deleted the fix/half-created-accounts branch September 1, 2026 17:51
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.

1 participant