반응형

AI를 기반으로 개발시에는 개발일지를 작성하는 것이 좋습니다.

 

1. AI와의 협업 효율 극대화 (컨텍스트 복원)

  • 새로운 대화창에서도 끊김 없는 작업: AI와의 대화가 길어지거나 며칠 뒤 새 세션을 시작할 때, AI에게 *"어제 개발일지(docs/devlog/...) 읽고 다음 작업 시작해줘"*라고만 하면 AI가 전체 프로젝트 히스토리와 다음 할 일을 1초 만에 파악합니다.
  • 같은 오류 반복 방지: AI가 이전에 겪었던 오류나 시도했다가 실패한 방식을 개발일지를 통해 인지하므로, 비효율적인 답변을 반복하지 않습니다.

2. '삽질'의 자산화 (트러블슈팅 시간 절약)

  • 미래의 나를 위한 공략집: 개발 중 겪는 라이브러리 충돌, 폰트 깨짐, API 인증 오류 등은 2~3달 뒤에 또 발생할 확률이 높습니다.
  • 해결 과정을 일지에 한 번 적어두면, 나중에 동일한 문제가 생겼을 때 몇 시간 동안 구글링할 필요 없이 10초 만에 해결할 수 있습니다.

3. 작업 전환 비용(Context Switching) 제로화

  • "어제 어디까지 했더라?" 방지: 퇴근 후나 며칠 쉬고 다시 코드를 열었을 때, 어디서부터 손대야 할지 막막해지는 현상을 완전히 없애줍니다.
  • 일지 마지막의 📌 Next Steps(다음 할 일) 체크리스트만 보고 바로 코딩에 몰입할 수 있습니다.

4. "왜 이렇게 짰지?"에 대한 의사결정 기록 (Architecture Decision)

  • 코드는 '어떻게(How)' 구현했는지만 보여주지만, 개발일지는 '왜(Why)' 그 라이브러리를 골랐고 그 방식을 택했는지를 남겨줍니다.
  • 나중에 코드를 리팩토링하거나 기능을 확장할 때 중요한 나침반 역할을 합니다.

5. 강력한 포트폴리오 & 기술 블로그 콘텐츠

  • 프로젝트가 끝난 뒤 포트폴리오나 기술 블로그(Velog, Medium 등)를 쓰려고 하면 기억이 안 나서 막막합니다.
  • 매일 누적된 개발일지는 그대로 다듬기만 하면 가장 진정성 있고 설득력 있는 기술 블로그 글이자 포트폴리오가 됩니다.

 

vs code 또는 Anitigravity에서 다음과 같이 지시합니다.

 

[ 프롬프트 ]

당신은 이 프로젝트의 테크니컬 리드이자 페어 프로그래머입니다. 우리는 이 프로젝트의 모든 개발 과정을 일자별 개발일지로 투명하게 기록합니다.

[개발일지 작성 규칙]
- 주요 기능 구현이나 리팩토링, 버그 수정이 완료되면 항상 `docs/devlog/` 폴더에 일자별 마크다운 파일(`YYYY-MM-DD.md`)을 생성하거나 갱신합니다.
- 단순 작업 나열이 아니라, "왜 이 기술/라이브러리를 선택했는지", "어떤 오류가 있었고 어떻게 해결했는지"에 대한 기술적 맥락(Context)을 반드시 남깁니다.
- 코드 파일 경로와 함수명은 백틱(`) 또는 마크다운 링크 형식으로 명확히 기재합니다.

 

[ 개발일지 포맷 예시 ]

 

# 📅 개발일지: YYYY-MM-DD

## 🎯 오늘의 목표
- [x] Streamlit 기반 기본 UI 대시보드 레이아웃 구성
- [ ] Gemini API 연동 및 프롬프트 파이프라인 테스트

---

## 🛠️ 주요 진행 및 구현 내용

### 1. [컴포넌트/기능명]
- **파일:** `src/components/card_preview.py`, `app.py`
- **구현 세부사항:**
  - 사용자로부터 URL/키워드를 입력받는 사이드바 구현
  - 4:5 비율 카드뉴스 슬라이드 렌더링 영역 배치

### 2. [추가 작업 내용]
- ...

---

## 💡 기술적 의사결정 및 트러블슈팅 (Troubleshooting)

### 1. [문제 발생 상황 또는 고민한 점]
- **문제/이슈:** HTML-to-Image 렌더링 시 한글 폰트가 깨지는 현상 발생
- **원인 분석:** 기본 시스템 폰트에 Noto Sans KR이 누락되어 있음
- **해결 방안:** 웹 폰트(Google Fonts Noto Sans KR)를 인라인 CSS `@import` 방식으로 강제 로드하여 해결

---

## 🧪 테스트 및 검증 결과
- `streamlit run app.py` 로컬 실행 정상 확인
- 샘플 텍스트 입력 시 5장 슬라이드 실시간 미리보기 반응 속도 0.5초 이내 확인

---

## 📌 다음 진행 예정 작업 (Next Steps)
- [ ] Gemini Flash API 연동 모듈 (`src/ai/generator.py`) 구현
- [ ] 슬라이드 텍스트 인라인 편집 상태 관리(Session State) 연결

반응형
반응형
📱 서비스 PRD & 기획서

[서비스 PRD] 인스타그램 반자동화 마케팅 솔루션 (Instar Studio): AI 릴스·카드뉴스 기획부터 계정 제재 없는 스마트 발행까지

매일 반복되는 인스타그램 피드/릴스 제작 피로도를 80% 줄이고, 섀도우밴 위험 없이 퍼스널 브랜딩과 마케팅 수익을 동시에 달성하는 올인원 반자동화 서비스 기획서입니다.

📌 Instar Studio 서비스 PRD 핵심 요약

  • Human-in-the-Loop 8:2 반자동화: AI가 콘텐츠 기획과 카드뉴스/대본의 80%를 자동 생성하고, 사용자가 1~2분 간 검토(20%)하여 계정 안전성 확보.
  • 섀도우밴(Shadowban) & 제재 완벽 차단: 100% 무인 매크로의 계정 영구 정지 위험을 해결하는 개별 쿠키 세션 및 스마트 핑거프린트 분리 기술 탑재.
  • 2-트랙 브랜드 성장 전략: 전문성 구축을 위한 지식·테크 브랜딩 계정과 빠른 현금 흐름 창출을 위한 수익형 커머스/제휴 마케팅 계정 동시 지원.
  • 10분 완성 릴스·카드뉴스 파이프라인: 실시간 AI 트렌드 분석 → SEO 타겟 캡션/해시태그 추출 → 원클릭 에디터 → 자동 예약 포스팅.

1. 서비스 기획 배경 및 해결하고자 하는 문제 (Problem & Solution)

인스타그램은 퍼스널 브랜딩과 사업 마케팅에 있어 선택이 아닌 필수 채널입니다. 하지만 많은 크리에이터와 소상공인, 마케터들이 다음과 같은 3대 장벽에 부딪혀 지속적인 운용에 실패하곤 합니다.

🚨 기존 인스타그램 운용의 3대 Pain Point

  • 과도한 시간 소요 (제작 피로도): 기획, 이미지/카드뉴스 디자인, 릴스 대본 작성, 해시태그 연구까지 포스팅 1편에 2~3시간 이상 소요.
  • 100% 무인 봇 사용 시 계정 차단 위험: 기존의 대량 댓글/좋아요 봇이나 스팸성 무인 자동 포스팅 툴은 인스타그램 인공지능 탐지 시스템에 의해 섀도우밴 또는 계정 정지 처분.
  • 지속적인 소재 고갈: 타겟 독자가 반응할 만한 실시간 트렌드 주제와 고단가 스폰서십 키워드를 매일 발굴하기 어려움.

Instar Studio는 이러한 문제를 해결하기 위해 "가장 안전하면서도 가장 빠른 반자동화(Semi-Automation)" 아키텍처를 도입했습니다. AI가 복잡한 조사와 디자인 초안을 준비하고, 사용자는 승인 버튼만 누르는 시스템입니다.

2. 2-트랙 인스타그램 마케팅 운영 전략

목적에 따라 전략을 명확히 분리하여, 단기 현금 흐름과 장기적인 브랜드 권위를 동시에 확보합니다.

구분 🌟 트랙 A: 퍼스널 브랜딩 & 크리에이터 💰 트랙 B: 커머스 & 수익형 마케팅
운영 목적 전문 분야 권위 확보, 인플루언서 성장, 수강생/클라이언트 유입 제휴 마케팅, 공동구매, 자사몰 제품 대량 홍보, 빠른 매출 창출
핵심 콘텐츠 • IT/AI/자기계발 지식 꿀팁 카드뉴스
• 숏폼 릴스 자막 대본 & 튜토리얼
• 실무 경험담 및 성공 노하우 분석
• 핫딜/할인 정보 및 트렌드 아이템 리뷰
• 생활 꿀팁 연계 제휴 상품 추천
• 카드뉴스 형태 프로모션 및 이벤트 안내
생성 방식 Human-Led (AI 보조)
AI가 자료 조사/구조화(70%) + 사용자 인사이트(30%)
AI-Led (Human 보조)
AI 실시간 핫 이슈 템플릿 대량생성(90%) + 원클릭 검토(10%)
수익 모델 브랜드 협찬, 강연, 전자책, 컨설팅, 고단가 외주 파트너십 쿠팡파트너스/알리 제휴 링크, 자사몰 직결 유입, 소상공인 마케팅 대행

3. 핵심 기능 명세 (5대 파이프라인 모듈)

┌─────────────────┐ ──> ┌─────────────────┐ ──> ┌─────────────────┐ ──> ┌─────────────────┐
│ 1. AI 트렌드 │ │ 2. 카드뉴스/릴스│ │ 3. 반자동 │ │ 4. 멀티 계정 │
│ 기획 모듈 │ │ 생성 엔진 │ │ 검토 UI │ │ 발행 모듈 │
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘

3.1 [모듈 1] 실시간 AI 트렌드 & 타겟팅 기획기

  • 실시간 핫이슈 & 검색량 분석: Gemini 3.6 Flash 엔진이 구글 트렌드, 네이버 실검, 인스타그램 최신 대세 해시태그를 실시간 수집.
  • SEO 최적화 캡션 & 해시태그 자동 추출: 탐색 탭(Explore Feed) 노출 알고리즘에 맞춰 메인 해시태그, 서브 해시태그, 타겟 커뮤니티 태그 3단계 조합.
  • 맞춤형 톤앤매너 프롬프트: 친근한 블로그형 어조, 위트 있는 릴스 자막형 어조, 격식 있는 전문 기사형 어조 선택 가능.

3.2 [모듈 2] 비주얼 카드뉴스 & 릴스 대본 생성 엔진

  • 4:5 카드뉴스 & 1:1 슬라이드 자동 생성: 가독성 높은 폰트와 컬러 파렛트가 적용된 HTML/CSS 템플릿 기반 카드뉴스 이미지 렌더링.
  • 숏폼 릴스(Reels) 타임라인 스크립트 작성: 0~3초 시선 집중 훅(Hook) 문구 → 본문 3대 팁 → CTA(댓글/팔로우 유도) 3단계 릴스 대본 구성.
  • 이미지 제너레이터 연동: 주제에 어울리는 고화질 프리미엄 그래픽 및 AI 합성 이미지 자동 배치.

3.3 [모듈 3] 섀도우밴 차단 듀얼 세션 & 휴먼 터치 검토 UI

  • 1분 팩트체크 & 실시간 미리보기 (Iframe Preview): 생성된 피드 이미지와 캡션을 한눈에 확인하고 오탈자 및 문맥 수정.
  • 휴먼인더루프(Human-in-the-loop) 승인 버튼: 인스타그램 어뷰징 필터를 우회하기 위해 사용자 클릭 행위(User Gesture)를 필수 포인팅으로 삽입.

3.4 [모듈 4] Playwright 기반 스마트 계정 스케줄러 & 발행 파이프라인

  • 쿠키 세션 연동 (`.instar_session.json`): 비밀번호 대량 입력 없이 최초 1회 브라우저 로그인 후 세션 안전 유지.
  • 다중 계정 관리 및 핑거프린트 분리: 여러 계정을 운영할 때 IP 및 헤드리스 브라우저 환경을 독립적으로 분리하여 계정 간 연쇄 제재 차단.
  • 원클릭 / 예약 발행 지원: 인스타그램 최적 유입 시간대(오전 8시, 점심 12시, 저녁 8시)에 맞춘 예약 업로드.

4. 기술 아키텍처 및 시스템 구상도

[ Instar Studio Tech Stack ]
• Frontend / UI : Next.js (React) / FastHTML & Tailwind Inline CSS
• Core Backend : Python 3.12, FastAPI, Uvicorn
• AI Engine : Google GenAI SDK (Gemini 3.6 Flash / Gemini 3.5 Flash)
• Browser Engine: Playwright (Headless/Headed Chrome Automation)
• Database : SQLite / Local JSON Session & History Storage
• Package format: Portable Windows EXE / Web Cloud Ready

5. 계정 안전성 및 저품질(Shadowban) 방지 정책

💡 개발진이 보장하는 3대 계정 보호 가이드라인

  1. 일일 발행 횟수 동적 조절: 1일 최대 2~3회 포스팅 제한 알고리즘을 두어 어뷰징 탐지 방지.
  2. 인간과 유사한 무작위 딜레이(Random Delay): 마우스 이동, 타이핑 속도, 클릭 간격에 무작위 시차(2~5초)를 자동 부여.
  3. 자연스러운 E-E-A-T 문맥 보장: 진부한 로봇 말투를 차단하고, 사용자의 개별 소견 및 직접 촬영 이미지 융합 지원.

6. 마치며 및 도입 안내

인스타그램 계정 성장의 핵심은 "꾸준함(Consistency)"과 "압도적인 콘텐츠 퀄리티"입니다. Instar Studio를 활용하면 하루 10분의 투자만으로 매일 1~2개의 고품질 피드와 릴스 포스팅을 지속할 수 있습니다.

 

 

 

 

반응형
반응형

 

노트북으로 AI 개발 환경 & DB & 배포 인프라 완벽 구축하기

1. 왜 노트북에 가상 서버와 DB를 구축해야 할까?

처음에 AI 공부를 하면서 비용이 많이 들었습니다.

chtGPT, CurSor, Claude, Supabase, Google API 비용등 많은 비용을 지불했습니다.

 

최소한의 비용으로 AI 개발을 진행 해보고자 합니다.

첫번째 서버 환경을 구축하려고 합니다. 

 

 

AI 개발 시 호스트 OS(Windows)에 직접 라이브러리와 CUDA, DB를 설치하면 버전 충돌로 인해 환경이 망가지기 쉽습니다.

  • 비용 0원: 비싼 클라우드 GPU 인스턴스 비용 없이 로컬에서 무제한 프로토타이핑 가능.
  • 배포 환경 일치성: 실제 운영 서버와 100% 동일한 Linux 표준 환경으로 배포 오류 방지.
  • 데이터 보안: 민감한 데이터를 외부 유출 없이 내 머신에서 안전하게 처리.
💡 하이브리드 전략:
코드 작성, 데이터 전처리, 경량 모델(1B~8B) 테스트 및 DB 연동은 로컬 노트북에서 진행하고, 대규모 분산 학습만 클라우드 GPU(RunPod, Colab 등)로 이관 합니다.

2. 기술 스택 비교 & 선택 가이드

① 가상화: WSL2 vs Oracle VirtualBox

비교 항목 WSL2 (Windows 표준) ★추천 Oracle VirtualBox
GPU(CUDA) 가속 완벽 지원 (NVIDIA GPU 바로 인식) 사실상 불가 (GPU 패스스루 불가)
자원 점유율 동적 메모리 할당 (가볍고 빠름) 고정 메모리 점유 (노트북 성능 저하)
GUI 지원 WSLg 내장 (차트/앱 창 개별 팝업) 전체 OS 화면 렌더링 (무거움)

② 데이터베이스: PostgreSQL(pgvector) vs MS SQL Server

저는 주로 오라클, MS SQL만 다루어 왔습니다. 

MS SQL은 벡터를 지원하지 않고, Oracle Database 23ai 이상)는 AI Vector Search 기능이 있다고 하나, 저는 경험해보지 못했습니다.

 

아직은 혼자서 공부하기에 DB는 PostgreSQL을 사용하기로 합니다.

벡터 임베딩 검색(Vector Embedding Search)이 필요한 가장 결정적인 이유는 글자(단어)가 정확히 일치하지 않아도 "문맥과 의미(의도)"를 파악해 원하는 정보를 찾아내기 위해서입니다.

 

 1) 기존 키워드 검색 vs 벡터 임베딩 검색

기존 SQL의 LIKE '%검색어%'나 키워드 검색은 **'정확한 철자'**가 일치해야만 결과를 찾을 수 있었습니다.

사용자 검색어기존 키워드 검색 (단어 일치)벡터 임베딩 검색 (의미 일치)
"머리가 지끈거리고 열날 때 먹는 약" ❌ '지끈', '열'이라는 단어가 없으면 검색 실패  "타이레놀 복용법", "해열진통제 효능" 문서 탐색
"휴대폰 배터리가 너무 빨리 닳아요" ❌ '스마트폰', '방전', '충전' 문서 누락  "스마트폰 사용 시간 늘리는 팁" 문서 탐색
"퇴사 절차 어떻게 됨?" ❌ 사내 문서 제목이 '의원면직 안내'면 검색 실패  "임직원 의원면직 및 인수인계 규정" 문서 탐색

 2) AI 개발에서 벡터 검색이 꼭 필요한 4가지 이유

① RAG (검색 증강 생성)의 핵심 엔진

  • LLM(챗봇)은 학습하지 않은 사내 문서나 최신 정보를 모릅니다.
  • 사용자가 질문하면 벡터 검색이 관련성 높은 사내 문서를 0.1초 만에 찾아서 LLM에게 전달하고, LLM은 그 문서를 바탕으로 거짓말(환각) 없이 정확한 답변을 작성합니다.
[사용자 질문] ──(벡터 검색)──> [사내 DB에서 관련 문서 추출] ──> [LLM이 문서 읽고 정확한 답변 생성]

② 사람의 자연스러운 질문(구어체, 오타) 완벽 처리

  • 사용자는 정형화된 검색 키워드(예: 스마트폰 AND 고장) 대신 **"어제 폰을 물에 빠뜨렸는데 소리가 안 나와"**처럼 일상 언어로 질문합니다.
  • 벡터 임베딩은 문장 전체의 의미를 다차원 좌표(숫자 배열)로 바꾸기 때문에 자연어 질문의 핵심 의도를 정확히 파악합니다.

③ 멀티모달(이미지, 음성) 검색 가능

  • 텍스트뿐만 아니라 이미지나 음성도 벡터로 변환할 수 있습니다.
  • "해변에서 노을을 보고 있는 고양이"라고 글자로 검색해도, 해당 설명이 태그로 적혀있지 않은 실제 고양이 사진 파일을 찾아낼 수 있습니다.

④ 초개인화 추천 시스템

  • 사용자가 최근 본 상품들의 벡터와 가장 거리가 가까운(취향이 유사한) 상품/음악/영상을 추천하는 데 사용됩니다.

AI/RAG 프레임워크(LangChain, LlamaIndex 등)에서는 일반 SQL과 벡터 임베딩 검색을 모두 지원하는 PostgreSQL + pgvector가 표준입니다.

3. 전체 작업 순서 (Step-by-Step 실전 구축)

 

우선 프로젝트 전용 작업폴더를 만들어 관리하는 것이 효율적입니다.

WSL2를 쓰실 때 폴더 위치에 따라 속도 차이가 5~10배 발생할 수 있습니다.

  •  가장 추천하는 위치 (WSL2 리눅스 내부 - 속도 극대화)
    • 경로: ~/projects/ai-server (Ubuntu 홈 디렉터리 내부)
    • 이유: Linux 네이티브 파일 시스템이라 Docker와 Python 라이브러리 로딩 속도가 가장 빠릅니다.
  • 🟡 윈도우 탐색기 접근 편의 우선 위치
    • 경로: C:\projects\ai-server (Windows C드라이브)
      • 이유: 윈도우 탐색기에서 찾기는 편하지만, WSL2와 입출력 시 약간의 오버헤드가 있습니다.
 
* 폴더 구조
 
ai-server/                     <-- 프로젝트 최상위 폴더
├── docker-compose.yml         <-- DB(PostgreSQL), pgAdmin 등 컨테이너 실행 설정
├── .env                       <-- DB 비밀번호, API 키 등 보안 환경변수
├── app/                       <-- AI 백엔드/서비스 소스코드 (FastAPI, Python)
│   ├── main.py
│   └── requirements.txt
└── notebooks/                 <-- Jupyter 실습 및 데이터 분석용
 
 
Antigravity에서 작업을 진행해 보겠습니다.
저는 C:\projects\ai-server 폴더를 만들었습니다.
 
터미널에서 리눅스(Ubuntu)를 설치합니다.
 
 
1 WSL2(Ubuntu) 가상 서버 설치

Windows PowerShell을 관리자 권한으로 실행 후 다음 명령어를 입력하고 PC를 재부팅합니다.

 

wsl --install

 

권한이 필요하다는 창이 나오면 허용하시면 됩니다. 설치가 완료되면 재부팅 합니다.

 
 
 
2 Docker Desktop 설치 및 WSL2 연동
 

 

설치가 완료되면 docker desktop이 실행이 됩니다. Settings > Resources > WSL Integration 에서 

'Enable integration with my default WSL distro'를 체크한 후 Apply & Restart를 합니다.

 

Linux용 Windows 하위 시스템에 설치된 배포가 없습니다. (No installed distributions)라고 나오는 경우:

  •  배포판이 전혀 설치되지 않은 상태입니다.
  • 해결법: wsl --install -d Ubuntu 명령어를 실행하여 Ubuntu를 설치

 

Create a default Unix user account: 가 나오면 엔터치고 패스워드를 입력합니다.

 

설치가 완료되면  Posershell에서 기본 배포판을 Ubuntu로 설정 합니다.

 
 
지금까지 리눅스 서버 설치하고 도커 데스크탑 설치 후 리눅스와 연동까지 했습니다.
정상적으로 잘 연동되었는지 확인해봅니다. 잘 되었습니다. ^^
 
 
 
 
3 AI 전용 DB (PostgreSQL + pgvector) 구축
Antigravity IDE에서 D:\AI 경로에 PostgreSQL 16과 웹 기반 DB 관리 도구인 Adminer를 Docker Compose로 구축하는 전체 파일 및 실행해 보겠습니다.
 

1. 프로젝트 폴더 열기 (Antigravity IDE)

  1. Antigravity IDE 상단 메뉴에서 File ➔ Open Folder... (폴더 열기)를 클릭합니다.
  2. D:\AI 폴더를 선택하여 작업 영역(Workspace)으로 엽니다. (폴더가 없다면 새로 생성)

2. 설정 파일 생성

D:\AI 폴더 루트에 아래 3개의 파일을 생성해 주세요.

📄 docker-compose.yml

yaml
 
services:
postgres:
image: postgres:16-alpine
container_name: ai_postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres1234}
POSTGRES_DB: ${DB_NAME:-aidb}
ports:
- "${DB_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-aidb}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- ai_network
 
adminer:
image: adminer:latest
container_name: ai_adminer
restart: unless-stopped
ports:
- "${ADMINER_PORT:-8080}:8080"
environment:
ADMINER_DEFAULT_SERVER: postgres
depends_on:
postgres:
condition: service_healthy
networks:
- ai_network
 
volumes:
postgres_data:
 
networks:
ai_network:
driver: bridge

📄 .env (환경 변수 설정)

env
 
# Database Settings
DB_USER=postgres
DB_PASSWORD=postgres1234
DB_NAME=aidb
DB_PORT=5432
 
# Adminer Web UI Port
ADMINER_PORT=8080

📄 init.sql (초기 실행용 SQL - 선택 사항)

최초 실행 시 DB에 테이블이나 샘플 데이터를 미리 만들어둘 수 있습니다.

sql
 
-- 예시: 기본 타임스탬프가 포함된 사용자 테이블 생성
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
 
-- 초기 테스트 데이터 삽입
INSERT INTO users (email, name)
VALUES ('admin@example.com', 'Admin')
ON CONFLICT (email) DO NOTHING;

터미널에서 powereshecll 모드이면 wsl로 모드 전환 후 다음과 같이 실행한다. *** 구동확인: 정상 ***

lg@DESKTOP-2GA0B26:/mnt/c/projects$ ls
ai-server  docker-compose.yml  init.sql
lg@DESKTOP-2GA0B26:/mnt/c/projects$ docker compose up -d
[+] up 36/36
 ✔ Image adminer:latest          Pulled                                                                    21.3s
 ✔ Image postgres:16-alpine      Pulled                                                                    21.7s
 ✔ Network projects_ai_network   Created                                                                    0.0s
 ✔ Volume projects_postgres_data Created                                                                    0.0s
 ✔ Container ai_postgres         Healthy                                                                    6.7s
 ✔ Container ai_adminer          Started

lg@DESKTOP-2GA0B26:/mnt/c/projects$ docker compose ps
NAME          IMAGE                COMMAND                  SERVICE    CREATED         STATUS                   
PORTS
ai_adminer    adminer:latest       "entrypoint.sh docke…"   adminer    4 minutes ago   Up 3 minutes             
0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp
ai_postgres   postgres:16-alpine   "docker-entrypoint.s…"   postgres   4 minutes ago   Up 4 minutes (healthy)   0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp

4. 웹 브라우저에서 Adminer 접속 및 확인

  1. 브라우저에서 http://localhost:8080 에 접속합니다.
  2. 아래 정보로 로그인합니다:
    • System(시스템): PostgreSQL
    • Server(서버): postgres (또는 ai_postgres)
    • Username(사용자명): postgres
    • Password(비밀번호): postgres1234
    • Database(데이터베이스): aidb
  3. 로그인 후 users 테이블 및 데이터를 바로 GUI로 확인/편집할 수 있습니다.

 

여기까지 나의 노트북에 서버환경을 구성하였습니다. 다음에는 서버를 활용하여 개발을 해봐야겠습니다.

 

참고) 개발 도구 조합: Antigravity와 VS Code 협업

  • Antigravity: 기획, 아키텍처 자동 설계, WSL2/Docker 명령 자동 실행, 다중 파일 구현 및 자율 디버깅 담당
  • VS Code: 동일한 폴더를 열어두고 파일 변경 내역 확인 및 세밀한 코드 다듬기 담당
반응형
반응형

 

SQL Anywhere 9 한글 깨짐(상형문자) 완벽 해결 가이드

레거시 파워빌더 9(PB 9) 시스템을 최신 파워빌더 2025(PB 2025) 로 마이그레이션하면서 구형 데이터베이스인 SQL Anywhere 9 (ASA 9)를 그대로 연동하려다 보면, 거의 100% 확률로 '한글 데이터가 한자나 상형문자로 깨져 나오는 현상'을 맞닥뜨리게 됩니다.

 

문제를 해결하기위해 여러 삽질 끝에 해결한 4가지 원인과 해결 방안을 정리하여 공유합니다.

 

windows OS 버전이 올라가면서 오래된 시스템을 당장 버릴 수 없어서 유지해야 하고 최근 windows 11로 전환해야 하는 기업에서는 고민이 될 수 있는 사항일 것 같습니다. 

늘 안정적인 환경에서 개발하다가 이런 작업을 처음 해보면서 쉽지 않은 일이었습니다.

 

이 글이 조금이라도 해결하는데 팁이 되길 바래봅니다.


🚨 왜 파워빌더 9에서는 잘 되던 한글이 2025에서는 깨질까?

근본 원인: ANSI vs Unicode 아키텍처의 충돌
PB 9은 ANSI(단순 바이트) 툴이라 DB에서 던져주는 바이트를 그대로 윈도우 OS가 해석해 한글로 그렸습니다. 하지만 PB 2025는 Unicode(UTF-16) 툴이기 때문에, ODBC 드라이버에게 무조건 유니코드 번역을 강제합니다. 이때 구형 DB 엔진이 제대로 된 번역 사전을 갖추지 못했거나 통신 설정이 어긋나면 한글 바이트가 서유럽어로 오역되어 쪼개지는 대참사가 발생합니다.

🔍 한글 깨짐 & 접속 에러를 유발하는 4가지 흑막

1. 번역 사전 (charsets 폴더) 누락

고객사 PC 등에 무설치(Portable)로 배포할 때, 보통 엔진 파일이 있는 win32 폴더만 가져가는 경우가 많습니다. 하지만 SQL Anywhere 9 설치 경로에 있는 charsets 폴더가 없으면 드라이버는 CP949를 유니코드로 번역할 능력을 상실합니다. 이 폴더가 없으면 드라이버가 무조건 영문 기준으로 번역해 버리므로 한글이 상형문자로 변합니다.

2. "읽기 전용" 파일 권한 락 (Windows 11)

Windows 11 환경에서는 보안이 엄격해져서, 백그라운드 엔진이 .db 파일과 .log 파일을 움켜쥐려 할 때 파일에 '읽기 전용' 속성이 걸려있으면 "아이디가 틀렸다" 거나 "Access Denied"라는 엉뚱한 에러를 뱉어내며 정상 접속을 튕겨냅니다. 압축파일이나 파일서버에서 복사해 온 DB 파일이라면 반드시 윈도우 우클릭 설정에서 읽기 전용을 해제해야 합니다.

3. 오염된 데이터베이스 (무방비 최초 접속)

가장 주의해야 할 부분입니다! 파워빌더 2025에서 ODBC의 한글 셋팅(CharSet=cp949)을 잡아주지 않은 상태로 단 한 번이라도 DB에 연결하면, DB 안의 데이터가 영원히 깨져버립니다!

파워빌더가 깨진 상형문자 상태로 읽어들인 뒤, 어떤 이유로든(내부 로그 저장, 실수로 갱신 등) 저장이 발생하면 그 즉시 깨진 글자가 DB 원본에 덮어씌워집니다. 이후에 설정을 고쳐도 이미 원본 데이터가 '상형문자화' 되어버리기 때문에 영영 복구되지 않습니다.

4. 환경변수 PATH와 타 버전(예: ASA 12) DLL 충돌

과거에 상위 버전인 ASA 12 클라이언트 등을 깔아본 적이 있다면 윈도우 PATH 환경변수에 12버전이 등록되어 있습니다. 이때 9버전 배치나 엔진을 돌리면 12버전 통신 DLL을 땡겨 쓰는 DLL 지옥(Hell) 현상이 발생해 이상한 에러가 납니다.


💯 가장 완벽하고 안전한 해결 프로세스 (정석)

✅ Phase 1: 파일 권한 및 폴더 세팅

  1. 개발 PC에 있는 \SQL Anywhere 9\charsets 폴더를 통째로 복사해서, 배포할 폴더 안의 win32 폴더와 나란히 놓습니다.
  2. 옮겨진 lkpis.dblkpis.log 파일을 마우스 우클릭하여 [읽기 전용] 체크를 모두 해제합니다.
  3. (중요) 그 어떤 툴이나 파워빌더 2025로도 아직 이 DB 파일을 열지 마세요! (최초 오염 방지)

✅ Phase 2: 안전한 ODBC DSN 자동화 스크립트 작성

Windows 11의 권한 상승 이슈와 PowerShell 무한 로딩, 그리고 PATH 꼬임 현상을 한 방에 해결하는 배치(.bat) 스크립트 코드를 만듭니다. (이 코드 하나면 DLL 수동 등록 및 환경변수가 완벽히 세팅됩니다.)

@echo off
:: [1] 관리자 권한 자동 획득
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' (
    echo 관리자 권한이 필요합니다...
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
    "%temp%\getadmin.vbs"
    exit /B
)
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )

:: [2] 배포 폴더를 윈도우 작업 디렉터리로 100% 확정
CD /D "%~dp0"
set "BASE_DIR=%~dp0"
if "%BASE_DIR:~-1%"=="\" set "BASE_DIR=%BASE_DIR:~0,-1%"

:: [3] 한글 방패 셋팅 (CharSet=cp949 강제 주입)
set "DSN_NAME=lkpis"
set "DSN_REG=HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\%DSN_NAME%"
reg add "%DSN_REG%" /v "CharSet" /t REG_SZ /d "cp949" /f >nul
reg add "%DSN_REG%" /v "TranslationOption" /t REG_SZ /d "cp949" /f >nul
:: (이외 드라이버 드라이버 등록 코드는 각자 환경에 맞게 추가)

:: [4] PATH 환경변수 VBScript로 안전하게 후열 추가 (1024자 제한 및 PowerShell 에러 회피)
set "ASA_PATH=%BASE_DIR%\win32"
echo Set WshShell = WScript.CreateObject("WScript.Shell") > "%temp%\addpath.vbs"
echo Set objEnv = WshShell.Environment("System") >> "%temp%\addpath.vbs"
echo strPath = objEnv("PATH") >> "%temp%\addpath.vbs"
echo If InStr(1, strPath, "%ASA_PATH%", 1) = 0 Then >> "%temp%\addpath.vbs"
echo     objEnv("PATH") = strPath ^& ";" ^& "%ASA_PATH%" >> "%temp%\addpath.vbs"
echo End If >> "%temp%\addpath.vbs"
cscript //nologo "%temp%\addpath.vbs"
del "%temp%\addpath.vbs"

echo 셋팅 완료!
pause

✅ Phase 3: 순정 백업 DB로 최종 연동 시도

  1. 관리자 권한의 위의 배치 파일을 실행시켜서 ODBC단에서 CharSet=cp949 쉴드를 먼저 완벽하게 구축합니다.
  2. 파워빌더 등에 한 번도 물리지 않은 순수한 원본 백업 DB(.db)를 폴더에 덮어씌웁니다.
  3. 이제 파워빌더 2025를 켜서 lkpis DSN을 통해 접속하고 테이블을 조회해 봅니다.

🎉 마무리

ODBC에서 cp949 방어막을 쳐둔 상태에서 깨지지 않은 DB로 최초 연결을 맺는 것. 이것이 지긋지긋한 파워빌더 유니코드 마이그레이션(한글 깨짐 현상)을 완벽하게 끝내는 마스터키였습니다. 이 글이 저와 같은 증상으로 고통받는 많은 개발자분들께 좋은 팁이 되기를 바랍니다!

반응형
반응형

 

소프트웨어 개발 패러다임은 단순한 코드 자동완성을 넘어 개발자의 의도를 스스로 파악하고 실행하는 'AI 에이전트(Agentic AI)' 체제로 완전히 전환되었습니다. 그 중심에는 앤스로픽(Anthropic)이 출시하여 개발 생태계를 뒤흔들고 있는 터미널 기반의 혁신적인 도구, '클로드 코드(Claude Code)'가 있습니다.

클로드 코드의 핵심 개념과 설치 방법, 그리고 실무 생산성을 300% 이상 끌어올릴 수 있는 고급 프롬프트 엔지니어링 전략을 상세히 공유합니다.

1. 클로드 코드(Claude Code)란 무엇인가?

클로드 코드는 개발자의 로컬 터미널(CLI) 환경에 직접 통합되어 작동하는 AI 개발 에이전트입니다. 단순히 코드를 추천해 주는 기존의 에디터 확장 프로그램(Copilot 등)과 달리, 프로젝트 전체의 아키텍처를 이해하고, 직접 명령어를 실행하며, 테스트 및 디버깅까지 스스로 수행하는 강력한 자율성을 가집니다.

구분 기존 AI 자동완성 (Copilot 등) 클로드 코드 (Claude Code)
작동 환경 IDE 플러그인 (인라인 추천) OS 터미널 (CLI) 및 프로젝트 전체 제어
맥락 이해도 현재 열려 있는 파일 위주 전체 리포지토리(Repository) 구조 분석
실행 권한 코드 제안만 가능 (수동 수락) 테스트 실행, 빌드, Git 커밋 자동화

2. 클로드 코드 설치 및 초기 설정

클로드 코드를 사용하기 위해서는 Node.js 환경과 Anthropic API 키가 필요합니다. 터미널을 열고 아래 명령어를 순서대로 입력하여 빠르고 간편하게 환경을 구축할 수 있습니다.

# 1. 클로드 코드 글로벌 패키지 설치
npm install -g @anthropic-ai/claude-code

# 2. Anthropic 계정 로그인 및 API 인증 연동
claude login

# 3. 개발 중인 프로젝트 디렉토리로 이동 후 초기화
cd ~/projects/my-awesome-app
claude init

💡 필수 팁:

claude init 실행 시 생성되는 .claudecode/config.json 파일을 통해 프로젝트별 보안 규칙 및 자동 실행 허용 명령어 범위를 반드시 설정해 두는 것이 안전합니다.

3. 실무 생산성을 높이는 프롬프트 엔지니어링 패턴

클로드 코드를 진정으로 강력하게 만드는 것은 '어떻게 질문하고 지시하느냐'에 달려 있습니다. 단순히 "이 코드 짜줘"가 아닌, 에이전트의 역량을 극대화하는 3가지 실무 프롬프트 패턴을 소개합니다.

① CO-STAR 프롬프트 프레임워크 적용

클로드에게 명령을 내릴 때 맥락(Context), 목적(Objective), 스타일(Style), 대상(Audience), 제약 조건(Response)을 명확히 명시하는 방법입니다.

[프롬프트 예시]
Context: 우리는 Next.js 15 기반의 이커머스 서비스를 개발 중이야.
Objective: 상품 상세 페이지의 이미지 지연 로딩(Lazy Loading) 및 캐싱 로직을 최적화해줘.
Style: 성능 지향적이며, TypeScript 타입 정의가 엄격하게 적용된 코드로 작성해줘.
Constraint: 외부 서드파티 라이브러리를 쓰지 말고, Next.js 내장 Image 컴포넌트만을 활용할 것.

② 점진적 리팩토링 및 테스트 주도 개발(TDD) 패턴

클로드 코드에게 테스트 코드 작성을 먼저 위임한 뒤, 해당 테스트를 통과하는 실제 비즈니스 로직을 빌드하게 만드는 방식입니다. 코드 품질과 안정성을 동시에 확보할 수 있는 최고의 방법입니다.

[프롬프트 예시]
"authService.ts 파일의 이메일 유효성 검증 로직에 대한 Vitest 테스트 케이스를 먼저 작성해줘.
그 다음, 테스트를 실행하고 실패하는 것을 확인한 뒤, 이 테스트를 모두 통과하도록 비즈니스 로직을 완성해줘."

4. 클로드 코드 실무 사용 시 핵심 주의사항

  • API 비용 관리: 클로드 코드는 프로젝트 전체 맥락을 읽기 때문에 토큰 소모량이 많을 수 있습니다. 불필요한 대형 바이너리 파일이나 빌드 결과물(dist, build 등)은 .gitignore 또는 .claudeignore 파일에 반드시 등록하세요.
  • 명령어 실행 권한 설정: 클로드 코드가 터미널 명령어를 직접 실행할 때, 데이터베이스 삭제(drop)나 중요 환경 변수 변경과 같은 민감한 작업은 반드시 수동 승인(Manual Approval)을 거치도록 설정하세요.
  • 보안 및 프라이버시: 사내 중요 자산이나 개인 정보가 포함된 데이터 파일이 클로드 API 전송 스트림에 포함되지 않도록 필터링 규칙을 정교하게 다듬어야 합니다.

5. 마치며: AI와 함께 협업하는 개발자의 미래

뛰어난 개발자는 코드를 타이핑하는 속도가 빠른 사람이 아닙니다. AI 에이전트에게 명확한 컨텍스트를 제공하고, 아키텍처 수준의 올바른 설계를 지시하며, 생성된 결과물을 정확히 검증할 수 있는 개발자가 시장을 선도합니다. 오늘 소개한 클로드 코드와 프롬프트 엔지니어링 가이드를 통해 여러분의 개발 생산성을 한 단계 더 업그레이드해 보세요.

반응형
반응형

 

Windows 11 환경으로 마이그레이션하면서 기존에 사용하던 Informix Client SDK (CSDK) 연동 문제로 고생좀 했습니다.^^

기존 배포파일에 포함된 인포믹스 설치 파일이 없어서 고객사가 제공해준 sdk로 설치를 진행하면서 헤매이었던 과정들을 정리하여 공유 합니다.

 

크게 1) 아무리 최신 버전(V4.5)을 깔아도 드라이버 인식이 안 되는 문제, 그리고 2) 설치(인스톨러) 화면 자체가 아예 뜨지 않고 튕겨버리는 문제 두 가지 함정에 빠지기 쉽습니다. 오늘은 이 두 가지 문제의 명확한 원인과 확실한 해결법을 총정리해 드립니다.

🚨 함정 1. 버전 아키텍처 불일치 (32비트 앱과 64비트 드라이버)

가장 많이 겪는 착각 중 하나가 "가장 최신 버전인 Informix Client SDK V4.5를 다운받아 설치하면 문제없겠지?"라는 생각입니다.

 주의: Informix CSDK V4.5에는 32비트 버전이 없습니다.

IBM/HCL 정책에 따라 Client SDK V4.5 이상부터는 오직 64비트(x86_64) 전용으로만 릴리즈되고 있습니다.

왜 32비트 애플리케이션에서 64비트 ODBC 드라이버를 쓸 수 없을까?

결론부터 말하자면 "메모리 주소 공간이 완벽히 분리되어 있기 때문"입니다. 64비트 Windows 운영체제에서 32비트 프로그램들은 `WoW64 (Windows 32-bit on Windows 64-bit)`라는 서브시스템(가상의 32비트 격리 공간) 안에서 실행됩니다.

  • 32비트 애플리케이션 (예: 기존 PowerBuilder) : 32비트용 DLL 라이브러리만 로드하여 사용할 수 있습니다.
  • 64비트 ODBC 드라이버 (CSDK V4.5) : 64비트 메모리 주소를 사용하도록 컴파일되어 있습니다.

즉, 32비트 프로그램이 데이터베이스에 접속하기 위해 64비트 ODBC 드라이버(DLL)에 접근하려고 시도하면 운영체제가 이를 하드웨어 차원에서 차단해버리게 되고, 결국 "드라이버를 찾을 수 없습니다" 또는 연동 실패 에러가 발생하게 되는 것입니다.

✅ 해결책: CSDK V4.10 (32비트)로 다운그레이드

만약 운영 중인 레거시 앱이 32비트 기반이라면, 반드시 32비트를 마지막으로 지원했던 버전인 Client SDK V4.10 (x86) 버전을 구해서 설치하셔야 합니다. 그래야만 setnet32.exe와 32비트 ODBC 관리자 환경이 정상적으로 연동됩니다.

🚨 함정 2. 인스톨러 GUI 실행 불가 (OS 인식 오류)

그렇다면 알맞게 V4.10 (32비트) 설치 파일을 다운로드해서 실행해 보려는데... এবার은 설치 창 자체가 안 뜨고 모래시계만 잠깐 돌다가 튕겨버리는 증상이 발생합니다.

 원인: InstallAnywhere (Java 기반) 버그

구버전 설치 프로그램 내장 Java가 최신 운영체제인 'Windows 11'이라는 이름을 OS로 인식하지 못하기 때문입니다. os.name 값에 매칭되는 지원 OS 목록이 없으면 패키징된 인스톨러가 치명적 에러로 간주해 자체 종료해 버립니다.

✅ 해결 방법: 환경변수(JAVA_TOOL_OPTIONS) 속이기

설치를 진행할 때 인스톨러에게 "이 컴퓨터는 Windows 11이 아니라 Windows 7이야"라고 거짓말을 치면 깔끔하게 해결됩니다.

  • 명령 프롬프트를 관리자 권한으로 실행
    작업 표시줄 돋보기 버튼에서 cmd를 검색한 뒤 '관리자 권한으로 실행'을 클릭합니다.
  • Java OS Name 환경변수 임시 세팅
    명령 프롬프트 창에 아래 명령어를 입력하고 엔터를 누릅니다.
    set "JAVA_TOOL_OPTIONS=-Dos.name=Windows 7"
  • 설치 파일 경로로 이동 및 실행
    cd 명령어로 설치 파일이 있는 경로로 이동한 뒤 설치 파일 .exe를 실행합니다.
    cd C:\Users\사용자\Downloads\Informix_SDK_4.10_32bit
    installclientsdk.exe

CMD 창에 Picked up JAVA_TOOL_OPTIONS: -Dos.name=Windows 7 이라는 문구가 출력되면서, 실패했던 마법사 UI 창이 정상적으로 로딩되고 무사히 설치를 완료할 수 있습니다.

🚨 함정 3. 마이그레이션 후 DB 접속 언어셋(Locale) 에러 (-23197, -23101)

CSDK 마이그레이션(예: V2.70 → V4.10) 후 기존 파워빌더 등에서 DB 접속 시 다음과 같은 언어셋 에러가 발생하는 경우가 많습니다.

  • SQL Error -23197 : Database locale information mismatch
  • SQL Error -23101 : Unable to load locale categories (언어셋을 euc-kr 등으로 임의 입력했을 때 발생)

왜 구버전에서는 잘 되었는데 지금은 안 될까?

가장 큰 원인은 신버전 CSDK의 엄격해진 GLS(Global Language Support) 검증 로직 때문입니다.

과거 구버전(V2.70)은 DB_LOCALE이나 CLIENT_LOCALE 값이 비어있어도 느슨하게 파싱하여 접속을 허용(가비지 인 가비지 아웃)했습니다. 하지만 신버전(V4.10)은 클라이언트가 설정한 로케일 값과 DB 서버가 실제로 생성될 때 세팅된 로케일 값이 100% 일치하지 않으면 접속을 원천 차단(-23197)합니다. 또한 Informix는 고유의 언어셋 명칭 규칙(`언어_국가.코드셋`)을 따르므로 통상적인 euc-kr은 인식하지 못해 -23101 에러를 발생시킵니다.

✅ 해결책: 알맞은 Locale 값 찾기 및 적용

해결을 위해서는 서버의 진짜 Locale을 알아내 Setnet32 또는 어플리케이션(파워빌더 DB Profile 등)에 정확히 입력해야 합니다. 한국 환경에서 주로 등장하는 다음 값들을 순서대로 테스트해 보세요.

  • ko_kr.949 또는 ko_kr.cp949 (Windows 환경 기본 한글)
  • ko_kr.utf8 (최신 표준 환경)
  • en_us.819 (★ 레거시 치트키) : 가장 오래된 시스템일수록 영어 기본값 상에 한글 바이트를 그대로 밀어넣어 사용하는 방식을 많이 썼습니다. -> 여러 locale 값을 대응하여 찾은 값!!!! 으로 해결~

⚠️ 추가 주의사항 (비밀번호 및 레지스트리 경로)

최신 CSDK 4.10 부터는 보안 정책 강화로 인해 Setnet32에 Host Password 저장을 지원하지 않습니다. 비밀번호는 직접 애플리케이션의 Connection String에 전달하는 방식으로 접속 로직을 런타임으로 변경해야 합니다.

또한, 64비트 OS(Windows 11)에서 기존 32비트 CSDK 설정(.reg 백업본)을 임포트할 때는 반드시 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Informix 하위 경로에 적용되도록 관리자 권한으로 설정해 주셔야 합니다.

마치며

설치가 완료된 후에는 32비트 환경 통신 및 레지스트리 세팅을 위해 setnet32.exe를 실행하여 환경을 구성해 줍니다. 그리고 제어판의 기본 ODBC가 아닌 반드시 C:\Windows\SysWOW64\odbcad32.exe (32비트 ODBC 관리자)를 열어 시스템 DSN을 등록해 주어야 기존 32비트 애플리케이션에서 문제없이 데이터베이스에 연결할 수 있습니다.

마이그레이션 과정에서 저와 같은 삽질을 겪고 계신 개발자분들께 큰 도움이 되길 바랍니다. 💪

반응형
반응형

🚀 TistoAI 시스템 고도화

실시간 데이터 연동 엔진 업데이트

1차 개발후 사용해보니, 카테고리별 핫 토픽을 조회하니 뭔가 과거 데이터를 가져오는 것이었습니다.

역시나, AI로 개발을 해보면 내가 원하는 방향으로 기획으로 AI가 개발을 진행했는지 끊임없이 의심하고 검증 해볼 필요가 있습니다.

 

다음은 개발 분석을 통해서 검색 엔진을 고도화한 내용입니다.

 

이번 업데이트에서는 사용자가 프로그램을 실행하는 바로 그 순간(실시간 기준일)의 최신 핫토픽과 정책 뉴스를 100% 반영하도록 카테고리별 검색 알고리즘과 LLM 프롬프트 파이프라인을 전면 개편하였습니다.

1. 2024년 과거 데이터 생성 원인 분석 (Root Cause)

기존 시스템에서 과거 2024년 기준의 내용이 출력되었던 핵심 원인은 다음 3가지였습니다:

  1. 프롬프트 내 동적 날짜(Timestamp) 미주입:
    기존 프롬프트에는 단순히 '오늘 발표된 뉴스'라는 추상적인 단어만 주어졌습니다. LLM(Gemini) 모델 특성상 명확한 현재 연도(2026년)와 날짜 기준이 없으면 자체 사전 학습 데이터의 최신 커트라인 시점(2024년)을 기본 '오늘'로 판단하는 경향이 있었습니다.
  2. Search Grounding 할당량 초과 시 지식 커트라인 회귀:
    실시간 구글 웹 검색 API(google_search) 호출 중 분당/일일 쿼터 초과(429 Error) 시 내장 지식으로 자동 전환(Fallback)되면서 2024년 데이터가 그대로 노출되었습니다.
  3. 글 생성(generate_blog_post) 시 본문 세부 검증 부재:
    주제는 최신 키워드였더라도, 실제 본문 HTML을 생성하는 과정에서 실시간 웹 검색 및 날짜 가이드가 적용되지 않아 본문 세부 지원금 수치와 조건이 2024년 구 버전으로 작성되었습니다.

2. TistoAI 카테고리별 실시간 검색 기준 및 로직

TistoAI는 총 5가지 핵심 카테고리를 제공하며, 각 분야에 최적화된 실시간 검색 키워드 및 구글 뉴스 RSS 파이프라인을 통해 고단가·고유입 주제를 추출합니다.

카테고리 명칭실시간 검색 키워드 및 대상추천 콘텐츠 특징
🏛️ 오늘의 정책뉴스
(policy)
정부 정책, 민생 지원금, 절세, 부동산/금융 지원, 복지 혜택 당일 발표된 정부 대책, 지자체 지원금, 소상공인/청년 지원 혜택 실시간 요약
🏛️ 정부지원금
(welfare)
정부지원금, 청년복지, 환급금, 근로장려금, 청년도약계좌 건강보험료 환급금, 근로장려금 반기신청, 청년 주거 대출 등 유입 폭발 키워드
💰 금융/절세
(finance)
연말정산, 절세 꿀팁, 예적금 금리, 주식/재테크, ISA 계좌 시중은행 파킹통장 금리 비교, 연말정산 미리보기, 비과세 금융상품 가이드
💻 IT/개발 트렌드
(tech)
Gemini/ChatGPT/AI 기술, IT 툴, 프롬프트, 개발 트렌드 최신 LLM 에이전트 활용법, 파이썬 자동화, 개발 생산성 툴(Cursor, Claude Code) 비평
🌿 생활/노하우
(life)
생활 꿀팁, 누진세 전기요금, 추석/설 연휴 여행, 제휴마케팅 핫이슈 계절별 생활비 절감 팁, 황금연휴 여행 특가, 쿠팡 와우할인 등 실생활 밀착형 주제

3. 핵심 시스템 개선 사항 (Engine Upgrades)

① 실행 시점 동적 타임스탬프(datetime.now()) 100% 자동 연동

사용자가 조회를 실행하고 글 생성을 누르는 바로 그 순간의 컴퓨터 실시간 날짜를 읽어와 프롬프트 최상단에 자동 인젝션합니다:

today_str = datetime.now().strftime("%Y년 %m월 %d일")
current_year = datetime.now().year
# -> [작성 기준일]: 2026년 08월 19일 (현재 연도: 2026년) 자동 주입

[시점 최신성 엄수 규칙]을 명시하여 2024년 등 과거 연도의 지원금 액수나 정책 기준이 본문에 섞이는 현상을 완벽히 차단했습니다.

② 구글 뉴스 RSS 2차 방어막(Fallback) 구축

Gemini API의 실시간 Search Grounding 툴 할당량이 초과되더라도, Google News RSS 파서가 당일 실제 언론사 및 정부 브리핑 헤드라인을 실시간 수집하여 LLM에 전달합니다. 따라서 100% 팩트 기반의 최신 핫뉴스 주제를 반환합니다.

③ 본문 포스팅 생성 시 실시간 웹 검색 및 최신성 검증 보장

주제 선정뿐만 아니라 '글 생성' 단계에서도 Google Search Grounding을 동시에 실행하여, 지원금 신청 자격, 세부 금액, 공식 사이트 바로가기 링크까지 현재 시점 기준으로 정밀 작성됩니다.

💡 AI 개발자의 성찰: "끊임없는 교차 검증과 테스트의 중요성"

AI를 활용하여 서비스를 개발할 때 가장 크게 깨닫게 되는 점은 바로 "AI를 100% 맹목적으로 신뢰하기보다는, 의도한 대로 동작하고 있는지 개발자가 끊임없이 직접 테스트하고 검증해야 한다"는 사실입니다.

아무리 성능이 뛰어난 LLM 모델이라도 파라미터 지식 한계나 Fallback 동작 중 예기치 않은 데이터 회귀 현상이 발생할 수 있습니다. 이번 업데이트 역시 프롬프트 수정에 그치지 않고, 카테고리별 수집 데이터, 실제 출력 결과물, 에러 로그, 본문 생성 품질까지 하나하나 직접 디버깅하고 교차 검증(Cross-Verification)함으로써 비로소 100% 완벽한 시스템을 완성할 수 있었습니다.

개발자의 세심한 교차 검증과 AI의 강력한 자동화 기능이 결합될 때 최고의 고품질 솔루션이 탄생한다는 소중한 인사이트를 다시 한번 얻었습니다.

📌 마무리 및 요약

TistoAI는 이번 엔진 고도화와 철저한 검증 프로세스를 통해 "항상 사용자가 실행하는 오늘 날짜 기준"으로 가장 신선하고 검색 유입률이 높은 최신 포스팅을 생성할 수 있게 되었습니다.

 

반응형
반응형

 

개발자를 위한 3분 클라우드 상식:
도커, 쿠버네티스, OpenShift의 차이와 협업 가이드

클라우드 네이티브 환경(Cloud Native) 개발 필수 지식 및 인프라 소통 가이드 

 

최근 프로젝트를 진행하다 보면 엔터프라이즈 환경에서 도커(Docker), 쿠버네티스(Kubernetes), 오픈시프트(OpenShift)라는 용어가 항상 따라다닙니다. 비슷한 것 같으면서도 역할이 전혀 다른 이 세 가지 기술의 개념을 아주 쉽게 정리하고, 실제 구축 시 개발자가 고객사 인프라 팀에 반드시 사전 요청해야 하는 필수 항목을 정리해 보았습니다.

1. 세 가지 기술의 명확한 개념 비교

🐳 도커 (Docker)

"택배 상자 (컨테이너 포장)"

애플리케이션과 그 실행 환경(OS, 라이브러리)을 하나의 바구니에 담아서 "어디서든 똑같이" 실행하게 해주는 기술입니다. 내 PC에서 잘 돌던 프로그램이 서버에서는 안 도는 고질적인 문제를 해결한 1등 공신입니다.

🎡 쿠버네티스 (K8s)

"거대한 물류 센터 관리자"

도커가 택배 상자라면, 그 수천 개의 상자(컨테이너)를 한꺼번에 관리하는 자동화 지휘자입니다. 트래픽이 몰리면 상자 개수를 자동으로 늘려주고, 서버가 죽으면 다른 서버에서 상자를 다시 켜주는 등 스케일링과 안정성을 담당합니다.

🔴 오픈시프트 (OpenShift)

"엔터프라이즈 맞춤형 프리미엄 물류 센터"

Red Hat(레드햇) 회사에서 쿠버네티스를 가져다가, 기업들이 쓰기 편하게 보안(Security), 편리한 대시보드 주소, 자동 빌드/배포 기능(CI/CD)을 한 스쿱 크게 얹어서 묶어 파는 프리미엄 상용 솔루션입니다.

즉, [도커]로 이미지를 만들면, 그 이미지가 [오픈시프트(엔터프라이즈 쿠버네티스)] 라는 거대한 플랫폼 위에서 안정적으로 돌아가게 되는 구조입니다.

📝 필수 체크리스트: 인프라팀에 요청할 사항

개발자가 OpenShift 환경에서 CI/CD(빌드 밑 배포) 환경을 구성하려면, 개발서버/운영서버 구축 전에 반드시 인프라/클라우드 관리팀에 아래 정보들을 메일로 요청해서 받아둬야 합니다.

1. 베이스 이미지 통제 여부
오픈시프트는 보안 검증이 까다롭습니다. 개발자가 마음대로 퍼블릭 도커 허브(Docker Hub) 이미지를 써도 되는지, 아니면 인프라팀 내부 레지스트리에 올려둔 공식 Nginx/Tomcat 베이스 이미지 주소(ex: UBI 이미지)가 있는지 확인해야 합니다.
2. 이미지 저장소(Registry) 주소 및 권한
개발팀이 빌드한 도커 이미지를 밀어 넣을 프라이빗 저장소 도메인 주소(예: quay.apps.회사도메인.com)와 로그인을 위한 계정(Token, ID/PW)을 요청해야 합니다.
3. 외부 접속 라우트(Route/Domain) URL
내부에서 돌아가는 컨테이너를 외부 사용자가 접속할 수 있도록 열어주는 실제 인터넷 주소(URL)를 예약/발급 받아야 합니다. SSL(HTTPS) 인증서 적용 여부도 확인해야 합니다.
4. 영구 스토리지 (PVC) 볼륨 명칭
파일 업로드나 로그 저상, 파워클라이언트 배포 파일 거치가 필요한 경우 컨테이너가 죽어도 날아가지 않는 저장공간을 요청해야 합니다. "ReadWriteMany 방식의 10GB 짜리 PVC 생성해주세요!" 라고 요청하고, 그렇게 생성된 PVC 이름을 넘겨받습니다.
5. 구동 강제 보안 정책 (SCC/UID)
오픈시프트에서는 해킹 방지를 위해 컨테이너 내부에서 root 계정 실행을 기본적으로 막아둡니다. Dockerfile에 특정 User 권한(ex: 1001100000)을 부여해야 하는지, 고객사만의 구동 권한 룰(가이드)이 존재하는지 확인합니다.

💡 작은 결론

고객사마다 서버 관리 정책 및 구조가 다를것입니다. 처음 이 환경을 접하면서 고객사에 가기전에 노트북에 가상서버를 설치하고 리눅스와 쿠버네티스 환경만을 구축해서 배포 테스트를 진행해 보았습니다. 도커 이미지를 만들고 쿠버네티스에서 실행할 yaml 만을 적용하여 배포 테스트를 해보았습니다.

 

사실 저는 웹 개발자가 아니라서 이 개발환경이 처음이고 낯설기는 하였으나, 새로운걸 배운다는것은 귀찮을때도 있지만 재밌고 설레기도 합니다. 항상 느끼는거지만 배움에는 끝이 없음을 다시 한번 깨닫게 됩니다.

 

고객사에서 OpenShift를 처음 접하였습니다. 많은 경험을 해보지는 않았지만 UI를 통해서 직관적으로 서버 배포 환경을 관리 할 수 있음이 상당히 매력적입니다.

 

#Docker #Kubernetes #OpenShift #K8s #클라우드네이티브 #개발자소통가이드 #PVC #클라우드인프라
반응형
반응형

 

기존 레거시 윈도우 환경에서 동작하던 다수의 파워빌더(PowerBuilder) 시스템을 최신 컨테이너 기반인 OpenShift (Kubernetes) 환경으로 이관하는 작업을 진행하게 되었습니다. 배포된 모델은 웹을 통해 클라이언트 모듈을 내려받는 파워클라이언트(PowerClient) 구조입니다.

이 포스팅에서는 6개의 업무 시스템(인사, 회계 등)을 어떻게 단일 OpenShift 환경으로 효율적으로 배포하고, 도커(Docker) 이미지 관리를 극대화했는지에 대한 실무 구축기를 공유합니다.

1. 아키텍처 결정: 분리 배포 vs 통합 배포

6개의 업무 시스템 폴더가 나누어져 있었기 때문에 초기에는 6개의 Dockerfile과 6개의 Pod를 띄우는 완전한 마이크로서비스 구성을 고려했습니다. 하지만 인프라 환경에서 단일 도메인(예: https://pb.apps.example.com/)만을 발급받아 라우트(Route)를 통일하는 구조로 결정되었습니다.

📌 도출된 솔루션

도커 이미지와 OpenShift YAML 설정은 딱 1개(1세트)만 구성합니다. 하나의 웹 파드 내부에 영구 스토리지(PVC)를 연결하고(Mount), 그 공간에 6개의 업무 시스템 파일들을 폴더 단위로 분리하여 복사해 웹 서비스하는 통합 컨테이너 환경을 구축했습니다.

2. 껍데기만 남긴 Dockerfile 전략

파워클라이언트 앱은 Java 로직 구동 환경(WAS)이 아닌 HTML, ZIP, PBD를 뿌려주는 정적 웹 리소스에 가깝습니다. 고객사의 표준 배포 이미지가 Tomcat 기반이었지만, 우리는 컨테이너 이미지 자체에 파워클라이언트 배포 파일들을 구워 넣지 않았습니다.

대신 도커 이미지는 껍데기(웹 서버 엔진) 역할만 수행하며, 실제 리소스 파일은 PVC 스토리지를 통해 런타임에 덮어 씌우는 방식을 선택했습니다. 이렇게 함으로써 소스(UI) 수정 시 매번 길고 무거운 Docker 이미지를 재빌드하지 않아도 됩니다.

FROM registry.example.com/base-images/openjdk:v1.0

USER root

# 스토리지(PVC)가 연결될 기본 디렉토리 공간 권한 세팅
WORKDIR /APP/powerbuilder/deploy

RUN chown -R 1001100000:1001100000 /APP/powerbuilder/deploy && \
    chmod -R 750 /APP/powerbuilder/deploy

EXPOSE 8500

USER 1001100000

# 앱 구동 스크립트 실행
CMD ["/APP/powerbuilder/deploy/start_server.sh", "run"]

3. 인프라와 쿠버네티스의 연결 고리: YAML 설정 노하우

단일 이미지를 기반으로 작성한 Deployment.yaml에서는 두 가지 요소가 배포의 핵심이었습니다.

① 필수 볼륨 마운트 (VolumeMounts)
`containers` 영역 내부에 물리 스토리지(PVC)를 특정 동작 런타임 폴더(/APP/powerbuilder/deploy)에 마운트하여, 컨테이너가 켜짐과 동시에 FTP를 통해 업로드해 둔 파워클라이언트 6개 파일 폴더(insa, acc 등)를 인식할 수 있게 만들었습니다.

② subPath를 통한 깔끔한 로그 관리

volumeMounts:
  - name: log-volume
    mountPath: /app/logs
    subPath: powerclient-web/logs

컨테이너 내부는 /app/logs를 쓰면, OpenShift가 자동으로 물리 스토리지 쪽에 powerclient-web/logs 라는 폴더 트리를 생성해주고 거기로 다이렉트를 시키는 subPath 방식을 적용했습니다. (개발자가 굳이 FTP로 접속해서 빈 폴더를 만들어주지 않아도 시스템이 알아서 폴더를 개척해 줍니다!)

4. 요약 및 결론

결과적으로 Git 레포지토리에는 가벼운 형상 관리 셋업용 스크립트 세트(Dockerfile, build.sh, push.sh, config) 단 1개만 올려두고 관리가 가능해졌습니다. OpenShift 인프라 담당자가 PVC 스토리지만 부여해 주면, 쿠버네티스의 자동화 능력을 바탕으로 유연하고 빠른 프론트(Client) 배포 환경이 완성되었습니다.

5. 샘플 코드

1. config (환경 변수 공통 파일)

 역할 : 빌드와 이미지 푸시 스크립트에서 공통으로 사용할 정보를 한곳에서 관리. 나중에 이미지 버전 (v1.0 -> v1.1) 변경될때 이 파일 수정하면 됩니다.

 

#!/bin/bash
# ========================================================
# 빌드 및 푸시에 사용될 환경 변수 공통 설정
# ========================================================
REGISTRY="quay.apps.cl-hub-test.ocp.kftc.net/my-project"
IMAGE_NAME="powerclient-all-in-one"
TAG="v1.0"

# 최종 이미지 주소 조합
FULL_IMAGE_PATH="${REGISTRY}/${IMAGE_NAME}:${TAG}"

 

2. build.sh (컨테이너 이미지 빌드 스크립트)

 

역할 : 작성한 6개 시스템의 소스 파일과 도커파일을 이용해 톰캣이 깔려 있는 하나의 이미지로 굽습니다.

#!/bin/bash
# ========================================================
# Docker / Podman 빌드 스크립트
# ========================================================
source ./config

echo "==========================================="
echo "🚀 6개 시스템 통합 컨테이너 빌드를 시작합니다..."
echo "📦 대상 이미지: $FULL_IMAGE_PATH"
echo "==========================================="

docker build -t $FULL_IMAGE_PATH .

echo ""
echo "✅ 빌드가 완료되었습니다!"

 

3. push.sh (컨테이너 레지스트리 업로드 스크립트)

 

역할 : 빌드가 끝난 이미지를 고객사 쿠버네티스(오픈시프트) 환경의 레지스트리로 전송(업로드) 합니다.

#!/bin/bash
# ========================================================
# 컨테이너 레지스트리 푸시 스크립트
# ========================================================
source ./config

echo "==========================================="
echo "☁️ 이미지를 원격 레지스트리로 푸시합니다."
echo "🏷️ 업로드 이미지: $FULL_IMAGE_PATH"
echo "==========================================="

# docker login 명령어로 레지스트리 로그인이 먼저 되어있어야 합니다.
docker push $FULL_IMAGE_PATH

echo ""
echo "✅ 레지스트리 푸시가 완료되었습니다!"

 

4. server.xml (톰캣 환경설정 파일)

 

역할 : 1개의 톰캣 엔진 내부에 6개의 시스템(A~F)을 각각 다른 폴더 경로(Context)로 쪼개어 연결해 줍니다.

이렇게 하면 http://URL/system_a 와 같은 형식으로 6개의 웹에 각각 접속 할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
  
    <!-- 고객사에서 지정(가이드)해 준 서비스 포트 (예: 8080 또는 8500) -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />
               
    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false">
        
        <!-- [핵심] 6개의 시스템을 단일 톰캣 엔진 내 6개의 별도 앱(Context)으로 분리 -->
        <Context path="/system_a" docBase="system_a" reloadable="false" />
        <Context path="/system_b" docBase="system_b" reloadable="false" />
        <Context path="/system_c" docBase="system_c" reloadable="false" />
        <Context path="/system_d" docBase="system_d" reloadable="false" />
        <Context path="/system_e" docBase="system_e" reloadable="false" />
        <Context path="/system_f" docBase="system_f" reloadable="false" />

      </Host>
    </Engine>
  </Service>
</Server>

 

5. Dockerfile( 배포 이미지 설계도)

 

역할 : 톰캣 베이스 이미지 위로 server.xml 환경 설정과, 서버 루트 디렉토리 안에 system_a ~ system_f 소스 폴더(또는 war)를 한번에 copy 해 줍니다.

# 1. 톰캣 기본 베이스 이미지 사용 (고객사 환경에 맞춰 Java 버전 수정 가능)
FROM tomcat:9.0-jdk17-openjdk-slim

# 작업 디렉토리 고정
WORKDIR /usr/local/tomcat

# 2. 통합용 Custom server.xml 덮어쓰기 (6개 Context 맵핑)
COPY server.xml /usr/local/tomcat/conf/server.xml

# 3. 6개의 시스템 소스 코드를 차례대로 복사
COPY ./src/system_a /usr/local/tomcat/webapps/system_a
COPY ./src/system_b /usr/local/tomcat/webapps/system_b
COPY ./src/system_c /usr/local/tomcat/webapps/system_c
COPY ./src/system_d /usr/local/tomcat/webapps/system_d
COPY ./src/system_e /usr/local/tomcat/webapps/system_e
COPY ./src/system_f /usr/local/tomcat/webapps/system_f

# 권한 설정 (컨테이너 내 권한 문제가 없도록)
RUN chmod -R 755 /usr/local/tomcat/webapps

# 방화벽 포트 명시
EXPOSE 8080

# 톰캣 서버 포어그라운드(Background) 실행 방지 -> OpenShift Pod가 종료되지 않게 유지
CMD ["catalina.sh", "run"]

 

6. deploy.yml (쿠버네티스/오픈시프트 명세서)

 

역할: 만들어진 1개의 큰 도커 이미지를 쿠버네티스에서 어떻게 띄우고(Deployment), 어떤 네트워크로 연결하며(service), 어떤 외부 주소로 빼줄지(Route)지시 합니다. 단 하나의  Route 도메인만 존재하면 됩니다.

 

---
# 1. Deployment: 6개 시스템이 들어있는 컨테이너 구동 세팅
apiVersion: apps/v1
kind: Deployment
metadata:
  name: powerclient-allinone-deployment
  labels:
    app: allinone-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: allinone-app
  template:
    metadata:
      labels:
        app: allinone-app
    spec:
      containers:
      - name: tomcat-container
        # config에 명시한 주소 그대로 불러오기
        image: quay.apps.cl-hub-test.ocp.kftc.net/my-project/powerclient-all-in-one:v1.0
        ports:
        - containerPort: 8080   # server.xml 톰캣 포트

---
# 2. Service: 컨테이너 내부 네트워크 맵핑 (LoadBalancer 역할)
apiVersion: v1
kind: Service
metadata:
  name: powerclient-allinone-service
spec:
  selector:
    app: allinone-app
  ports:
    - protocol: TCP
      port: 8080        
      targetPort: 8080  # 톰캣 컨테이너가 열어둔 포트
  type: ClusterIP

---
# 3. Route: 브라우저 접속을 위한 단일 통합 도메인 URL 설정 (OpenShift 전용)
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: powerclient-allinone-route
spec:
  # 고객사가 가이드해준 대시보드(웹) 단일 도메인 URL 입력
  host: pb-all.apps.cl-intsvc-test.ocp.kftc.net
  to:
    kind: Service
    name: powerclient-allinone-service
  port:
    targetPort: 8080

 

반응형
반응형

 

Windows 11 환경에서 레거시 ODBC(SQL Anywhere 6.0) DSN 저장 불가 현상 해결기

오래된 레거시 시스템을 유지보수하면서 최신 OS와 호환성을 맞추는 일이 생각보다 고됩니다. 이번 포스팅에서는 Windows 11 (특히 Enterprise LTSC 버전) 환경에서 SQL Anywhere 6.0 (Adaptive Server Anywhere) ODBC 설정이 무시되고 저장이 안 되는 기이한 현상을 어떻게 해결했는지, 그 여정과 원인을 정리해 보았습니다.


🚨 1. 문제 발생: "저장 버튼을 눌렀는데 값은 어디로 갔을까?"

최근 고객사 PC(Windows 11 Enterprise LTSC)에 레거시 32비트 DB인 SQL Anywhere 6.0을 셋팅하고 접속해야 할 일이 생겼습니다. 평소처럼 자동화된 배치(.bat) 파일을 이용해 ODBC 드라이버와 DSN 설정을 진행했습니다.

드라이버 셋팅은 되었으나, db 연동이 안됩니다.

확인을 위해  "ODBC 데이터 원본 관리자(32비트)" 창을 열어 등록된 DSN의 구성(C) 버튼을 누르고 수정을 시도할 때 발생했습니다.

  • 비밀번호나 설정값을 바꾸고 [확인]을 눌렀는데 에러 하나 없이 창이 닫힙니다.
  • 다시 구성 창을 열어보면? 방금 수정한 값이 흔적도 없이 사라져 있고 옛날 값 그대로입니다.

🕵️ 2. 문제 원인 찾기 (Troubleshooting)

가설 A: 언어팩 DLL 충돌 문제인가?

처음엔 가장 흔한 옛날 드라이버 파일 누락을 의심했습니다. SQL Anywhere는 OS 언어(한국어)를 감지하여 한국어 언어팩 파일(dblgko6.dll)을 찾지만, 기존 파일 디렉터리에는 영문 파일(dblgen6.dll)만 있는 것을 발견했습니다.

하지만 설정 UI 창 자체가 튕기지 않고 정상적으로 팝업되는 것을 보아, 드라이버가 영문팩을 물고 UI를 띄우는 데는 성공한 상태였습니다. 즉, DLL 언어 충돌이 근본 원인은 아니었습니다.

가설 B: 윈도우 보안(UAC)과 레지스트리 권한 문제 💡 (빙고!)

디버깅 끝에 진짜 원인을 찾았습니다. 기존 ODBC 등록 배치 파일은 DSN을 '시스템 DSN'으로 등록하고 있었습니다.

  • 시스템 DSN의 저장소: 윈도우 레지스트리의 HKEY_LOCAL_MACHINE (전체 시스템 영역)
  • Windows 최신 보안 정책: HKLM 영역은 반드시 관리자 권한으로 실행된 프로세스만 수정(쓰기)할 수 있습니다.

요즘 프로그램이라면 설정 저장 시 "관리자 권한이 필요합니다"라는 UAC(사용자 계정 컨트롤) 경고창을 띄웠을 것입니다. 하지만 20년 전 UAC 개념이 없던 시절에 만들어진 구형 드라이버는 저장을 시도했다가 윈도우 보안정책에 막혀 저장이 실패(Access Denied)해도, 유저에게 에러 창을 띄우지 않고 그냥 넘어가는 침묵의 실패(Silent Failure)를 발생시키고 있었던 것입니다.


🖥️ 3. Windows 10과 Windows 11의 차이점

"어? 예전 Windows 10이나 다른 PC에서는 이런 문제가 없었는데요?"

과거 윈도우 버전들(특히 일반 Pro 이하 버전이나 정책이 느슨한 상태)과 최신 Windows 11 Enterprise LTSC 사이에는 보안 잣대의 엄격함에 큰 차이가 있습니다.

  • Registry Virtualization (레지스트리 가상화): 과거 Windows OS는 오래된 32비트 프로그램이 관리자 권한 없이 HKLM에 쓰기를 시도하면, 에러를 내뿜게 놔두지 않고 사용자 몰래 VirtualStore라는 가상 영역(AppData 내 파일 폴더 형태 등)에 값을 대신 저장해 주었습니다. 프로그램은 정상적으로 저장했다고 착각하게 되죠.
  • 강화된 UAC 프로세스 (Windows 11 LTSC): 최신 LTSC 버전과 기업용 보안 셋팅에서는 위와 같은 우회(호환성 트릭)를 보안 위협으로 간주해 강력하게 차단합니다. "권한 없으면 못 써!" 하고 칼같이 끊어버리기 때문에, 레거시 프로그램의 조용한 쓰기 실패 현상이 이번에 수면 위로 명확히 드러난 것입니다.

🛠️ 4. 완벽한 해결책: '사용자 DSN'으로 갈아타기

이 문제를 해결하는 방법은 두 가지입니다.

  1. 매번 ODBC 관리자를 검색 후 '관리자 권한으로 실행'해서 수정하기 (번거로움)
  2. 권한이 필요 없는 개인 영역인 '사용자 DSN'(HKEY_CURRENT_USER) 활용하기 (추천!)

우리는 두 번째 방법인 사용자 DSN(User DSN)을 적극 활용하여 배치 스크립트를 재작성했습니다. 드라이버 시스템 등록은 최초 1회만 관리자 권한으로 밀어 넣고, 자주 수정되는 DSN 정보는 HKCU에 저장하여 권한 스트레스 없이 마음껏 변경할 수 있도록 구조를 변경했습니다.

최종 해결 스크립트 공유 (system_setup_all.bat)

@echo off
:: [1] 관리자 권한 확인 (ODBC 드라이버 HKLM 등록 필수)
openfiles >nul 2>&1
if %errorlevel% neq 0 (
    echo [오류] 드라이버 등록을 위해 관리자 권한이 필요합니다.
    pause
    exit /b 1
)

:: [2] 환경 변수 설정
set "TARGET_DIR=%~dp0"
set "DSN_NAME=gongje"
set "ENGINE_NAME=gongje"
set "DRIVER_NAME=Adaptive Server Anywhere 6.0 Compact"

:: [3] 드라이버 공통 등록 (HKLM - 반드시 관리자 필요)
set "INST_REG=HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\%DRIVER_NAME%"
reg add "%INST_REG%" /v "Driver" /t REG_SZ /d "%TARGET_DIR%dbodbc6.dll" /f >nul
reg add "%INST_REG%" /v "Setup" /t REG_SZ /d "%TARGET_DIR%dbodbc6.dll" /f >nul
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\ODBC Drivers" /v "%DRIVER_NAME%" /t REG_SZ /d "Installed" /f >nul

:: [4] 사용자 DSN 등록 (HKCU - 관리자 불필요, 자유롭게 수정 가능!)
set "USER_DSN_REG=HKEY_CURRENT_USER\SOFTWARE\ODBC\ODBC.INI\%DSN_NAME%"
reg delete "%USER_DSN_REG%" /f >nul 2>&1
reg add "%USER_DSN_REG%" /v "Driver" /t REG_SZ /d "%TARGET_DIR%dbodbc6.dll" /f >nul
reg add "%USER_DSN_REG%" /v "DatabaseName" /t REG_SZ /d "%ENGINE_NAME%" /f >nul
reg add "HKEY_CURRENT_USER\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources" /v "%DSN_NAME%" /t REG_SZ /d "%DRIVER_NAME%" /f >nul

echo 드라이버는 시스템에, DSN은 사용자 영역에 안전하게 등록 완료!
pause

📝 마무리하며

최신 Windows 환경에서 옛날(Legacy) 프로그램이 알 수 없는 동작을 할 때는 단순한 호환성 오류를 넘어서 '운영체제의 보안 정책(UAC, 권한 통제)'이 레거시 프로그램의 옛날식 API 호출을 어떻게 처리하는지 차이를 보는 것이 중요합니다.

 

System DSN에서 User DSN으로의 셋팅 전환은 이러한 윈도우 보안 갈등을 우회 할 수 있음을 알게되었습니다.

 

짧은 프로젝트 기간안에 오래된 DB 연동 하는 것중에 ASA 6.0 작업을 공유 해봅니다.

반응형

+ Recent posts