feat: 공개 Reference 응답에 판단 기준과 예시를 싣는다
Reference 의 본문은 `body_markdown` 이 아니라 `reference_detail.rules` 와 `examples` 에 있다. Studio 의 Reference 편집기가 규칙(제목+본문)과 예시를 따로 받고 마크다운 본문은 비워 두기 때문이다. 공개 조회는 그 두 칸을 읽지 않고 `body_markdown` 만 봤다. 그래서 `content: ""` 를 내보냈고, 공개 화면의 "판단 기준"과 "예시"가 통째로 비었다 — Studio 에서는 다 보이는데 공개 쪽만 빈 이유가 이것이다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEHXspz4rv5pB5wiiSsVDu
This commit is contained in:
co-authored by
Claude Opus 5
parent
f1fd56fcb5
commit
a5f93b9b75
+8
@@ -11,6 +11,7 @@ import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.QuestionPo
|
|||||||
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.QuestionUpdatePublic;
|
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.QuestionUpdatePublic;
|
||||||
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponse;
|
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponse;
|
||||||
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponseReference;
|
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponseReference;
|
||||||
|
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponseReferenceRulesInner;
|
||||||
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponseRelations;
|
import dev.caskeleton.adapter.inbound.web.techlog.publicapi.api.model.ReferenceDetailResponseRelations;
|
||||||
import dev.caskeleton.application.techlog.publicsite.model.CaseDetailView;
|
import dev.caskeleton.application.techlog.publicsite.model.CaseDetailView;
|
||||||
import dev.caskeleton.application.techlog.publicsite.model.PublishedDocumentView;
|
import dev.caskeleton.application.techlog.publicsite.model.PublishedDocumentView;
|
||||||
@@ -74,6 +75,13 @@ public final class DocumentResponseMapper {
|
|||||||
body.setScopeSummary(doc.primarySummary());
|
body.setScopeSummary(doc.primarySummary());
|
||||||
body.setAppliesTo(doc.appliesTo());
|
body.setAppliesTo(doc.appliesTo());
|
||||||
body.setExcludedScope(doc.excludedScope());
|
body.setExcludedScope(doc.excludedScope());
|
||||||
|
// Reference 의 본문은 `content` 가 아니라 여기 있다 — 이것을 빼면 공개 화면에 판단 기준과
|
||||||
|
// 예시가 통째로 빠진다.
|
||||||
|
body.setRules(
|
||||||
|
doc.rules().stream()
|
||||||
|
.map(rule -> new ReferenceDetailResponseReferenceRulesInner(rule.title(), rule.body()))
|
||||||
|
.toList());
|
||||||
|
body.setExamples(doc.examples());
|
||||||
body.setFreshnessStatus(
|
body.setFreshnessStatus(
|
||||||
ReferenceDetailResponseReference.FreshnessStatusEnum.fromValue(doc.freshnessStatus()));
|
ReferenceDetailResponseReference.FreshnessStatusEnum.fromValue(doc.freshnessStatus()));
|
||||||
body.setContent(doc.content());
|
body.setContent(doc.content());
|
||||||
|
|||||||
+4
@@ -97,6 +97,7 @@ public class JdbcPublicDocumentQueryAdapter implements PublicDocumentQueryPort {
|
|||||||
// 컬럼(`public_resource_projection.last_verified_at`)은 `upsertProjection` 이
|
// 컬럼(`public_resource_projection.last_verified_at`)은 `upsertProjection` 이
|
||||||
// 채우지 않아 언제나 null 이었다.
|
// 채우지 않아 언제나 null 이었다.
|
||||||
+ " p.navigation_path, p.published_at, p.updated_at, d.last_verified_at,"
|
+ " p.navigation_path, p.published_at, p.updated_at, d.last_verified_at,"
|
||||||
|
+ " r.rules, r.examples,"
|
||||||
+ " t.name AS topic_name, t.slug AS topic_slug,"
|
+ " t.name AS topic_name, t.slug AS topic_slug,"
|
||||||
+ " pr.name AS project_name, pr.slug AS project_slug,"
|
+ " pr.name AS project_name, pr.slug AS project_slug,"
|
||||||
+ " a.content_type AS cover_content_type, a.alt_text AS cover_alt,"
|
+ " a.content_type AS cover_content_type, a.alt_text AS cover_alt,"
|
||||||
@@ -132,6 +133,9 @@ public class JdbcPublicDocumentQueryAdapter implements PublicDocumentQueryPort {
|
|||||||
isCase ? environment(rs) : List.of(),
|
isCase ? environment(rs) : List.of(),
|
||||||
isCase ? List.of() : json.strings(rs.getString("applies_to")),
|
isCase ? List.of() : json.strings(rs.getString("applies_to")),
|
||||||
isCase ? List.of() : json.strings(rs.getString("excluded_scope")),
|
isCase ? List.of() : json.strings(rs.getString("excluded_scope")),
|
||||||
|
// Reference 의 본문은 body_markdown 이 아니라 규칙과 예시에 있다.
|
||||||
|
isCase ? List.of() : json.referenceRules(rs.getString("rules")),
|
||||||
|
isCase ? List.of() : json.strings(rs.getString("examples")),
|
||||||
isCase ? null : rs.getString("freshness_status"),
|
isCase ? null : rs.getString("freshness_status"),
|
||||||
rs.getString("body_markdown"),
|
rs.getString("body_markdown"),
|
||||||
rs.getString("content_format"),
|
rs.getString("content_format"),
|
||||||
|
|||||||
+11
@@ -2,6 +2,7 @@ package dev.caskeleton.adapter.outbound.persistence.techlog.publicsite;
|
|||||||
|
|
||||||
import dev.caskeleton.application.techlog.publicsite.model.ContactLinkView;
|
import dev.caskeleton.application.techlog.publicsite.model.ContactLinkView;
|
||||||
import dev.caskeleton.application.techlog.publicsite.model.ProfileView;
|
import dev.caskeleton.application.techlog.publicsite.model.ProfileView;
|
||||||
|
import dev.caskeleton.application.techlog.publicsite.model.ReferenceRuleView;
|
||||||
import dev.caskeleton.shared.error.MappingException;
|
import dev.caskeleton.shared.error.MappingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,6 +33,16 @@ final class PublicJson {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Reference 의 판단 기준. 설계의 컬럼은 {@code {title, body, order}} 배열이다. */
|
||||||
|
List<ReferenceRuleView> referenceRules(String json) {
|
||||||
|
List<ReferenceRuleView> out = new ArrayList<>();
|
||||||
|
for (JsonNode node : array(json)) {
|
||||||
|
out.add(
|
||||||
|
new ReferenceRuleView(node.path("title").asString(""), node.path("body").asString("")));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
List<ContactLinkView> contacts(String json) {
|
List<ContactLinkView> contacts(String json) {
|
||||||
List<ContactLinkView> out = new ArrayList<>();
|
List<ContactLinkView> out = new ArrayList<>();
|
||||||
for (JsonNode node : array(json)) {
|
for (JsonNode node : array(json)) {
|
||||||
|
|||||||
+4
@@ -20,6 +20,8 @@ public record PublishedDocumentView(
|
|||||||
List<String> environmentSummary,
|
List<String> environmentSummary,
|
||||||
List<String> appliesTo,
|
List<String> appliesTo,
|
||||||
List<String> excludedScope,
|
List<String> excludedScope,
|
||||||
|
List<ReferenceRuleView> rules,
|
||||||
|
List<String> examples,
|
||||||
String freshnessStatus,
|
String freshnessStatus,
|
||||||
String content,
|
String content,
|
||||||
String contentFormat,
|
String contentFormat,
|
||||||
@@ -37,6 +39,8 @@ public record PublishedDocumentView(
|
|||||||
environmentSummary = environmentSummary == null ? List.of() : List.copyOf(environmentSummary);
|
environmentSummary = environmentSummary == null ? List.of() : List.copyOf(environmentSummary);
|
||||||
appliesTo = appliesTo == null ? List.of() : List.copyOf(appliesTo);
|
appliesTo = appliesTo == null ? List.of() : List.copyOf(appliesTo);
|
||||||
excludedScope = excludedScope == null ? List.of() : List.copyOf(excludedScope);
|
excludedScope = excludedScope == null ? List.of() : List.copyOf(excludedScope);
|
||||||
|
rules = rules == null ? List.of() : List.copyOf(rules);
|
||||||
|
examples = examples == null ? List.of() : List.copyOf(examples);
|
||||||
tags = tags == null ? List.of() : List.copyOf(tags);
|
tags = tags == null ? List.of() : List.copyOf(tags);
|
||||||
// Reference 에는 evidence 를 담는 본문이 없다. 빈 목록이 정상이며 없음과 구분하지 않는다.
|
// Reference 에는 evidence 를 담는 본문이 없다. 빈 목록이 정상이며 없음과 구분하지 않는다.
|
||||||
bodyAssets = bodyAssets == null ? List.of() : List.copyOf(bodyAssets);
|
bodyAssets = bodyAssets == null ? List.of() : List.copyOf(bodyAssets);
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package dev.caskeleton.application.techlog.publicsite.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference 의 판단 기준 한 줄. 계약 {@code ReferenceDetailResponse.reference.rules[]}.
|
||||||
|
*
|
||||||
|
* <p>Reference 의 본문은 마크다운 한 덩어리가 아니라 제목이 붙은 규칙의 목록이다 — Studio 의 편집기가 그렇게 받고, 공개 화면도 그렇게 그린다.
|
||||||
|
*/
|
||||||
|
public record ReferenceRuleView(String title, String body) {}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# source: tech-log-design-package contracts/openapi/studio-v1.yaml @ 83148b2 (master)
|
# source: tech-log-design-package contracts/openapi/studio-v1.yaml @ ff0c12a (master)
|
||||||
18dd46898be64b07f7e826409d19347512613ee2e22420028a4a0644f50f37dd studio-v1.yaml
|
18dd46898be64b07f7e826409d19347512613ee2e22420028a4a0644f50f37dd studio-v1.yaml
|
||||||
# source: tech-log-design-package contracts/openapi/public-v1.yaml @ 83148b2 (master)
|
# source: tech-log-design-package contracts/openapi/public-v1.yaml @ ff0c12a (master)
|
||||||
702d6666a8feba9899c7eb7c2a94a0880bcb23b178c7ed2009c6e69d9a1c848c public-v1.yaml
|
34efa8d2fdba959373081e5b2aace252be86bef243a80c238d8c4af50fa8eb0a public-v1.yaml
|
||||||
# source: tech-log-design-package contracts/openapi/studio-management-v1.yaml @ 83148b2 (master)
|
# source: tech-log-design-package contracts/openapi/studio-management-v1.yaml @ ff0c12a (master)
|
||||||
72650735061fde627f5037571eb986cb758f44a546f065c88408399f8eec4a55 studio-management-v1.yaml
|
72650735061fde627f5037571eb986cb758f44a546f065c88408399f8eec4a55 studio-management-v1.yaml
|
||||||
|
|||||||
@@ -1335,6 +1335,23 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
# Reference 의 본문은 `content` 마크다운이 아니라 이 두 칸에 있다. Studio 의 Reference
|
||||||
|
# 편집기는 규칙(제목+본문)과 예시를 따로 받고 body_markdown 은 비워 두므로, 이것을
|
||||||
|
# 내보내지 않으면 공개 화면에 판단 기준과 예시가 통째로 빠진다.
|
||||||
|
rules:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [title, body]
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
examples:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
freshnessStatus:
|
freshnessStatus:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
|||||||
Reference in New Issue
Block a user