Expand description
Use cases for the MagicLink feature (Story 3.2 — FR6, INV-13, INV-17).
Two operations:
MagicLinkUseCases::issue— a syndic issues a magic link bound to a(scope_kind, scope_id)+ recipient user. Returns the clear token ONCE.MagicLinkUseCases::validate_and_consume— the public/c/{token}endpoint hashes the incoming token, looks it up, validates it, and marks it consumed atomically. Returns the resolvedMagicLinkso the caller handler can fetch the underlying scope resource.
Security highlights:
- Clear token is generated inside
MagicLink::issueand returned to the handler. It is NEVER logged and NEVER re-fetched from DB. - Lookup uses
find_by_token_hash(sha256(token))— a forged token returnsNone→ translated toMagicLinkInvalid(uniform with “unknown token” to defeat enumeration). - Single-use enforced by
mark_consumed(race-safeUPDATE ... WHERE consumed_at IS NULLat the repository layer).