From 43227b226585ecaf1b2ec6c7800472d546ad35ec Mon Sep 17 00:00:00 2001 From: Marcel Raddatz Date: Fri, 10 Apr 2026 20:07:53 +0200 Subject: [PATCH] feat(backend): make invite share URL base configurable via app.base-url Replaces hardcoded \"https://yourapp.com\" with a Spring property. - application.yml: app.base-url defaults to http://localhost:5173 - application-docker.yml: reads APP_BASE_URL env var, same default - HouseholdService: injects @Value("${app.base-url}") and uses it in toInviteResponse() to build shareUrl - HouseholdServiceTest: sets field via ReflectionTestUtils in @BeforeEach; adds test asserting shareUrl starts with configured base URL Co-Authored-By: Claude Sonnet 4.6 --- .../recipeapp/household/HouseholdService.java | 6 ++++- .../src/main/resources/application-docker.yml | 3 +++ backend/src/main/resources/application.yml | 3 +++ .../household/HouseholdServiceTest.java | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/recipeapp/household/HouseholdService.java b/backend/src/main/java/com/recipeapp/household/HouseholdService.java index 678bf67..9328d50 100644 --- a/backend/src/main/java/com/recipeapp/household/HouseholdService.java +++ b/backend/src/main/java/com/recipeapp/household/HouseholdService.java @@ -17,6 +17,7 @@ import com.recipeapp.recipe.TagRepository; import com.recipeapp.recipe.entity.Ingredient; import com.recipeapp.recipe.entity.IngredientCategory; import com.recipeapp.recipe.entity.Tag; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -38,6 +39,9 @@ public class HouseholdService { private final TagRepository tagRepository; private final VarietyScoreConfigRepository varietyScoreConfigRepository; + @Value("${app.base-url}") + private String baseUrl; + private static final SecureRandom RANDOM = new SecureRandom(); private static final String CODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; @@ -262,7 +266,7 @@ public class HouseholdService { private InviteResponse toInviteResponse(HouseholdInvite invite) { return new InviteResponse( invite.getInviteCode(), - "https://yourapp.com/join/" + invite.getInviteCode(), + baseUrl + "/join/" + invite.getInviteCode(), invite.getExpiresAt()); } } diff --git a/backend/src/main/resources/application-docker.yml b/backend/src/main/resources/application-docker.yml index c0cb1ec..b293959 100644 --- a/backend/src/main/resources/application-docker.yml +++ b/backend/src/main/resources/application-docker.yml @@ -2,3 +2,6 @@ spring: flyway: locations: classpath:db/migration,classpath:db/seed out-of-order: true + +app: + base-url: ${APP_BASE_URL:http://localhost:5173} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 097c33a..6c98ef0 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -30,3 +30,6 @@ spring: server: port: 8080 + +app: + base-url: http://localhost:5173 diff --git a/backend/src/test/java/com/recipeapp/household/HouseholdServiceTest.java b/backend/src/test/java/com/recipeapp/household/HouseholdServiceTest.java index 9b00fbb..213825d 100644 --- a/backend/src/test/java/com/recipeapp/household/HouseholdServiceTest.java +++ b/backend/src/test/java/com/recipeapp/household/HouseholdServiceTest.java @@ -17,7 +17,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.junit.jupiter.api.BeforeEach; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; import java.time.Instant; import java.util.List; @@ -43,6 +45,11 @@ class HouseholdServiceTest { @InjectMocks private HouseholdService householdService; + @BeforeEach + void setUp() { + ReflectionTestUtils.setField(householdService, "baseUrl", "http://localhost:5173"); + } + private UserAccount testUser() { return new UserAccount("sarah@example.com", "Sarah", "hashed"); } @@ -132,6 +139,21 @@ class HouseholdServiceTest { verify(householdInviteRepository).save(any(HouseholdInvite.class)); } + @Test + void createInviteShouldBuildShareUrlWithConfiguredBaseUrl() { + var user = testUser(); + var household = new Household("Smith family", user); + var member = new HouseholdMember(household, user, "planner"); + + when(householdMemberRepository.findByUserEmailIgnoreCase("sarah@example.com")).thenReturn(Optional.of(member)); + when(householdInviteRepository.save(any(HouseholdInvite.class))).thenAnswer(i -> i.getArgument(0)); + + InviteResponse result = householdService.createInvite("sarah@example.com"); + + assertThat(result.shareUrl()).startsWith("http://localhost:5173/join/"); + assertThat(result.shareUrl()).endsWith(result.inviteCode()); + } + @Test void acceptInviteShouldAddUserAsMember() { var user = new UserAccount("tom@example.com", "Tom", "hashed");