9b2db931ee
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>
19 lines
685 B
C#
19 lines
685 B
C#
namespace YesChef.Api.Entities;
|
|
|
|
public class Recipe
|
|
{
|
|
public int Id { get; set; }
|
|
public int FamilyId { get; set; }
|
|
public Family Family { get; set; } = null!;
|
|
public required string Title { get; set; }
|
|
public string? Description { get; set; }
|
|
public string? Instructions { get; set; }
|
|
public int? Servings { get; set; }
|
|
public string? SourceUrl { get; set; }
|
|
public int CreatedByUserId { get; set; }
|
|
public User CreatedByUser { get; set; } = null!;
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
public List<RecipeIngredient> Ingredients { get; set; } = [];
|
|
}
|