diff --git a/src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/techlog/query/JdbcCatalogQueryAdapter.java b/src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/techlog/query/JdbcCatalogQueryAdapter.java index d7eb6c2..5b11fae 100644 --- a/src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/techlog/query/JdbcCatalogQueryAdapter.java +++ b/src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/techlog/query/JdbcCatalogQueryAdapter.java @@ -68,11 +68,25 @@ public class JdbcCatalogQueryAdapter implements CatalogQueryPort { .list(); } + /** + * 프로젝트의 공개 경로를 함께 싣는다. + * + *

여기서 {@code publicPath} 를 늘 null 로 두었더니 Decision 의 즉시 미리보기가 어떤 문서에서도 열리지 않았다. Decision 의 공개 + * 주소는 자기 slug 가 아니라 {@code <프로젝트 경로>/decisions#} 라, 렌더 모델이 프로젝트 경로를 요구한다 — 그것이 비어 있으면 + * "PROJECT public path is required" 로 미리보기 전체가 멈춘다. 화면에는 무엇이 모자란지 나오지 않는다. + * + *

게시되지 않은 프로젝트는 여전히 null 이다. 그때는 공개 주소가 실제로 없고, 없는 주소를 지어내면 미리보기가 보여 주는 링크가 게시 뒤에 달라진다. + */ private List searchProjects(String pattern, int limit) { return jdbcClient .sql( - "SELECT id, name, updated_at FROM project " - + "WHERE lower(name) LIKE :pattern ORDER BY name LIMIT :limit") + "SELECT pr.id, pr.name, pr.updated_at, p.navigation_path" + + " FROM project pr" + + " LEFT JOIN public_resource_projection p" + + " ON p.resource_type = 'PROJECT' AND p.resource_id = pr.id" + + " AND " + + PUBLICLY_VISIBLE + + " WHERE lower(pr.name) LIKE :pattern ORDER BY pr.name LIMIT :limit") .param("pattern", pattern) .param("limit", limit) .query( @@ -82,7 +96,7 @@ public class JdbcCatalogQueryAdapter implements CatalogQueryPort { CatalogEntryType.PROJECT, rs.getString("name"), "PROJECT", - null, + rs.getString("navigation_path"), "project:" + rs.getTimestamp("updated_at").toInstant())) .list(); } diff --git a/src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/techlog/management/ManagementPersistenceIntegrationTest.java b/src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/techlog/management/ManagementPersistenceIntegrationTest.java index f987730..ea7d843 100644 --- a/src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/techlog/management/ManagementPersistenceIntegrationTest.java +++ b/src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/techlog/management/ManagementPersistenceIntegrationTest.java @@ -785,4 +785,34 @@ class ManagementPersistenceIntegrationTest { .single()) .isZero(); } + + /** + * Decision 의 공개 주소는 자기 slug 가 아니라 프로젝트 주소 아래에 있다. 그래서 편집기가 Decision 을 미리 그리려면 이 목록이 프로젝트의 공개 경로를 + * 알고 있어야 한다 — 한동안 늘 null 이었고, 그동안 Decision 은 어떤 문서에서도 즉시 미리보기가 열리지 않았다. + */ + @Test + void projectCatalogCarriesThePublicPathOfPublishedProjectsOnly() { + ProjectEditView open = projects.create(new CreateProjectCommand("Catalog Published", "test")); + jdbcClient + .sql("UPDATE project SET slug = 'catalog-published' WHERE id = :id") + .param("id", open.id()) + .update(); + ProjectEditView loaded = projects.find(open.id()).orElseThrow(); + assertThat(projects.publish(loaded.id(), loaded.version(), "PUBLIC", "test")).isPresent(); + + ProjectEditView hidden = projects.create(new CreateProjectCommand("Catalog Hidden", "test")); + + var entries = catalog.search(CatalogEntryType.PROJECT, "catalog", null, 50).items(); + + assertThat(entries) + .filteredOn(entry -> entry.id().equals(open.id())) + .singleElement() + .satisfies( + entry -> assertThat(entry.publicPath()).isEqualTo("/projects/catalog-published")); + // 게시되지 않은 프로젝트는 공개 주소가 실제로 없다. 지어내면 미리보기가 보여 준 링크가 게시 뒤에 달라진다. + assertThat(entries) + .filteredOn(entry -> entry.id().equals(hidden.id())) + .singleElement() + .satisfies(entry -> assertThat(entry.publicPath()).isNull()); + } }