Implement household domain with outside-in TDD (15 tests)
Controller (5 tests): create household, get mine, get members, create invite, accept invite. Service (10 tests): household creation with planner role + seed data (categories, tags, staple ingredients), conflict when already in household, invite code generation with 48h expiry, accept invite with expired/used/conflict validation. Also includes: - Household, HouseholdMember, HouseholdInvite JPA entities - HouseholdInvite repository with findByInviteCode - Ingredient, IngredientCategory, Tag entities + repositories (created early for seed data, will be extended in recipe domain) - Fixed BackendApplicationTests to use AbstractIntegrationTest Total: 38 tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.recipeapp.recipe;
|
||||
|
||||
import com.recipeapp.recipe.entity.IngredientCategory;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface IngredientCategoryRepository extends JpaRepository<IngredientCategory, UUID> {
|
||||
List<IngredientCategory> findByHouseholdIdOrderBySortOrder(UUID householdId);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.recipeapp.recipe;
|
||||
|
||||
import com.recipeapp.recipe.entity.Ingredient;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface IngredientRepository extends JpaRepository<Ingredient, UUID> {
|
||||
List<Ingredient> findByHouseholdId(UUID householdId);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.recipeapp.recipe;
|
||||
|
||||
import com.recipeapp.recipe.entity.Tag;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface TagRepository extends JpaRepository<Tag, UUID> {
|
||||
List<Tag> findByHouseholdId(UUID householdId);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.recipeapp.recipe.entity;
|
||||
|
||||
import com.recipeapp.household.entity.Household;
|
||||
import jakarta.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ingredient")
|
||||
public class Ingredient {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "household_id", nullable = false)
|
||||
private Household household;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "citext")
|
||||
private String name;
|
||||
|
||||
@Column(name = "is_staple", nullable = false)
|
||||
private boolean isStaple;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "category_id")
|
||||
private IngredientCategory category;
|
||||
|
||||
protected Ingredient() {}
|
||||
|
||||
public Ingredient(Household household, String name, boolean isStaple) {
|
||||
this.household = household;
|
||||
this.name = name;
|
||||
this.isStaple = isStaple;
|
||||
}
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public Household getHousehold() { return household; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public boolean isStaple() { return isStaple; }
|
||||
public void setStaple(boolean staple) { isStaple = staple; }
|
||||
public IngredientCategory getCategory() { return category; }
|
||||
public void setCategory(IngredientCategory category) { this.category = category; }
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.recipeapp.recipe.entity;
|
||||
|
||||
import com.recipeapp.household.entity.Household;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ingredient_category")
|
||||
public class IngredientCategory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "household_id", nullable = false)
|
||||
private Household household;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "citext")
|
||||
private String name;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
private short sortOrder;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
protected IngredientCategory() {}
|
||||
|
||||
public IngredientCategory(Household household, String name, short sortOrder) {
|
||||
this.household = household;
|
||||
this.name = name;
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
void onCreate() { createdAt = Instant.now(); }
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public Household getHousehold() { return household; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public short getSortOrder() { return sortOrder; }
|
||||
public void setSortOrder(short sortOrder) { this.sortOrder = sortOrder; }
|
||||
public Instant getCreatedAt() { return createdAt; }
|
||||
}
|
||||
46
backend/src/main/java/com/recipeapp/recipe/entity/Tag.java
Normal file
46
backend/src/main/java/com/recipeapp/recipe/entity/Tag.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.recipeapp.recipe.entity;
|
||||
|
||||
import com.recipeapp.household.entity.Household;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "tag")
|
||||
public class Tag {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "household_id", nullable = false)
|
||||
private Household household;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "citext")
|
||||
private String name;
|
||||
|
||||
@Column(name = "tag_type", nullable = false, length = 20)
|
||||
private String tagType;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
protected Tag() {}
|
||||
|
||||
public Tag(Household household, String name, String tagType) {
|
||||
this.household = household;
|
||||
this.name = name;
|
||||
this.tagType = tagType;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
void onCreate() { createdAt = Instant.now(); }
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public Household getHousehold() { return household; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getTagType() { return tagType; }
|
||||
public Instant getCreatedAt() { return createdAt; }
|
||||
}
|
||||
Reference in New Issue
Block a user