# 60갑자 일주자료의 표준 데이터로 완전 통합한 명리학 시스템 구축기

- 작성자: [블루스](https://community.clauders.ai/member/imported-member-tXX6csRDH3)
- 공간: [바이브 코딩](https://community.clauders.ai/claude-code)
- 게시: 2025-11-16
- 연재: [Rails로 화면부터 서버까지 만들기](https://community.clauders.ai/series/solo-fullstack-rails) 1/2편
- 태그: #JSON처리 #RAG #Markdown파싱 #데이터표준화 #명리학 #벡터DB #데이터구조화 #데이터통합 #60갑자 #일주 #Dify #1인풀스택
- 주소: https://community.clauders.ai/claude-code/post/60%EA%B0%91%EC%9E%90-%EC%9D%BC%EC%A3%BC%EC%9E%90%EB%A3%8C%EC%9D%98-%ED%91%9C%EC%A4%80-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A1%9C-%EC%99%84%EC%A0%84-%ED%86%B5%ED%95%A9%ED%95%9C-%EB%AA%85%EB%A6%AC%ED%95%99-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%EC%B6%95%EA%B8%B0-84ee2fb6-bb66-8dee-a82b-2b3e5ac03c93

---

## 소개

**시도하고자 했던 것**

명리학(사주) 교육 및 상담 시스템인 "한바둑 명리학 시스템"을 개발하면서,

60갑자 일주(日柱) 데이터를 체계적으로 정리하고자 했습니다.

하지만 문제가 있었습니다:

**11개의 서로 다른 파일**에 데이터가 흩어져 있음

**8가지 다른 구조** (JSON 키명과 계층이 모두 다름)

**중복, 누락, 비표준화**로 인한 활용 불가능

향후 **DB 마이그레이션**과 **AI 연동**을 위해 표준화 필수

**그 이유**

60갑자는 명리학의 핵심 개념으로, 각 일주마다:

기본 특성 (오행, 음양)

성격과 심리

대인관계

직업과 재물운

건강과 생활

발전 방향

특징 요약

이 **7가지 필드**로 체계화하여,

사용자가 자신의 사주를 입력하면 AI가 자동으로 통변(해석)을 생성하는 시스템을 만들고자 했습니다.

하지만 수작업으로 60개 일주 × 7필드 = **420개 필드**를 정리하는 것은 현실적으로 불가능했고,

Claude의 도움을 받기로 했습니다.

## 진행 방법

**사용 도구**

**Claude Sonnet 4.5** (Computer Use)

**Python 3** (데이터 분석 및 변환)

**JSON** (데이터 포맷)

**Bash** (파일 관리)

**전체 프로세스 (3단계)**

**Phase 1: 파일 분석 및 자동 매핑**

먼저 11개 파일의 구조를 분석했습니다.

**프롬프트 예시:**

11개 파일을 분석하고, 각 파일의 구조와 일주 개수를 파악해줘. 특히 필드 이름이 어떻게 되어 있는지 확인해줘.

**실행 코드:**

```
import json
import os

files = [
    '5개_일주_7필드_통합_2.json',
    '5개_일주_7필드_통합_3.json',
    # ... 총 11개 파일
]

for filename in files:
    with open(filename, 'r', encoding='utf-8') as f:
        data = json.load(f)
  
    # 구조 파악
    if isinstance(data, dict):
        if 'iljus' in data:
            iljus = data['iljus']
        elif 'data' in data:
            iljus = data['data']
    elif isinstance(data, list):
        iljus = data
  
    # 일주명 추출
    for ilju in iljus:
        name = ilju.get('pillar_name') or ilju.get('일주명') or ilju.get('ilju_name')
        print(f"발견: {name}")
```

python

import json import os files = [ '5개_일주_7필드_통합_2.json', '5개_일주_7필드_통합_3.json', _# ... 총 11개 파일_ ] for filename in files: with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) _# 구조 파악_ if isinstance(data, dict): if 'iljus' in data: iljus = data['iljus'] elif 'data' in data: iljus = data['data'] elif isinstance(data, list): iljus = data _# 일주명 추출_ for ilju in iljus: name = ilju.get('pillar_name') or ilju.get('일주명') or ilju.get('ilju_name') print(f"발견: {name}")

**발견된 8가지 구조:**

**standard** (29개): 필드1_기본_특성, 필드2_성격_심리 ...

**english** (5개): field1_intro, field2_personality ...

**korean** (5개): 서론, 기본성향, 특징 ...

**alternative** (6개): 개요, 성격과_기질 ...

**daymaster** (5개): basic_understanding, yin_yang_elements ...

**summary_style1** (2개): element_structure, personality_core ...

**summary_style2** (2개): field1_personality, field2_career ...

**markdown** (6개): content (긴 마크다운 텍스트)

**자동 매핑 코드:**

```
# 필드 매핑 규칙 정의
FIELD_MAPPINGS = {
    'english': {
        'field1_intro': '필드1_기본_특성',
        'field2_personality': '필드2_성격_심리',
        'field3_career_wealth': '필드4_직업_재물',
        'field4_love_marriage': '필드3_대인관계_사회성',
        'field5_health': '필드5_건강_생활',
        'field6_fortune_cycles': '필드6_발전방향',
        'field7_life_advice': '필드7_특징_요약'
    },
    # ... 총 8가지 매핑 규칙
}

def map_to_standard_fields(original_data, structure_type):
    mapping = FIELD_MAPPINGS[structure_type]
    standard_fields = {}
  
    for original_key, standard_key in mapping.items():
        if original_key in original_data:
            standard_fields[standard_key] = original_data[original_key]
  
    return standard_fields
```

python

_# 필드 매핑 규칙 정의_ FIELD_MAPPINGS = { 'english': { 'field1_intro': '필드1_기본_특성', 'field2_personality': '필드2_성격_심리', 'field3_career_wealth': '필드4_직업_재물', 'field4_love_marriage': '필드3_대인관계_사회성', 'field5_health': '필드5_건강_생활', 'field6_fortune_cycles': '필드6_발전방향', 'field7_life_advice': '필드7_특징_요약' }, _# ... 총 8가지 매핑 규칙_ } def map_to_standard_fields(original_data, structure_type): mapping = FIELD_MAPPINGS[structure_type] standard_fields = {} for original_key, standard_key in mapping.items(): if original_key in original_data: standard_fields[standard_key] = original_data[original_key] return standard_fields

**결과:** 54개 일주 자동 변환 완료

**Phase 2: 빈 필드 자동 생성**

Phase 1 후 26개 일주에 빈 필드가 발견되었습니다.

**프롬프트 예시:**

빈 필드를 자동으로 채워줘. - 필드6 (발전방향): 일반론 템플릿 활용 - 필드7 (특징_요약): 다른 필드에서 핵심 문장 추출 - 필드5 (건강_생활): 오행론 기반 생성 - 필드1 (기본_특성): 필드2, 4에서 요약

**발전방향 생성 코드:**

```
def generate_field6_development(ilju):
    name = ilju['간지']
  
    development = f"**{name}일주의 발전 방향**\n\n"
    development += f"""
**단기 목표 (1-3년)**
- 현재 분야에서의 전문성 강화
- 인적 네트워크 구축 및 확장
- 재정 기반 안정화

**중기 목표 (3-10년)**
- 자신만의 독특한 강점 개발
- 리더십 역량 키우기
- 안정적 수입원 다각화

**장기 발전**
- 지속 가능한 성장 패턴 확립
- 사회적 영향력 확대
- 후학 양성 및 지식 전수
"""
    return development
```

python

def generate_field6_development(ilju): name = ilju['간지'] development = f"**{name}일주의 발전 방향**\n\n" development += f""" **단기 목표 (1-3년)** - 현재 분야에서의 전문성 강화 - 인적 네트워크 구축 및 확장 - 재정 기반 안정화 **중기 목표 (3-10년)** - 자신만의 독특한 강점 개발 - 리더십 역량 키우기 - 안정적 수입원 다각화 **장기 발전** - 지속 가능한 성장 패턴 확립 - 사회적 영향력 확대 - 후학 양성 및 지식 전수 """ return development

**건강 관리 생성 코드:**

```
def generate_field5_health(ilju):
    ilgan = ilju['간지'][0]  # 천간
  
    # 오행별 주의 부위
    health_by_element = {
        '갑': ('목', '간담', '눈', '근육'),
        '을': ('목', '간담', '신경계', '목덜미'),
        '병': ('화', '심장', '소장', '혈액순환'),
        '정': ('화', '심장', '눈', '정신'),
        '무': ('토', '비위', '소화기', '피부'),
        # ...
    }
  
    element, organs = health_by_element.get(ilgan, ('오행', '장부'))[:2]
  
    health = f"""
**주의할 부위**
{ilgan}({element}) 일간으로 {organs}에 주의가 필요합니다.

**건강 관리 포인트**
1. 규칙적인 생활
2. 스트레스 관리
3. 균형 잡힌 식습관
4. 정기 검진
"""
    return health
```

python

def generate_field5_health(ilju): ilgan = ilju['간지'][0] _# 천간_ _# 오행별 주의 부위_ health_by_element = { '갑': ('목', '간담', '눈', '근육'), '을': ('목', '간담', '신경계', '목덜미'), '병': ('화', '심장', '소장', '혈액순환'), '정': ('화', '심장', '눈', '정신'), '무': ('토', '비위', '소화기', '피부'), _# ..._ } element, organs = health_by_element.get(ilgan, ('오행', '장부'))[:2] health = f""" **주의할 부위** {ilgan}({element}) 일간으로 {organs}에 주의가 필요합니다. **건강 관리 포인트** 1. 규칙적인 생활 2. 스트레스 관리 3. 균형 잡힌 식습관 4. 정기 검진 """ return health

**결과:** 41개 빈 필드 생성 완료

**Phase 3: Markdown 텍스트 파싱**

6개 일주는 긴 Markdown 형식 텍스트였습니다.

**프롬프트 예시:**

이 Markdown 텍스트를 7개 섹션으로 나눠줘. - ## 서론 → 필드1 - ## 성격, 성향 → 필드2 - ## 결혼, 가족 → 필드3 - ## 직업, 재물 → 필드4 - ## 건강 → 필드5 - ## 기타 → 필드6

**파싱 코드:**

```
import re

def parse_markdown_to_7fields(content):
    sections = {}
    current_section = None
    current_content = []
  
    # ## 헤더 기준으로 분리
    for line in content.split('\n'):
        if line.startswith('## '):
            if current_section:
                sections[current_section] = '\n'.join(current_content).strip()
  
            current_section = re.sub(r'[^\w\s가-힣]', '', line.replace('##', '')).strip()
            current_content = []
        else:
            if current_section:
                current_content.append(line)
  
    # 섹션을 필드로 매핑
    standard_fields = {}
    for section_name, content in sections.items():
        if '서론' in section_name:
            standard_fields['필드1_기본_특성'] = content
        elif '성격' in section_name or '성향' in section_name:
            standard_fields['필드2_성격_심리'] = content
        # ...
  
    return standard_fields
```

python

import re def parse_markdown_to_7fields(content): sections = {} current_section = None current_content = [] _# ## 헤더 기준으로 분리_ for line in content.split('\n'): if line.startswith('## '): if current_section: sections[current_section] = '\n'.join(current_content).strip() current_section = re.sub(r'[^\w\s가-힣]', '', line.replace('##', '')).strip() current_content = [] else: if current_section: current_content.append(line) _# 섹션을 필드로 매핑_ standard_fields = {} for section_name, content in sections.items(): if '서론' in section_name: standard_fields['필드1_기본_특성'] = content elif '성격' in section_name or '성향' in section_name: standard_fields['필드2_성격_심리'] = content _# ..._ return standard_fields

**결과:** 6개 일주 완전 파싱 (평균 13,000자 → 7필드 분배)

**최종 통합**

**통합 코드:**

```
# 60갑자 순서로 정렬
gapja_order = [
    '갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유',
    # ... 60개
]

sorted_iljus = []
for gapja in gapja_order:
    if gapja in all_iljus_data:
        sorted_iljus.append(all_iljus_data[gapja])

# 최종 JSON 생성
integrated_data = {
    'metadata': {
        'title': '60갑자 일주 완전 통합 데이터',
        'version': '3.0',
        'created_at': datetime.now().isoformat(),
        'total_iljus': 60
    },
    'iljus': sorted_iljus
}

with open('60개_일주_표준화_완전판_v3_0_FINAL.json', 'w', encoding='utf-8') as f:
    json.dump(integrated_data, f, ensure_ascii=False, indent=2)
```

python

_# 60갑자 순서로 정렬_ gapja_order = [ '갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', _# ... 60개_ ] sorted_iljus = [] for gapja in gapja_order: if gapja in all_iljus_data: sorted_iljus.append(all_iljus_data[gapja]) _# 최종 JSON 생성_ integrated_data = { 'metadata': { 'title': '60갑자 일주 완전 통합 데이터', 'version': '3.0', 'created_at': [datetime.now](http://datetime.now)().isoformat(), 'total_iljus': 60 }, 'iljus': sorted_iljus } with open('60개_일주_표준화_완전판_v3_0_FINAL.json', 'w', encoding='utf-8') as f: json.dump(integrated_data, f, ensure_ascii=False, indent=2)

## 결과와 배운 점

**최종 결과**

✅ **60개 전체 일주 완성** (100%)

✅ **420개 필드** (60개 × 7필드) 모두 채움

✅ **588,104자**의 구조화된 콘텐츠

✅ **1.25MB** 통합 JSON 파일

**필드별 평균 글자 수:**

필드1 (기본_특성): 1,789자

필드2 (성격_심리): 1,853자

필드3 (대인관계_사회성): 1,329자

필드4 (직업_재물): 1,618자

필드5 (건강_생활): 1,109자

필드6 (발전방향): 925자

필드7 (특징_요약): 1,177자

**배운 점**

**1. 작은 단위로 나누기**

처음엔 "60개 파일을 한 번에 통합해줘"라고 했다가 실패했습니다. 대신:

파일 구조 분석

비슷한 구조끼리 그룹화

Phase별 처리

최종 통합

이렇게 단계를 나누니 성공했습니다.

**2. 원본 데이터 보존의 중요성**

통합 JSON에 원본 데이터를 모두 보존했습니다:

```
{
  "일주명": "갑자일주",
  "표준_7필드": { ... },
  "원본_데이터": { ... },  // 원본 보존!
  "원본_파일": "10개_일주_통합_최종.json",
  "변환_방법": "markdown_parsing"
}
```

json

{ "일주명": "갑자일주", "표준_7필드": { ... }, "원본_데이터": { ... }, _// 원본 보존!_ "원본_파일": "10개_일주_통합_최종.json", "변환_방법": "markdown_parsing" }

나중에 "이 변환이 맞나?"를 확인할 수 있어 안심이 되었습니다.

**3. 검증 코드 작성**

각 단계마다 검증 코드를 작성했습니다:

```
# 빈 필드 확인
empty_count = sum(1 for v in ilju['표준_7필드'].values() if not v.strip())

# 60갑자 순서 확인
missing = [i for i in range(1, 61) if i not in gapja_nums]

# 중복 확인
duplicates = {name: count for name, count in Counter(names).items() if count > 1}
```

python

_# 빈 필드 확인_ empty_count = sum(1 for v in ilju['표준_7필드'].values() if not v.strip()) _# 60갑자 순서 확인_ missing = [i for i in range(1, 61) if i not in gapja_nums] _# 중복 확인_ duplicates = {name: count for name, count in Counter(names).items() if count > 1}

도움 받은 글 (옵션)

**참고한 자료**

**Claude 공식 문서**

Computer Use 가이드

파일 처리 베스트 프랙티스

**명리학 참고 서적**

『연해자평(淵海子平)』

『명리정종(命理正宗)』

『적천수(滴天髓)』

『자평진전(子平眞詮)』

**데이터 표준화 사례**

PostgreSQL JSON 처리

대용량 텍스트 구조화

벡터 DB 설계
