diff --git a/backend/src/main/java/com/krrishg/controller/ExportController.java b/backend/src/main/java/com/krrishg/controller/ExportController.java index 4ada0f8..bfdaea4 100644 --- a/backend/src/main/java/com/krrishg/controller/ExportController.java +++ b/backend/src/main/java/com/krrishg/controller/ExportController.java @@ -44,7 +44,7 @@ public class ExportController { SiteStructure structure = llmService.restoreVersion(versions.get(0).getId()); try { byte[] zip = exportService.exportSite(structure); - String filename = site.getSubdomain() != null ? site.getSubdomain() : site.getName().replaceAll("\\s+", "-"); + String filename = site.getName().replaceAll("\\s+", "-"); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + sanitizeFilename(filename) + "-export.zip\"") diff --git a/backend/src/main/java/com/krrishg/controller/SiteController.java b/backend/src/main/java/com/krrishg/controller/SiteController.java index 2ef2f3c..8d83ec7 100644 --- a/backend/src/main/java/com/krrishg/controller/SiteController.java +++ b/backend/src/main/java/com/krrishg/controller/SiteController.java @@ -36,18 +36,12 @@ public class SiteController { @PostMapping public ResponseEntity createSite(@AuthenticationPrincipal UserPrincipal principal, @Valid @RequestBody SiteRequest request) { - String subdomain = sanitizeSubdomain(request.getSubdomain()); - if (subdomain != null && siteRepository.existsBySubdomain(subdomain)) { - throw new IllegalArgumentException("Subdomain already taken"); - } - Site.DeploymentTarget target = parseDeploymentTarget(request.getDeploymentTarget()); Site site = Site.builder() .userId(principal.id()) .name(request.getName()) .description(request.getDescription()) - .subdomain(subdomain) .deploymentTarget(target) .build(); @@ -64,20 +58,12 @@ public class SiteController { @PutMapping("/{id}") public ResponseEntity updateSite(@AuthenticationPrincipal UserPrincipal principal, - @PathVariable UUID id, - @Valid @RequestBody SiteRequest request) { + @PathVariable UUID id, + @Valid @RequestBody SiteRequest request) { Site site = findSiteForUser(id, principal.id()); - String newSubdomain = sanitizeSubdomain(request.getSubdomain()); - boolean subdomainChanged = (site.getSubdomain() != null && !site.getSubdomain().equals(newSubdomain)) - || (site.getSubdomain() == null && newSubdomain != null); - if (subdomainChanged && newSubdomain != null && siteRepository.existsBySubdomain(newSubdomain)) { - throw new IllegalArgumentException("Subdomain already taken"); - } - site.setName(request.getName()); site.setDescription(request.getDescription()); - site.setSubdomain(newSubdomain); if (request.getDeploymentTarget() != null) { site.setDeploymentTarget(parseDeploymentTarget(request.getDeploymentTarget())); @@ -104,17 +90,6 @@ public class SiteController { return site; } - private String sanitizeSubdomain(String subdomain) { - if (subdomain == null || subdomain.isBlank()) { - return null; - } - String cleaned = subdomain.strip().toLowerCase(); - if (!cleaned.matches("^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$")) { - throw new IllegalArgumentException("Subdomain must be 3-63 characters, lowercase alphanumeric with hyphens"); - } - return cleaned; - } - private Site.DeploymentTarget parseDeploymentTarget(String value) { if (value == null || value.isBlank()) { return Site.DeploymentTarget.NONE; diff --git a/backend/src/main/java/com/krrishg/dto/SiteRequest.java b/backend/src/main/java/com/krrishg/dto/SiteRequest.java index bbdf3ce..a128f36 100644 --- a/backend/src/main/java/com/krrishg/dto/SiteRequest.java +++ b/backend/src/main/java/com/krrishg/dto/SiteRequest.java @@ -11,7 +11,5 @@ public class SiteRequest { private String description; - private String subdomain; - private String deploymentTarget; } diff --git a/backend/src/main/java/com/krrishg/dto/SiteResponse.java b/backend/src/main/java/com/krrishg/dto/SiteResponse.java index 68da531..9efd76a 100644 --- a/backend/src/main/java/com/krrishg/dto/SiteResponse.java +++ b/backend/src/main/java/com/krrishg/dto/SiteResponse.java @@ -18,7 +18,6 @@ public class SiteResponse { private UUID userId; private String name; private String description; - private String subdomain; private String publishedUrl; private SiteStatus status; private String deploymentTarget; @@ -32,7 +31,6 @@ public class SiteResponse { .userId(site.getUserId()) .name(site.getName()) .description(site.getDescription()) - .subdomain(site.getSubdomain()) .publishedUrl(site.getPublishedUrl()) .status(site.getStatus()) .deploymentTarget(site.getDeploymentTarget().name()) diff --git a/backend/src/main/java/com/krrishg/model/Site.java b/backend/src/main/java/com/krrishg/model/Site.java index 6cd2386..848ef61 100644 --- a/backend/src/main/java/com/krrishg/model/Site.java +++ b/backend/src/main/java/com/krrishg/model/Site.java @@ -30,9 +30,6 @@ public class Site { @Column(name = "description", length = 1000) private String description; - @Column(name = "subdomain", unique = true) - private String subdomain; - @Column(name = "published_url") private String publishedUrl; diff --git a/backend/src/main/java/com/krrishg/repository/SiteRepository.java b/backend/src/main/java/com/krrishg/repository/SiteRepository.java index aa6b797..56540fb 100644 --- a/backend/src/main/java/com/krrishg/repository/SiteRepository.java +++ b/backend/src/main/java/com/krrishg/repository/SiteRepository.java @@ -4,14 +4,9 @@ import com.krrishg.model.Site; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; -import java.util.Optional; import java.util.UUID; public interface SiteRepository extends JpaRepository { List findByUserIdOrderByCreatedAtDesc(UUID userId); - - Optional findBySubdomain(String subdomain); - - boolean existsBySubdomain(String subdomain); } diff --git a/backend/src/main/java/com/krrishg/service/DomainService.java b/backend/src/main/java/com/krrishg/service/DomainService.java index e715f05..a9e23ba 100644 --- a/backend/src/main/java/com/krrishg/service/DomainService.java +++ b/backend/src/main/java/com/krrishg/service/DomainService.java @@ -4,9 +4,6 @@ import com.krrishg.model.SelfHostedConfig; import com.krrishg.model.Site; import com.krrishg.repository.SelfHostedConfigRepository; import com.krrishg.repository.SiteRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Optional; @@ -14,18 +11,13 @@ import java.util.Optional; @Service public class DomainService { - private static final Logger log = LoggerFactory.getLogger(DomainService.class); - private final SiteRepository siteRepository; private final SelfHostedConfigRepository selfHostedConfigRepository; - private final String siteDomain; public DomainService(SiteRepository siteRepository, - SelfHostedConfigRepository selfHostedConfigRepository, - @Value("${indie.domain}") String siteDomain) { + SelfHostedConfigRepository selfHostedConfigRepository) { this.siteRepository = siteRepository; this.selfHostedConfigRepository = selfHostedConfigRepository; - this.siteDomain = siteDomain; } public Optional resolveSite(String hostname) { @@ -40,33 +32,6 @@ public class DomainService { return siteRepository.findById(config.get().getSiteId()); } - String subdomain = extractSubdomain(lower); - if (subdomain != null) { - return siteRepository.findBySubdomain(subdomain); - } - return Optional.empty(); } - - private String extractSubdomain(String hostname) { - String suffix = "." + siteDomain; - if (hostname.endsWith(suffix)) { - String subdomain = hostname.substring(0, hostname.indexOf(suffix)); - if (!subdomain.isEmpty() && !subdomain.contains(".")) { - return subdomain; - } - } - return null; - } - - public boolean isSubdomainAvailable(String subdomain) { - return !siteRepository.existsBySubdomain(subdomain); - } - - public String getSiteUrl(Site site) { - if (site.getSubdomain() != null) { - return "https://" + site.getSubdomain() + "." + siteDomain; - } - return null; - } } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index de3f7e7..c3a17bd 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -43,7 +43,6 @@ indie: repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/} author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform} author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local} - domain: ${INDIE_SITE_DOMAIN:indie.com} cors: allowed-origins: ${INDIE_CORS_ORIGINS:http://localhost:4200,http://localhost:3000} diff --git a/backend/src/test/java/com/krrishg/controller/ExportControllerTest.java b/backend/src/test/java/com/krrishg/controller/ExportControllerTest.java index 6f780e6..1f96bb4 100644 --- a/backend/src/test/java/com/krrishg/controller/ExportControllerTest.java +++ b/backend/src/test/java/com/krrishg/controller/ExportControllerTest.java @@ -66,7 +66,6 @@ class ExportControllerTest { .id(siteId) .userId(userId) .name("My Site") - .subdomain("my-site") .status(SiteStatus.DRAFT) .createdAt(LocalDateTime.now()) .updatedAt(LocalDateTime.now()) @@ -125,17 +124,16 @@ class ExportControllerTest { } @Test - void exportSanitizesFilenameForSiteWithoutSubdomain() throws Exception { - Site siteNoSubdomain = Site.builder() + void exportSanitizesFilenameWithSpecialCharacters() throws Exception { + Site siteWithSpecialName = Site.builder() .id(siteId) .userId(userId) .name("My Cool Site!") - .subdomain(null) .status(SiteStatus.DRAFT) .createdAt(LocalDateTime.now()) .updatedAt(LocalDateTime.now()) .build(); - when(siteRepository.findById(siteId)).thenReturn(Optional.of(siteNoSubdomain)); + when(siteRepository.findById(siteId)).thenReturn(Optional.of(siteWithSpecialName)); GenerationVersion version = GenerationVersion.builder() .id("v1") diff --git a/backend/src/test/java/com/krrishg/controller/SiteControllerTest.java b/backend/src/test/java/com/krrishg/controller/SiteControllerTest.java index 0c8f7e7..e332ff2 100644 --- a/backend/src/test/java/com/krrishg/controller/SiteControllerTest.java +++ b/backend/src/test/java/com/krrishg/controller/SiteControllerTest.java @@ -80,41 +80,22 @@ class SiteControllerTest { .userId(userId) .name("New Site") .description("Description") - .subdomain("new-site") .status(SiteStatus.DRAFT) .createdAt(LocalDateTime.now()) .updatedAt(LocalDateTime.now()) .build(); - when(siteRepository.existsBySubdomain("new-site")).thenReturn(false); when(siteRepository.save(any(Site.class))).thenReturn(saved); SiteRequest request = new SiteRequest(); request.setName("New Site"); request.setDescription("Description"); - request.setSubdomain("new-site"); mockMvc.perform(post("/api/sites") .with(authentication(auth)) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) - .andExpect(jsonPath("$.name").value("New Site")) - .andExpect(jsonPath("$.subdomain").value("new-site")); - } - - @Test - void createSiteReturns400OnDuplicateSubdomain() throws Exception { - when(siteRepository.existsBySubdomain("taken")).thenReturn(true); - - SiteRequest request = new SiteRequest(); - request.setName("Site"); - request.setSubdomain("taken"); - - mockMvc.perform(post("/api/sites") - .with(authentication(auth)) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isBadRequest()); + .andExpect(jsonPath("$.name").value("New Site")); } @Test @@ -173,23 +154,19 @@ class SiteControllerTest { .id(siteId) .userId(userId) .name("Old Name") - .subdomain("old-sub") .status(SiteStatus.DRAFT) .build(); when(siteRepository.findById(siteId)).thenReturn(Optional.of(existing)); - when(siteRepository.existsBySubdomain("new-sub")).thenReturn(false); when(siteRepository.save(any(Site.class))).thenAnswer(invocation -> invocation.getArgument(0)); SiteRequest request = new SiteRequest(); request.setName("New Name"); - request.setSubdomain("new-sub"); mockMvc.perform(put("/api/sites/{id}", siteId) .with(authentication(auth)) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isOk()) - .andExpect(jsonPath("$.name").value("New Name")) - .andExpect(jsonPath("$.subdomain").value("new-sub")); + .andExpect(jsonPath("$.name").value("New Name")); } } diff --git a/backend/src/test/java/com/krrishg/dto/SiteResponseTest.java b/backend/src/test/java/com/krrishg/dto/SiteResponseTest.java index 9aee402..0f24971 100644 --- a/backend/src/test/java/com/krrishg/dto/SiteResponseTest.java +++ b/backend/src/test/java/com/krrishg/dto/SiteResponseTest.java @@ -22,7 +22,6 @@ class SiteResponseTest { .userId(userId) .name("My Site") .description("A test site") - .subdomain("mysite") .status(SiteStatus.PUBLISHED) .publishedAt(now) .createdAt(now) @@ -35,7 +34,6 @@ class SiteResponseTest { assertEquals(userId, response.getUserId()); assertEquals("My Site", response.getName()); assertEquals("A test site", response.getDescription()); - assertEquals("mysite", response.getSubdomain()); assertEquals(SiteStatus.PUBLISHED, response.getStatus()); assertEquals(now, response.getPublishedAt()); assertEquals(now, response.getCreatedAt()); @@ -54,7 +52,6 @@ class SiteResponseTest { SiteResponse response = SiteResponse.from(site); assertNull(response.getDescription()); - assertNull(response.getSubdomain()); assertNull(response.getPublishedAt()); } } diff --git a/backend/src/test/java/com/krrishg/repository/SiteRepositoryTest.java b/backend/src/test/java/com/krrishg/repository/SiteRepositoryTest.java index 903ab33..f9ccb29 100644 --- a/backend/src/test/java/com/krrishg/repository/SiteRepositoryTest.java +++ b/backend/src/test/java/com/krrishg/repository/SiteRepositoryTest.java @@ -60,30 +60,4 @@ class SiteRepositoryTest { assertTrue(sites.isEmpty()); } - @Test - void findBySubdomain() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("Site") - .subdomain("mysubdomain") - .build(); - siteRepository.save(site); - - Optional found = siteRepository.findBySubdomain("mysubdomain"); - assertTrue(found.isPresent()); - assertEquals("Site", found.get().getName()); - } - - @Test - void existsBySubdomain() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("Site") - .subdomain("exists-sub") - .build(); - siteRepository.save(site); - - assertTrue(siteRepository.existsBySubdomain("exists-sub")); - assertFalse(siteRepository.existsBySubdomain("no-sub")); - } } diff --git a/backend/src/test/java/com/krrishg/service/DomainServiceTest.java b/backend/src/test/java/com/krrishg/service/DomainServiceTest.java index 6938cff..7c3fb6c 100644 --- a/backend/src/test/java/com/krrishg/service/DomainServiceTest.java +++ b/backend/src/test/java/com/krrishg/service/DomainServiceTest.java @@ -1,5 +1,6 @@ package com.krrishg.service; +import com.krrishg.model.SelfHostedConfig; import com.krrishg.model.Site; import com.krrishg.model.SiteStatus; import com.krrishg.support.FakeSelfHostedConfigRepository; @@ -14,8 +15,6 @@ import static org.junit.jupiter.api.Assertions.*; class DomainServiceTest { - private static final String SITE_DOMAIN = "indie.example.com"; - private FakeSiteRepository siteRepository; private FakeSelfHostedConfigRepository selfHostedConfigRepository; private DomainService domainService; @@ -24,34 +23,33 @@ class DomainServiceTest { void setUp() { siteRepository = new FakeSiteRepository(); selfHostedConfigRepository = new FakeSelfHostedConfigRepository(); - domainService = new DomainService(siteRepository, selfHostedConfigRepository, SITE_DOMAIN); + domainService = new DomainService(siteRepository, selfHostedConfigRepository); } @Test - void resolveSiteReturnsSiteWhenSubdomainMatches() { + void resolveSiteReturnsSiteForSelfHostedDomain() { Site site = Site.builder() .userId(UUID.randomUUID()) .name("My Site") - .subdomain("mysite") .status(SiteStatus.DRAFT) .build(); siteRepository.save(site); - Optional result = domainService.resolveSite("mysite.indie.example.com"); + SelfHostedConfig config = SelfHostedConfig.builder() + .siteId(site.getId()) + .domain("www.example.com") + .build(); + selfHostedConfigRepository.save(config); + + Optional result = domainService.resolveSite("www.example.com"); assertTrue(result.isPresent()); - assertEquals("mysite", result.get().getSubdomain()); + assertEquals(site.getId(), result.get().getId()); } @Test - void resolveSiteReturnsEmptyForUnknownSubdomain() { - Optional result = domainService.resolveSite("unknown.indie.example.com"); - assertTrue(result.isEmpty()); - } - - @Test - void resolveSiteReturnsEmptyForNonMatchingHostname() { - Optional result = domainService.resolveSite("example.com"); + void resolveSiteReturnsEmptyForUnknownHostname() { + Optional result = domainService.resolveSite("unknown.example.com"); assertTrue(result.isEmpty()); } @@ -62,73 +60,8 @@ class DomainServiceTest { } @Test - void resolveSiteReturnsEmptyWhenSubdomainContainsDots() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("My Site") - .subdomain("mysite") - .status(SiteStatus.DRAFT) - .build(); - siteRepository.save(site); - - Optional result = domainService.resolveSite("mysite.staging.indie.example.com"); + void resolveSiteReturnsEmptyWhenHostnameIsBlank() { + Optional result = domainService.resolveSite(" "); assertTrue(result.isEmpty()); } - - @Test - void resolveSiteIsCaseInsensitiveOnHostname() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("My Site") - .subdomain("mysite") - .status(SiteStatus.DRAFT) - .build(); - siteRepository.save(site); - - Optional result = domainService.resolveSite("MySite.indie.example.com"); - assertTrue(result.isPresent()); - assertEquals("mysite", result.get().getSubdomain()); - } - - @Test - void isSubdomainAvailableReturnsTrueWhenNotTaken() { - assertTrue(domainService.isSubdomainAvailable("available")); - } - - @Test - void isSubdomainAvailableReturnsFalseWhenTaken() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("My Site") - .subdomain("taken") - .status(SiteStatus.DRAFT) - .build(); - siteRepository.save(site); - - assertFalse(domainService.isSubdomainAvailable("taken")); - } - - @Test - void getSiteUrlReturnsHttpsUrlWithSubdomain() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("My Site") - .subdomain("mysite") - .status(SiteStatus.DRAFT) - .build(); - - String url = domainService.getSiteUrl(site); - assertEquals("https://mysite.indie.example.com", url); - } - - @Test - void getSiteUrlReturnsNullWhenNoSubdomain() { - Site site = Site.builder() - .userId(UUID.randomUUID()) - .name("My Site") - .status(SiteStatus.DRAFT) - .build(); - - assertNull(domainService.getSiteUrl(site)); - } } diff --git a/backend/src/test/java/com/krrishg/support/FakeSiteRepository.java b/backend/src/test/java/com/krrishg/support/FakeSiteRepository.java index 24d8f99..e5727f9 100644 --- a/backend/src/test/java/com/krrishg/support/FakeSiteRepository.java +++ b/backend/src/test/java/com/krrishg/support/FakeSiteRepository.java @@ -5,7 +5,6 @@ import com.krrishg.repository.SiteRepository; import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.UUID; public class FakeSiteRepository extends InMemoryRepository implements SiteRepository { @@ -33,17 +32,4 @@ public class FakeSiteRepository extends InMemoryRepository implement .sorted(Comparator.comparing(Site::getCreatedAt).reversed()) .toList(); } - - @Override - public Optional findBySubdomain(String subdomain) { - return store.values().stream() - .filter(s -> subdomain.equals(s.getSubdomain())) - .findFirst(); - } - - @Override - public boolean existsBySubdomain(String subdomain) { - return store.values().stream() - .anyMatch(s -> subdomain.equals(s.getSubdomain())); - } }