docs: reorder & testing

This commit is contained in:
Ilia Denisov
2026-05-07 00:58:53 +03:00
committed by GitHub
parent f446c6a2ac
commit 604fe40bcf
148 changed files with 9150 additions and 2757 deletions
+1 -1
View File
@@ -18,5 +18,5 @@ Primary references:
- [`../openapi.yaml`](../openapi.yaml) — REST contract.
- [`../PLAN.md`](../PLAN.md) — historical staged build-up; kept for
archaeology, not as a source of truth.
- [`../../ARCHITECTURE.md`](../../ARCHITECTURE.md) — workspace-level
- [`../../docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) — workspace-level
architecture.
+24 -6
View File
@@ -2,7 +2,7 @@
This document collects the multi-step interactions inside `backend`
that span domain modules. Each section assumes the reader is familiar
with `../README.md` and `../../ARCHITECTURE.md`.
with `../README.md` and `../../docs/ARCHITECTURE.md`.
## Registration (send + confirm)
@@ -39,11 +39,29 @@ sequenceDiagram
Gateway-->>Client: 200 {device_session_id}
```
Re-confirming the same `challenge_id` returns the existing session and
clears the throttle window (the throttle reuses the latest un-consumed
challenge rather than dropping the request). `accounts.user_name` is
synthesised once and never overwritten on subsequent sign-ins; the same
account always lands the same handle.
A `challenge_id` is single-use: confirm consumes the row in the same
transaction that inserts the device session, so a second confirm-email-code
on the same id returns `400 invalid_request` (`auth.ErrChallengeNotFound`)
together with unknown and expired ids. The opaque error code is
deliberate — the API never differentiates "consumed", "expired", and
"never existed" so an attacker cannot mine challenge_id state.
Throttle reuses the latest un-consumed challenge rather than dropping
the request: send-email-code returns the existing `challenge_id` to a
caller hitting the throttle, leaving the wire shape identical to a
fresh issue.
`accounts.permanent_block` is checked twice on the registration path:
once in send-email-code (no fresh challenge for an already-blocked
address) and once in confirm-email-code after the verification code has
matched (catches the case where an admin applied the block in the
window between the two calls). Both paths surface
`auth.ErrEmailPermanentlyBlocked` and the handler maps it to `400
invalid_request` with message `email is not allowed`.
`accounts.user_name` is synthesised once at first sign-in and never
overwritten on subsequent sign-ins; the same account always lands the
same handle.
## Authenticated request lifecycle