diff --git a/BACKLOG.md b/BACKLOG.md index d570c98..1a44d35 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -20,6 +20,13 @@ Prerequisite for the product catalog and unit catalog work — both rely on a `F - **JWT refresh tokens.** Today's tokens are signed with HS256 and (per `Program.cs`) likely have no refresh path; they expire and the user gets bounced to login. Add refresh tokens with rotation + revocation list. - **Account deletion / data export.** GDPR-style request handling. Family-scoped: deleting a user shouldn't delete the family's data, but should redact PII. - **Rate limiting on `/api/auth/register` and `/api/auth/login`.** Currently unlimited — with multi-family this becomes a real abuse vector. +- **Email-based invites (admin-sent) doubling as email confirmation.** Today the `InviteCode` is a shareable secret an admin distributes out-of-band; new users self-register with it and there's no proof they own a real email address. Build an invite flow where a family admin enters an email, the backend issues a single-use, time-limited invite token and sends a templated email containing a join link. Clicking the link drops the user into a registration form pre-bound to that family + email; on submit, both the invite is consumed and the email is marked confirmed in one step (no second "confirm your email" round-trip needed). Implications: + - New table for invites: `(Id, FamilyId, Email, TokenHash, IssuedByUserId, IssuedAt, ExpiresAt, ConsumedAt, ConsumedByUserId)`. Hash the token (don't store raw) so a DB leak doesn't leak active invites. + - `User` gains an `Email` (unique) and `EmailConfirmedAt` column. Migration backfill: existing users have null email until they (or an admin) attach one. + - SMTP infrastructure shared with the password-reset item above — design both together; same templating, same rate limits, same outbound queue if we add one. + - Admin UI on `/family`: list pending invites, resend, revoke. Pair with the existing role/membership management. + - Keep the old `InviteCode` flow available initially (or as an admin-only "generate shareable code" fallback) so we don't strand families that prefer the link-share workflow. Revisit deprecation once email invites are battle-tested. + - Open question: do we allow registering without an invite at all once email invites land? Recommend yes-for-now (existing `InviteCode` path stays) so this can ship incrementally. ### Real-time conflict resolution - The deferred SignalR-versioning plan in memory addresses connect-window races. It does **not** address edit conflicts (two family members renaming the same store, unchecking-then-checking the same item simultaneously).