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:
DongHyeonka
2026-08-25 19:11:01 +09:00
co-authored by Claude Opus 5
parent f1fd56fcb5
commit a5f93b9b75
7 changed files with 56 additions and 4 deletions
@@ -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.ReferenceDetailResponse;
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.application.techlog.publicsite.model.CaseDetailView;
import dev.caskeleton.application.techlog.publicsite.model.PublishedDocumentView;
@@ -74,6 +75,13 @@ public final class DocumentResponseMapper {
body.setScopeSummary(doc.primarySummary());
body.setAppliesTo(doc.appliesTo());
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(
ReferenceDetailResponseReference.FreshnessStatusEnum.fromValue(doc.freshnessStatus()));
body.setContent(doc.content());
@@ -97,6 +97,7 @@ public class JdbcPublicDocumentQueryAdapter implements PublicDocumentQueryPort {
// 컬럼(`public_resource_projection.last_verified_at`)은 `upsertProjection` 이
// 채우지 않아 언제나 null 이었다.
+ " 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,"
+ " pr.name AS project_name, pr.slug AS project_slug,"
+ " 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 ? List.of() : json.strings(rs.getString("applies_to")),
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"),
rs.getString("body_markdown"),
rs.getString("content_format"),
@@ -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.ProfileView;
import dev.caskeleton.application.techlog.publicsite.model.ReferenceRuleView;
import dev.caskeleton.shared.error.MappingException;
import java.util.ArrayList;
import java.util.List;
@@ -32,6 +33,16 @@ final class PublicJson {
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> out = new ArrayList<>();
for (JsonNode node : array(json)) {
@@ -20,6 +20,8 @@ public record PublishedDocumentView(
List<String> environmentSummary,
List<String> appliesTo,
List<String> excludedScope,
List<ReferenceRuleView> rules,
List<String> examples,
String freshnessStatus,
String content,
String contentFormat,
@@ -37,6 +39,8 @@ public record PublishedDocumentView(
environmentSummary = environmentSummary == null ? List.of() : List.copyOf(environmentSummary);
appliesTo = appliesTo == null ? List.of() : List.copyOf(appliesTo);
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);
// Reference 에는 evidence 를 담는 본문이 없다. 빈 목록이 정상이며 없음과 구분하지 않는다.
bodyAssets = bodyAssets == null ? List.of() : List.copyOf(bodyAssets);
@@ -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) {}
+4 -4
View File
@@ -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
# source: tech-log-design-package contracts/openapi/public-v1.yaml @ 83148b2 (master)
702d6666a8feba9899c7eb7c2a94a0880bcb23b178c7ed2009c6e69d9a1c848c public-v1.yaml
# source: tech-log-design-package contracts/openapi/studio-management-v1.yaml @ 83148b2 (master)
# source: tech-log-design-package contracts/openapi/public-v1.yaml @ ff0c12a (master)
34efa8d2fdba959373081e5b2aace252be86bef243a80c238d8c4af50fa8eb0a public-v1.yaml
# source: tech-log-design-package contracts/openapi/studio-management-v1.yaml @ ff0c12a (master)
72650735061fde627f5037571eb986cb758f44a546f065c88408399f8eec4a55 studio-management-v1.yaml
+17
View File
@@ -1335,6 +1335,23 @@ components:
type: array
items:
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:
type: string
enum: