Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/workflows/database-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Database Documentation

on:
push:
branches: [main]
Comment thread
hywznn marked this conversation as resolved.
paths:
- 'src/main/resources/db/migration/**'
- 'scripts/db-docs/**'
- '.github/workflows/database-docs.yml'
pull_request:
branches: [main]
paths:
- 'src/main/resources/db/migration/**'
- 'scripts/db-docs/**'
- '.github/workflows/database-docs.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: database-docs-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-docs:
name: Build database documentation
runs-on: ubuntu-latest
timeout-minutes: 15

services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_DB: fowoco_docs
POSTGRES_USER: fowoco_docs
POSTGRES_PASSWORD: fowoco_docs_ci_only
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U fowoco_docs -d fowoco_docs"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Set up Node.js 24
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '24'

- name: Test documentation generator
run: node --test scripts/db-docs/generate-site.test.mjs

- name: Generate database documentation
run: ./scripts/db-docs/generate.sh
env:
DB_DOCS_CONTAINER_HOST: 127.0.0.1
DB_DOCS_EPHEMERAL: 'true'
DB_DOCS_PORT: '5432'
DB_DOCS_DATABASE: fowoco_docs
DB_DOCS_USER: fowoco_docs
DB_DOCS_PASSWORD: fowoco_docs_ci_only
DB_DOCS_GIT_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Upload database documentation preview
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: database-docs-site
path: build/db-docs/site
if-no-files-found: error
retention-days: 14

deploy-pages:
name: Deploy database documentation
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: build-docs
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Download database documentation
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: database-docs-site
path: site

- name: Configure GitHub Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5

- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
with:
path: site

- name: Deploy GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ FOWOCO는 단순 번역 서비스가 아닙니다. 체류·계약·서류·신

계획 문서는 현재 동작하는 API가 아닙니다. 구현의 원본은 코드·테스트와 실행 시 생성되는 OpenAPI이고, 장기 아키텍처 결정은 [ADR](docs/adr/README.md), 계획 범위와 예시는 [API 카탈로그](https://github.com/fowoco/server/wiki/09-API-Specification)와 Issue에서 확인합니다.

데이터베이스 구조는 [DB 문서 사이트](https://fowoco.github.io/server/)에서 전체
Comment thread
hywznn marked this conversation as resolved.
ERD, 테이블·컬럼·제약조건과 Flyway 적용 이력을 확인할 수 있습니다. 이 사이트는
`main`의 Migration을 일회용 빈 PostgreSQL에 적용해 자동 생성하며 실제 데이터는
포함하지 않습니다. PR 미리보기와 로컬 생성 방법은
[데이터베이스 문서 사용법](docs/database-documentation.md)을 봅니다.

## 5분 실행

### 필요한 것
Expand Down
104 changes: 104 additions & 0 deletions docs/database-documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 데이터베이스 문서 사용법

FOWOCO Server의 데이터베이스 문서는 `main`의 Flyway Migration을 일회용
PostgreSQL에 처음부터 적용한 결과로 생성합니다.

- 팀 공유 사이트: <https://fowoco.github.io/server/>
- 변경의 원본: `src/main/resources/db/migration`
- 구조 결정의 원본: `docs/adr`

문서는 구조를 쉽게 찾기 위한 보조 수단입니다. 문서 화면에서 DB를 변경할 수
없으며, Flyway SQL을 거치지 않은 변경은 정식 변경으로 인정하지 않습니다.

## 무엇을 볼 수 있나요?

| 메뉴 | 확인할 수 있는 내용 |
| --- | --- |
| 테이블 구조 | 전체 ERD, 컬럼 타입, Nullable, 기본값 |
| 관계 | PK, FK, UNIQUE, CHECK, INDEX |
| Migration 이력 | 적용 버전, 상태, 적용 시각, 실행 시간 |
| 생성 정보 | 기준 Git commit, Flyway·Schema version, 생성 시각 |

운영 DB의 데이터, 계정, 접속 주소, 비밀번호는 문서에 포함하지 않습니다.

## 언제 갱신되나요?

다음 경로가 변경되어 `main`에 병합되면 `Database Documentation` Workflow가
자동 실행됩니다.

```text
src/main/resources/db/migration/**
scripts/db-docs/**
.github/workflows/database-docs.yml
```

Workflow는 다음 순서로 동작합니다.

```text
빈 PostgreSQL 시작
→ Flyway migrate
→ Flyway validate
→ SchemaSpy HTML 생성
→ Migration 이력 페이지 생성
→ GitHub Pages 배포
```

Migration 적용이나 `validate`가 실패하면 기존 Pages를 덮어쓰지 않습니다.

## PR에서 먼저 확인하기

Migration을 바꾼 PR에서는 Pages를 배포하지 않습니다.

1. PR의 `Checks`에서 `Database Documentation`을 엽니다.
2. 실행 결과 아래의 `Artifacts`로 이동합니다.
3. `database-docs-site`를 내려받습니다.
4. 압축을 풀고 `index.html`을 브라우저로 엽니다.

Artifact는 14일 동안 보관합니다. PR 작성자는 ERD 변경이 의도한 구조인지
확인한 뒤 리뷰를 요청합니다.

## 로컬에서 생성하기

Docker Desktop 또는 Docker Engine과 Node.js 24 이상이 필요합니다.

```bash
./scripts/db-docs/generate-local.sh
```

이 명령은 작업마다 별도의 Docker network와 PostgreSQL container를 만들고,
완료되거나 실패하면 정확히 그 임시 자원만 제거합니다.

생성 결과는 Git에 포함되지 않는 아래 경로에 있습니다.

```text
build/db-docs/site/index.html
```

macOS에서는 다음 명령으로 열 수 있습니다.

```bash
open build/db-docs/site/index.html
```

## 실패했을 때 확인할 것
Comment thread
hywznn marked this conversation as resolved.

| 증상 | 확인 |
| --- | --- |
| Docker를 찾지 못함 | Docker Desktop 설치·실행 여부 |
| PostgreSQL 준비 실패 | 기존 container와 Docker 자원 상태 |
| Flyway migrate 실패 | 가장 최근 Migration SQL과 PostgreSQL 문법 |
| Flyway validate 실패 | 이미 적용된 Migration을 수정·삭제했는지 |
| SchemaSpy 실패 | 테이블·FK·제약조건 오류와 container 로그 |
| Pages 배포 실패 | Repository Pages Source와 `github-pages` Environment |

적용된 Migration을 수정하거나 `flyway repair`로 실패를 숨기지 않습니다. 새
버전의 Migration을 추가해 정정하고, 위험한 변경은 ADR과 리뷰를 먼저 거칩니다.

## 보안 원칙

- 운영·Staging DB에 연결하지 않습니다.
- 실제 사용자·근로자·Demo Seed 데이터를 넣지 않습니다.
- 임시 DB 값은 Workflow 내부에서만 사용합니다.
- Personal Access Token과 별도 Cloud Secret은 사용하지 않습니다.
- Workflow Action은 full-length commit SHA로 고정합니다.
- 생성 사이트에는 Schema 구조와 비민감 build metadata만 게시합니다.
50 changes: 50 additions & 0 deletions scripts/db-docs/generate-local.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RUN_ID="$$"
NETWORK_NAME="fowoco-db-docs-${RUN_ID}"
CONTAINER_NAME="fowoco-db-docs-postgres-${RUN_ID}"
POSTGRES_IMAGE="${DB_DOCS_POSTGRES_IMAGE:-postgres:17-alpine}"
DATABASE_NAME="fowoco_docs"
DATABASE_USER="fowoco_docs"
DATABASE_PASSWORD="fowoco_docs_local_only"

if ! command -v docker >/dev/null 2>&1 || ! docker info >/dev/null 2>&1; then
echo "[db-docs] 실행 중인 Docker Desktop 또는 Docker Engine이 필요합니다." >&2
exit 1
fi

cleanup() {
docker rm -f "${CONTAINER_NAME}" >/dev/null 2>&1 || true
docker network rm "${NETWORK_NAME}" >/dev/null 2>&1 || true
}
trap cleanup EXIT INT TERM

docker network create "${NETWORK_NAME}" >/dev/null
docker run -d --rm \
--name "${CONTAINER_NAME}" \
--network "${NETWORK_NAME}" \
-e "POSTGRES_DB=${DATABASE_NAME}" \
-e "POSTGRES_USER=${DATABASE_USER}" \
-e "POSTGRES_PASSWORD=${DATABASE_PASSWORD}" \
"${POSTGRES_IMAGE}" >/dev/null

for attempt in $(seq 1 30); do
if docker exec "${CONTAINER_NAME}" pg_isready -U "${DATABASE_USER}" -d "${DATABASE_NAME}" >/dev/null 2>&1; then
break
fi
if [[ "${attempt}" == "30" ]]; then
echo "[db-docs] PostgreSQL이 준비되지 않았습니다." >&2
exit 1
fi
sleep 1
done

DB_DOCS_DOCKER_NETWORK="${NETWORK_NAME}" \
DB_DOCS_CONTAINER_HOST="${CONTAINER_NAME}" \
DB_DOCS_EPHEMERAL=true \
DB_DOCS_DATABASE="${DATABASE_NAME}" \
DB_DOCS_USER="${DATABASE_USER}" \
DB_DOCS_PASSWORD="${DATABASE_PASSWORD}" \
"${SCRIPT_DIR}/generate.sh"
Loading
Loading