Skip to content

Commit c391c11

Browse files
robinjoonclaude
andauthored
docs: SpectaQL 기반 GraphQL API 문서화 파이프라인 구성 (#6)
* docs: SpectaQL 기반 GraphQL API 문서화 파이프라인 구성 - spectaql/config.yml: SpectaQL 설정 파일 추가 - Dockerfile.api-docs: Node.js 멀티스테이지 빌드 + Nginx 서빙 - deploy-api-docs.yml: 스키마 변경 시 자동 빌드·배포 워크플로우 - graphql-schema 스킬: .graphqls 작성 시 description 강제 규칙 - 문서화 전략 문서 작성 (도구 선정 이유, CI/CD 흐름) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: SpectaQL config에 x-url 추가 및 임시 스키마 설정 - schemaFile이 비어있으면 파싱 에러 발생하여 learning.graphqls 임시 설정 - SDL 전용 모드에서 필수인 info.x-url 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 98864b5 commit c391c11

File tree

5 files changed

+331
-0
lines changed

5 files changed

+331
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
name: graphql-schema
3+
description: Write, create, edit, or review a GraphQL schema (.graphqls) file. Enforces mandatory descriptions on all types, fields, arguments, and enum values for API documentation. Triggers when working with any .graphqls file in src/main/resources/schema/.
4+
---
5+
6+
# /graphql-schema
7+
8+
GraphQL 스키마(`.graphqls`) 파일을 작성·수정할 때 description 규칙을 강제합니다.
9+
SpectaQL로 정적 API 문서를 자동 생성하므로, 스키마에 작성된 description이 곧 프론트엔드 개발자가 보는 API 문서입니다.
10+
11+
## Arguments
12+
13+
$ARGUMENTS
14+
15+
## Description 필수 규칙
16+
17+
**모든 공개 스키마 요소에 description을 반드시 작성합니다.** description이 없는 요소는 허용하지 않습니다.
18+
19+
### 적용 대상
20+
21+
| 요소 | 필수 여부 | 예시 |
22+
|------|----------|------|
23+
| type (Query, Mutation, 커스텀 타입) | 필수 | `"""할 일"""` |
24+
| type 내 field | 필수 | `"고유 식별자"` |
25+
| input | 필수 | `"""할 일 생성 입력"""` |
26+
| input 내 field | 필수 | `"할 일 제목 (1~100자)"` |
27+
| enum | 필수 | `"""할 일 상태"""` |
28+
| enum value | 필수 | `"진행 중"` |
29+
| argument | 필수 | `"할 일 상태 필터"` |
30+
31+
### Description 문법
32+
33+
- **한 줄**: `"설명"` (double quote)
34+
- **여러 줄**: `"""설명"""` (triple quote, Markdown 지원)
35+
- `# 주석`은 사용하지 않음 (graphql-java가 description으로 노출하지만 GraphQL 스펙에 부합하지 않으므로 `"""` / `""`를 사용)
36+
37+
### Description 작성 가이드
38+
39+
- 한국어로 작성
40+
- 프론트엔드 개발자가 이해할 수 있는 수준으로 작성
41+
- 필드의 제약조건이 있으면 명시 (예: 최대 길이, 허용 값 범위)
42+
- nullable 필드는 "선택" 또는 미지정 시 동작을 설명
43+
44+
## 올바른 예시
45+
46+
```graphql
47+
"""할 일을 조회하고 관리하는 쿼리"""
48+
type Query {
49+
"""
50+
조건에 맞는 할 일 목록을 조회합니다.
51+
조건이 없으면 전체를 반환합니다.
52+
"""
53+
tasks(
54+
"할 일 상태 필터 (미지정 시 전체)"
55+
status: TaskStatus
56+
"담당자 ID 필터"
57+
assigneeId: ID
58+
): [Task!]!
59+
60+
"ID로 할 일을 단건 조회합니다. 존재하지 않으면 null 반환"
61+
task(
62+
"조회할 할 일 ID"
63+
id: ID!
64+
): Task
65+
}
66+
67+
"""할 일 데이터 변경"""
68+
type Mutation {
69+
"새 할 일을 생성합니다"
70+
createTask(
71+
"생성할 할 일 정보"
72+
input: CreateTaskInput!
73+
): Task!
74+
}
75+
76+
"""할 일"""
77+
type Task {
78+
"고유 식별자"
79+
id: ID!
80+
"할 일 제목 (1~100자)"
81+
title: String!
82+
"할 일 상세 설명 (선택)"
83+
description: String
84+
"현재 상태"
85+
status: TaskStatus!
86+
}
87+
88+
"""할 일 생성 입력"""
89+
input CreateTaskInput {
90+
"할 일 제목 (1~100자, 필수)"
91+
title: String!
92+
"할 일 상세 설명 (선택)"
93+
description: String
94+
}
95+
96+
"""할 일 상태"""
97+
enum TaskStatus {
98+
"할 일 (미시작)"
99+
TODO
100+
"진행 중"
101+
IN_PROGRESS
102+
"완료"
103+
DONE
104+
}
105+
```
106+
107+
## 잘못된 예시 (금지)
108+
109+
```graphql
110+
# description 없음 — 금지
111+
type Query {
112+
tasks(status: TaskStatus): [Task!]!
113+
}
114+
115+
# '#' 주석을 description으로 사용 — 금지
116+
type Task {
117+
# 고유 식별자
118+
id: ID!
119+
}
120+
```
121+
122+
## 기존 스키마 수정 시
123+
124+
기존 `.graphqls` 파일을 수정할 때, description이 없는 요소를 발견하면 해당 요소에도 description을 추가합니다.
125+
126+
## 제외 대상
127+
128+
`src/main/resources/schema/learning.graphqls`는 학습용 스키마이므로 이 규칙을 적용하지 않습니다 (수정 금지 코드).
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Deploy API Docs
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'src/main/resources/schema/**'
9+
- 'spectaql/**'
10+
- 'Dockerfile.api-docs'
11+
workflow_dispatch:
12+
13+
env:
14+
HARBOR_REGISTRY: harbor.homelab.robinjoon.xyz
15+
IMAGE_NAME: loop/server-docs
16+
17+
jobs:
18+
build-and-push:
19+
runs-on: [self-hosted, macOS, ARM64]
20+
outputs:
21+
image-tag: ${{ steps.meta.outputs.tag }}
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
27+
- name: Generate image tag
28+
id: meta
29+
run: |
30+
TAG=$(date +'%Y%m%d')-${{ github.run_number }}
31+
echo "tag=$TAG" >> $GITHUB_OUTPUT
32+
33+
- name: Set up Docker Buildx
34+
uses: docker/setup-buildx-action@v3
35+
36+
- name: Login to Harbor
37+
uses: docker/login-action@v3
38+
with:
39+
registry: ${{ env.HARBOR_REGISTRY }}
40+
username: ${{ secrets.HARBOR_USERNAME }}
41+
password: ${{ secrets.HARBOR_PASSWORD }}
42+
43+
- name: Build and push API docs image
44+
uses: docker/build-push-action@v6
45+
with:
46+
context: .
47+
file: Dockerfile.api-docs
48+
push: true
49+
tags: |
50+
${{ env.HARBOR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.tag }}
51+
${{ env.HARBOR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
52+
53+
update-helm:
54+
runs-on: [self-hosted, macOS, ARM64]
55+
needs: build-and-push
56+
57+
steps:
58+
- name: Checkout Helm repository
59+
uses: actions/checkout@v4
60+
with:
61+
repository: Spotit-KR/loop-helm
62+
token: ${{ secrets.HELM_REPO_PAT }}
63+
path: helm-repo
64+
65+
- name: Update image tag
66+
run: |
67+
cd helm-repo
68+
sed -i '' 's/tag: ".*"/tag: "${{ needs.build-and-push.outputs.image-tag }}"/' server-docs/values/values-prod.yaml
69+
70+
- name: Commit and push changes
71+
run: |
72+
cd helm-repo
73+
git config user.name "github-actions[bot]"
74+
git config user.email "github-actions[bot]@users.noreply.github.com"
75+
git add server-docs/values/values-prod.yaml
76+
git commit -m "chore: update server-docs prod image tag to ${{ needs.build-and-push.outputs.image-tag }}"
77+
git push

Dockerfile.api-docs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM node:20-alpine AS builder
2+
WORKDIR /build
3+
COPY spectaql/ spectaql/
4+
COPY src/main/resources/schema/ src/main/resources/schema/
5+
RUN npx spectaql spectaql/config.yml
6+
7+
FROM nginx:alpine
8+
COPY --from=builder /build/build/spectaql/ /usr/share/nginx/html/
9+
EXPOSE 80
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# GraphQL API 문서화 전략
2+
3+
프론트엔드 개발자에게 GraphQL API 문서를 정적 HTML로 제공하기 위한 도구 선정과 CI 통합 방안을 정리합니다.
4+
5+
## 도구 선정: SpectaQL
6+
7+
> **GitHub**: https://github.com/anvilco/spectaql
8+
> **유형**: 정적 사이트 생성기 (Node.js)
9+
10+
### 선정 이유
11+
12+
| 기준 | SpectaQL 평가 |
13+
|------|---------------|
14+
| **CI/CD 통합** | CLI 기반으로 Gradle task, GitHub Actions 등에 즉시 통합 가능 |
15+
| **정적 HTML 출력** | 빌드 결과물이 순수 HTML/CSS/JS — 별도 서버 없이 Nginx, S3 등으로 바로 배포 |
16+
| **SDL 파일 직접 지원** | `src/main/resources/schema/*.graphqls` 파일을 그대로 입력으로 사용 |
17+
| **프론트 개발자 대상** | 3-column 레이아웃(네비게이션/설명/예시)으로 API 레퍼런스 탐색에 최적화 |
18+
| **자동화** | 스키마 변경 → CI 빌드 → 문서 자동 갱신 파이프라인 구성 가능 |
19+
20+
### 검토한 대안
21+
22+
- **Magidoc** — Svelte 기반 모던 UI, Fuzzy 검색 등 기능이 풍부하나 Svelte 의존성이 추가되고 커뮤니티가 SpectaQL 대비 작음
23+
- **GraphiQL** — DGS 기본 내장 인터랙티브 IDE. API 테스트 용도로는 적합하나 정적 문서 생성이 불가하여 CI 파이프라인에 맞지 않음
24+
25+
## SpectaQL 개요
26+
27+
SpectaQL은 GraphQL 스키마로부터 **3-column 레이아웃의 정적 HTML 문서**를 자동 생성하는 Node.js 도구입니다.
28+
29+
### 주요 기능
30+
31+
- 모든 Type, Field, Query, Mutation, Argument, Subscription 자동 문서화
32+
- SDL 파일(`.graphqls`), 라이브 엔드포인트, introspection JSON 모두 지원
33+
- CSS/JS/HTML 테마 커스터마이징 (Handlebars 템플릿)
34+
- 스키마 description의 Markdown 지원
35+
- 예시 코드 자동/수동 생성
36+
37+
## 프로젝트 구성
38+
39+
### 디렉토리 구조
40+
41+
```text
42+
project-root/
43+
├── spectaql/
44+
│ └── config.yml # SpectaQL 설정 파일
45+
├── Dockerfile.api-docs # Nginx 기반 문서 서빙 이미지
46+
├── .github/workflows/
47+
│ └── deploy-api-docs.yml # 문서 빌드·배포 워크플로우
48+
└── src/main/resources/schema/
49+
├── task.graphqls # BC별 스키마 파일 (문서 소스)
50+
└── ...
51+
```
52+
53+
### SpectaQL 설정 (`spectaql/config.yml`)
54+
55+
BC별 스키마가 추가되면 `schemaFile` 목록에 경로를 추가합니다. `learning.graphqls`는 학습용이므로 제외합니다.
56+
57+
### 로컬 실행
58+
59+
```bash
60+
npx spectaql spectaql/config.yml
61+
open build/spectaql/index.html
62+
```
63+
64+
## CI/CD 파이프라인
65+
66+
### 빌드·배포 흐름
67+
68+
```text
69+
main push (스키마/spectaql 변경) → deploy-api-docs.yml 트리거
70+
71+
Docker 멀티스테이지 빌드 (Node.js → SpectaQL 생성 → Nginx 이미지)
72+
73+
Harbor push (harbor.homelab.robinjoon.xyz/loop/server-docs)
74+
75+
Helm repo 업데이트 (Spotit-KR/loop-helm → server-docs/values/values-prod.yaml)
76+
77+
k3s 자동 배포 → Nginx가 정적 HTML 서빙
78+
```
79+
80+
### 워크플로우 (`deploy-api-docs.yml`)
81+
82+
- **트리거**: `main` push 시 `src/main/resources/schema/**`, `spectaql/**`, `Dockerfile.api-docs` 변경 + 수동 트리거
83+
- **이미지**: `loop/server-docs` (기존 `loop/server`와 분리)
84+
- **태그 포맷**: `YYYYMMDD-<run-number>` + `latest`
85+
- 기존 `deploy-prod.yml`과 동일한 패턴 (Harbor push → Helm repo 업데이트)
86+
87+
### Docker 이미지 (`Dockerfile.api-docs`)
88+
89+
멀티스테이지 빌드로 최종 이미지에는 Nginx + 정적 HTML만 포함됩니다.
90+
91+
```text
92+
Stage 1 (node:20-alpine) → npx spectaql로 HTML 생성
93+
Stage 2 (nginx:alpine) → 생성된 HTML을 /usr/share/nginx/html/에 복사
94+
```
95+
96+
> 문서 접근 인증은 배포 서버의 인프라 레이어(Ingress, Basic Auth 등)에서 별도 처리합니다.
97+
98+
## 참고 링크
99+
100+
- [SpectaQL GitHub](https://github.com/anvilco/spectaql)
101+
- [SpectaQL 설정 옵션](https://github.com/anvilco/spectaql#options)
102+
- [Magidoc 공식 문서](https://magidoc.js.org) — 대안 참고
103+
- [GraphiQL GitHub](https://github.com/graphql/graphiql) — 대안 참고

spectaql/config.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
spectaql:
2+
targetDir: build/spectaql
3+
4+
introspection:
5+
schemaFile:
6+
- src/main/resources/schema/learning.graphqls
7+
# BC별 스키마 추가 시 여기에 경로 추가하고 learning.graphqls는 제거
8+
# - src/main/resources/schema/task.graphqls
9+
# - src/main/resources/schema/auth.graphqls
10+
11+
info:
12+
title: Loop GraphQL API
13+
description: Loop 프로젝트 GraphQL API 레퍼런스
14+
x-url: https://api.loop.example.com/graphql

0 commit comments

Comments
 (0)