First member into a family becomes Admin; subsequent members default to
Member. JWTs carry a family_role claim that is refreshed from the DB on
each request so promotions and demotions take effect immediately.
New /api/family endpoints let admins view the roster, regenerate the
invite code, change roles, and remove members. Last-admin and
self-removal guards prevent locking the family out of management.
The /family page exposes the same actions in the UI; the bottom nav now
links there. Members see the roster but not the invite code.
Existing deployments get a one-time backfill at startup: any family with
members but no admin gets its earliest-joined member promoted.
Adds FamilyMembership join (UserId, FamilyId, Role) and a non-null
FamilyId FK on Store, ShoppingList, ShoppingListItem, Recipe, and
RecipeIngredient. FamilyId is denormalized on items/ingredients so the
tenant filter is a single column predicate without joins. Store name
uniqueness is now scoped per family.
JWT issuance stamps a family_id claim; ClaimsPrincipalExtensions exposes
GetFamilyId(). Register validates the supplied invite code against
Family.InviteCode (replacing the env-var equality check) and writes a
FamilyMembership row. OnTokenValidated rejects requests whose user has
been removed from the claimed family since login.
Every endpoint filters by FamilyId on read and stamps it on write.
Cross-family storeId references on list create/update return 400. The
SignalR hub verifies list ownership on JoinList and uses a per-family
overview group, so cross-tenant fan-out is structurally impossible.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Set up YesChef.Api.UnitTests and YesChef.Api.IntegrationTests projects
running on TUnit + Microsoft.Testing.Platform. Integration tests use a
single Postgres 17 Testcontainer per session and clone a migrated
template database per test (`CREATE DATABASE … TEMPLATE …`) so tests
remain fully isolated and run in parallel without replaying migrations
each time.
Test-author DX is built around fluent entity builders, a TestDataFactory
for common scenarios, and a two-level base hierarchy
(IntegrationTest / AuthenticatedIntegrationTest) whose `[Before(Test)]`
hooks stand up the per-test database, app factory, default user, and
authenticated HttpClient — leaving each test body focused on the action
under test.
Adds src/backend/global.json to opt `dotnet test` into MTP mode on the
.NET 10 SDK, and updates CLAUDE.md with how to run the tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>