docs: record the sign-in code and preview behaviour still to build
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 47s
Forgejo Docker Build / Root app tests (push) Successful in 48s
Forgejo Android APK / Build signed APK (push) Successful in 1m59s
Forgejo Docker Build / Build Docker image (push) Successful in 14s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s

Both came out of using the app: the preview works but is all-or-nothing, and
signing in should be possible without a password without replacing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
Daniel 2026-09-11 02:42:07 +02:00
parent f735e2e910
commit a3dee83ac2

34
TODO.md
View file

@ -145,3 +145,37 @@ Worth doing before Kubernetes, roughly in order:
them and the compose should stay reviewable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## Sign-in by one-time code, alongside passwords
An option, not a replacement. An account keeps its password; the sign-in screen
offers "email me a code" as a second way in, and an account can use either.
- Reuse the invite machinery rather than inventing a second one: codes are
hashed at rest, single-use, short-lived, and claimed by one atomic UPDATE
carrying every condition, so two attempts at the same code cannot both win.
- Much shorter TTL than an invite — minutes, not days — and rate limited per
account and per IP, because a login code is a credential and an attacker can
ask for one without knowing the password.
- A code must never reveal whether the address has an account. The response is
the same either way.
- 2FA still applies on top where enabled: a code replaces the password step, not
the second factor.
## The signed-out preview, as it should behave
The preview works now, but it is currently all-or-nothing. Intended shape:
- Signed out with preview on, the assistant chat is visible and usable.
- Anything else — saved chats, images, settings — prompts sign-in rather than
failing. Today those simply 401.
- A cap of three questions per visitor, then an invitation to sign in. The cap
has to be enforced on the server: a preview visitor has no identity, so it
cannot be per-account, and a purely client-side count is worth nothing.
- Nothing is persisted for a preview visitor. That is already true and must
stay true — PREVIEW_USER has id: null precisely so nothing can be owned.
- If the visitor then signs in **in the same browser**, the preview
conversation is adopted into the new account and saved. This is the
interesting part: because preview deliberately has no identity, the transcript
has to be held client-side and replayed on the first authenticated request,
not looked up server-side. Size-cap it and drop it on sign-out.