신입사원 SQL 실습, 이제 어려운 SQL 말고 ‘자연어’로 합니다

소개

저는 매년 1월부터 3월까지 공채 신입사원을 대상으로 Linux, Shell Script, Database, WAS, Network, C/C++ 등 인프라 및 프로그래밍 언어 전반에 대한 교육을 진행하고 있습니다.
그중 Database 교육을 진행하며, 다양한 이기종 데이터베이스 환경에 접속해 SQL 실습을 보다 효율적으로 수행할 수 있는 전용 애플리케이션의 필요성을 느꼈습니다. 특히 신입사원들이 가장 어려움을 겪는 부분은 2중·3중 조인과 같은 복잡한 SQL 작성이었으며, 이를 생성형 AI 기반의 자연어 입력을 통해 자동으로 SQL을 생성하여 학습을 지원하는 애플리케이션을 개발하고자 하였습니다.

진행 방법

  1. "이기종 DBMS SQL 편집기" 기획 및 Lovable 프롬프트 생성(Claude)

  2. WSL2 환경 구축 및 Ubuntu Linux 설치

  3. docker 환경 구성 및 oracle 설치

  4. Lovable 앱 개발

  5. Cursor ai 앱 실행

1. "Linux 학습 환경 애플리케이션" 기획 및 Lovable 프롬프트 생성(Claude)

당신은 이기종 DBMS 전문가이며 PRD 작성 전문가입니다. 첨부된 문서는 신입사원 교육 시 진행하는 Oracle 설치 및 SQL 실행 프로세스를 정리한 문서입니다. 
첨부문서와 아래 요구사항을 확인하고 PRD 작성해 주세요.
---
* 이기종 DBMS 지원
* 동일한 테스트 테이블 생성(EMP, DEPT 테이블)
* 동일한 유저 생성(scott)
* DB관리자 패스워드는 dbms1234##으로 통일
Linux는 아래 Ubuntu 환경으로 해줘.
---
junsan12@DESKTOP-VQGF6FR:~$ uname -a
Linux DESKTOP-VQGF6FR 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun  5 18:30:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
junsan12@DESKTOP-VQGF6FR:~$
---
docker-composer는 사용하지 말고 단일 docker로만 진행을 할거야.
다시 PRD 수정해줘.
당신은 Lovable 프롬프트 전문가입니다. Lovable 프롬프트 작성해 주세요.

출력

Lovable 프롬프트: 다중 DBMS SQL 편집기

📋 프로젝트 개요
여러 데이터베이스 시스템(Oracle, MySQL, PostgreSQL, MariaDB, SQL Server)에 연결하여 SQL 쿼리를 작성, 실행, 관리할 수 있는 전문적인 웹 기반 SQL 편집기를 만들어주세요.

🎯 핵심 기능
1. 데이터베이스 연결 관리자

DBMS 선택기: 5개의 다른 DBMS를 전환할 수 있는 드롭다운 메뉴

Oracle 11g XE (localhost:1521)
MySQL 8.0 (localhost:3306)
PostgreSQL 15 (localhost:5432)
MariaDB 10.11 (localhost:3307)
SQL Server 2022 (localhost:1433)


연결 상태 표시기:

실시간 연결 상태를 색상 인디케이터로 표시
표시 예: "● 연결됨 (scott@oracle11g:1521)" 또는 "○ 연결 안됨"
연결됨은 초록색 점, 연결 안됨은 회색 점


사전 구성된 인증 정보:

사용자: scott
비밀번호: tiger
데이터베이스: Oracle은 XE, 나머지는 testdb



2. SQL 편집기 컴포넌트

Monaco Editor 통합 (선호) 또는 CodeMirror를 대안으로 사용
SQL 문법 하이라이팅: 키워드(SELECT, FROM, WHERE), 함수, 문자열, 주석
줄 번호: 왼쪽에 줄 번호 표시
자동 들여쓰기: SQL 문에 대한 스마트 들여쓰기
괄호 매칭: 일치하는 괄호와 대괄호 강조 표시
여러 줄 지원: 여러 SQL 문 처리 가능

편집기 플레이스홀더 텍스트:
-- 여기에 SQL 쿼리를 작성하세요
-- 팁: Ctrl + Enter를 눌러 실행하세요
-- 예제: SELECT * FROM emp WHERE deptno = 10;
키보드 단축키:

Ctrl + Enter: SQL 실행
Ctrl + /: 주석 토글
Ctrl + F: 찾기
Ctrl + Shift + F: SQL 포맷팅
Ctrl + Shift + K: 편집기 지우기

3. 액션 버튼
편집기 아래에 다음 버튼들이 있는 툴바를 만들어주세요:
버튼아이콘기능스타일SQL 포맷팅🎨SQL 코드를 자동으로 정렬하고 예쁘게 만들기보조 버튼지우기🗑️편집기의 모든 내용 지우기보조 버튼실행▶️SQL 쿼리 실행주요 버튼 (파란색)CSV 내보내기📥결과를 CSV로 다운로드보조 버튼히스토리🕐쿼리 히스토리 보기보조 버튼
버튼 상태:

편집기가 비어있거나 연결되지 않았을 때 "실행" 비활성화
SELECT 결과가 없을 때 "CSV 내보내기" 비활성화
쿼리 실행 중에는 "실행" 버튼에 로딩 스피너 표시

4. 결과 패널
빈 상태 (첫 실행 전):
아직 결과가 없습니다.
SQL 쿼리를 실행하여 여기에서 결과를 확인하세요.
SELECT 쿼리 결과:

인터랙티브 데이터 테이블로 표시
정렬 가능한 컬럼 헤더
실행 시간 표시: "실행 시간: 0.045초"
행 개수: "행: 14개"
대용량 결과에 대한 페이지네이션 (페이지당 100행)
가로 및 세로 스크롤
가독성을 위한 교대 행 색상

DML 쿼리 결과 (INSERT/UPDATE/DELETE):
✓ 쿼리가 성공적으로 실행되었습니다
영향받은 행: 5개
실행 시간: 0.032초
에러 메시지:
❌ 쿼리 실행 중 오류:
ORA-00942: 테이블 또는 뷰가 존재하지 않습니다

라인 1, 위치 15
SELECT * FROM employee;
              ^
5. 추가 기능

CSV 내보내기: 쿼리 결과를 CSV 파일로 다운로드
결과 복사: 결과를 클립보드에 복사
쿼리 히스토리: 타임스탬프와 함께 마지막 10개의 실행된 쿼리 저장
연결 테스트: DBMS가 선택되면 자동으로 연결 테스트
반응형 디자인: 모바일 친화적 레이아웃


🎨 UI/UX 디자인 요구사항
레이아웃 구조
┌─────────────────────────────────────────────────────┐
│  [🗄️ 로고] 다중 DBMS SQL 편집기     [👤 사용자 정보] │
├─────────────────────────────────────────────────────┤
│  데이터베이스: [Oracle ▼] [MySQL ▼] [PostgreSQL ▼]  │
│  상태: ● 연결됨 (scott@oracle11g:1521)              │
├─────────────────────────────────────────────────────┤
│                                                     │
│  [ SQL 편집기 - 전체 너비, 높이: 300px ]            │
│  - SQL 문법 하이라이팅이 있는 Monaco 편집기         │
│  - 줄 번호, 자동완성                                │
│                                                     │
├─────────────────────────────────────────────────────┤
│  [SQL 포맷팅] [지우기] [실행] [내보내기] [히스토리]  │
├─────────────────────────────────────────────────────┤
│  결과 패널                                          │
│  ┌───────────────────────────────────────────────┐ │
│  │ 실행 시간: 0.045초  |  행: 14개              │ │
│  ├───────┬────────┬──────────┬─────┬──────────┤ │
│  │ EMPNO │ ENAME  │ JOB      │ SAL │ DEPTNO   │ │
│  ├───────┼────────┼──────────┼─────┼──────────┤ │
│  │ 7369  │ SMITH  │ CLERK    │ 800 │ 20       │ │
│  │ 7499  │ ALLEN  │ SALESMAN │1600 │ 30       │ │
│  └───────┴────────┴──────────┴─────┴──────────┘ │
│  [결과 복사] [CSV 내보내기]                         │
└─────────────────────────────────────────────────────┘
색상 구성

주요 색상: 파란색 (#2563eb) - 실행 버튼용
보조 색상: 회색 (#6b7280) - 다른 버튼용
성공: 초록색 (#10b981) - 성공적인 쿼리용
오류: 빨간색 (#ef4444) - 오류 메시지용
배경: 연한 회색 (#f9fafb) - 결과 패널용
편집기 배경: 어두운 색 (#1e1e1e) 또는 밝은 색 (#ffffff) 토글 가능

타이포그래피

글꼴 패밀리: 'Inter', 'Segoe UI', sans-serif (UI용)
편집기 글꼴: 'Fira Code', 'Consolas', monospace
글꼴 크기:

헤더: 24px
본문: 14px
편집기: 14px
버튼: 14px




🔧 기술 구현
프론트엔드 스택

프레임워크: React 18+ with TypeScript
코드 편집기: Monaco Editor (@monaco-editor/react 사용)
UI 컴포넌트: shadcn/ui 또는 Ant Design
상태 관리: React Context API 또는 Zustand
HTTP 클라이언트: Axios (API 호출용)
스타일링: Tailwind CSS

백엔드 API 엔드포인트 (현재는 Mock)
POST /api/sql/execute
json요청:
{
  "dbms": "oracle",
  "sql": "SELECT * FROM emp WHERE deptno = 10",
  "connectionId": "conn_12345"
}

응답 (성공):
{
  "success": true,
  "data": {
    "columns": ["EMPNO", "ENAME", "JOB", "SAL", "DEPTNO"],
    "rows": [
      [7782, "CLARK", "MANAGER", 2450, 10],
      [7839, "KING", "PRESIDENT", 5000, 10]
    ],
    "rowCount": 2,
    "executionTime": 0.045
  }
}

응답 (오류):
{
  "success": false,
  "error": {
    "code": "ORA-00942",
    "message": "테이블 또는 뷰가 존재하지 않습니다",
    "line": 1,
    "position": 15
  }
}
POST /api/connection/test
json요청:
{
  "dbms": "mysql",
  "host": "localhost",
  "port": 3306,
  "database": "testdb",
  "username": "scott",
  "password": "tiger"
}

응답:
{
  "success": true,
  "message": "성공적으로 연결되었습니다",
  "serverVersion": "MySQL 8.0.35"
}
샘플 Mock 데이터 (초기 개발용)
javascriptconst mockEmployees = [
  { empno: 7369, ename: 'SMITH', job: 'CLERK', sal: 800, deptno: 20 },
  { empno: 7499, ename: 'ALLEN', job: 'SALESMAN', sal: 1600, deptno: 30 },
  { empno: 7521, ename: 'WARD', job: 'SALESMAN', sal: 1250, deptno: 30 },
  { empno: 7566, ename: 'JONES', job: 'MANAGER', sal: 2975, deptno: 20 },
  { empno: 7654, ename: 'MARTIN', job: 'SALESMAN', sal: 1250, deptno: 30 },
  { empno: 7698, ename: 'BLAKE', job: 'MANAGER', sal: 2850, deptno: 30 },
  { empno: 7782, ename: 'CLARK', job: 'MANAGER', sal: 2450, deptno: 10 },
  { empno: 7788, ename: 'SCOTT', job: 'ANALYST', sal: 3000, deptno: 20 },
  { empno: 7839, ename: 'KING', job: 'PRESIDENT', sal: 5000, deptno: 10 },
  { empno: 7844, ename: 'TURNER', job: 'SALESMAN', sal: 1500, deptno: 30 },
  { empno: 7876, ename: 'ADAMS', job: 'CLERK', sal: 1100, deptno: 20 },
  { empno: 7900, ename: 'JAMES', job: 'CLERK', sal: 950, deptno: 30 },
  { empno: 7902, ename: 'FORD', job: 'ANALYST', sal: 3000, deptno: 20 }
];

const mockDepartments = [
  { deptno: 10, dname: 'ACCOUNTING', loc: 'NEW YORK' },
  { deptno: 20, dname: 'RESEARCH', loc: 'DALLAS' },
  { deptno: 30, dname: 'SALES', loc: 'CHICAGO' },
  { deptno: 40, dname: 'OPERATIONS', loc: 'BOSTON' }
];

📝 컴포넌트 구조
src/
├── components/
│   ├── Header.tsx                 # 로고, 타이틀, 사용자 정보
│   ├── DatabaseSelector.tsx       # DBMS 드롭다운 선택기
│   ├── ConnectionStatus.tsx       # 연결 인디케이터
│   ├── SqlEditor.tsx              # Monaco 편집기 래퍼
│   ├── ActionButtons.tsx          # 포맷, 지우기, 실행 버튼
│   ├── ResultsPanel.tsx           # 쿼리 결과 표시
│   ├── DataTable.tsx              # SELECT 결과용 테이블 컴포넌트
│   ├── ErrorMessage.tsx           # 오류 표시 컴포넌트
│   ├── QueryHistory.tsx           # 히스토리 사이드바/모달
│   └── ExportDialog.tsx           # CSV 내보내기 모달
├── hooks/
│   ├── useConnection.ts           # 데이터베이스 연결 로직
│   ├── useQueryExecution.ts       # SQL 실행 로직
│   └── useQueryHistory.ts         # 히스토리 관리
├── services/
│   ├── api.ts                     # API 클라이언트 (Axios)
│   └── sqlFormatter.ts            # SQL 포맷팅 유틸리티
├── types/
│   ├── database.ts                # 데이터베이스 타입
│   └── query.ts                   # 쿼리 결과 타입
└── App.tsx                        # 메인 애플리케이션

🚀 구현 단계
1단계: 기본 레이아웃

헤더, 편집기, 결과 섹션이 있는 메인 레이아웃 생성
5개 옵션이 있는 DBMS 선택기 드롭다운 추가
연결 상태 인디케이터 구현
Tailwind CSS로 스타일링

2단계: SQL 편집기

Monaco Editor 통합
SQL 문법 하이라이팅 추가
키보드 단축키 구현 (Ctrl+Enter 등)
플레이스홀더 텍스트 추가

3단계: 쿼리 실행

Mock API 엔드포인트 생성
로딩 상태가 있는 실행 버튼 구현
SQL 파싱 후 Mock 결과 반환
결과를 테이블 형식으로 표시

4단계: 추가 기능

SQL 포맷팅 버튼 추가 (sql-formatter 라이브러리 사용)
지우기 버튼 구현
CSV 내보내기 기능 추가
쿼리 히스토리 패널 생성

5단계: 오류 처리

줄/위치가 포함된 SQL 오류 표시
연결 오류 표시
빈 쿼리에 대한 유효성 검사 추가


🎨 테스트용 샘플 SQL 쿼리
sql-- 기본 SELECT
SELECT * FROM emp;

-- JOIN 쿼리
SELECT e.empno, e.ename, e.job, d.dname, d.loc
FROM emp e
INNER JOIN dept d ON e.deptno = d.deptno;

-- WHERE 절
SELECT * FROM emp WHERE sal > 2000 ORDER BY sal DESC;

-- 집계 함수
SELECT deptno, COUNT(*) as emp_count, AVG(sal) as avg_salary
FROM emp
GROUP BY deptno;

-- 오류 쿼리 (테스트용)
SELECT * FROM employee;  -- 테이블이 존재하지 않음

🔐 보안 참고사항

데이터베이스 인증 정보에는 환경 변수 사용
백엔드에서 SQL 인젝션 방지 구현
인증/권한 추가 (향후 단계)
프로덕션에서는 HTTPS 사용


📦 권장 라이브러리
json{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^5.0.0",
    "@monaco-editor/react": "^4.6.0",
    "axios": "^1.6.0",
    "sql-formatter": "^15.0.0",
    "lucide-react": "^0.300.0",
    "tailwindcss": "^3.4.0",
    "@tanstack/react-table": "^8.10.0"
  }
}

🎯 성공 기준

 사용자가 5개의 다른 DBMS 중에서 선택 가능
 SQL 편집기에 문법 하이라이팅과 줄 번호 있음
 실행 버튼이 SQL을 실행하고 결과를 테이블로 표시
 SQL 포맷팅 버튼이 SQL 코드를 적절히 들여쓰기
 지우기 버튼이 편집기를 비움
 결과에 실행 시간과 행 개수 표시
 오류 메시지가 줄 번호와 함께 명확히 표시
 CSV 내보내기가 결과를 CSV 파일로 다운로드
 쿼리 히스토리가 마지막 10개 쿼리 저장
 태블릿과 데스크톱에서 반응형 디자인 작동
 쿼리 실행 중 로딩 상태 표시


🎨 디자인 참고

다음과 유사한 깔끔하고 전문적인 디자인 사용:

Azure Data Studio
DBeaver
TablePlus
phpMyAdmin


현대적인 UI:

미묘한 그림자와 테두리
부드러운 애니메이션 (0.2초 전환)
명확한 시각적 계층 구조
접근 가능한 색상 대비 (WCAG AA)




💡 추가 참고사항

깔끔하고 읽기 쉬운 코드에 집중
복잡한 함수에는 JSDoc 주석 추가
적절한 TypeScript 타입 구현
React 모범 사례 사용 (hooks, custom hooks)
재사용 가능한 컴포넌트 만들기
더 나은 UX를 위한 로딩 스켈레톤 추가
자동 저장을 위한 디바운싱 구현 (선택사항)
다크 모드 토글 고려 (선택사항)


1단계부터 시작하여 점진적으로 구축하세요. 초기에는 Mock 데이터를 사용하고 나중에 실제 데이터베이스에 연결하세요.

2. WSL2 환경 구축 및 Ubuntu Linux 설치

  • powershell 관리자 권한으로 실행

    윈도우 파워셸
  • wsl --install 실행

    Windows powershell 명령의 스크린샷

  • 컴퓨터 재부팅

  • 컴퓨터 재부팅 후 Ubuntu 자동 설치

  • 설치 확인

3. docker 환경 구성 및 oracle 설치

  • docker 엔진 설치하기

    # 기존 Docker 흔적 있으면 정리
    sudo apt remove docker docker-engine docker.io containerd runc
    
    # 필수 패키지 설치
    sudo apt update
    sudo apt install -y ca-certificates curl gnupg
    
    # Docker 공식 GPG 키 추가
    # 이 단계는 “공식 Docker 저장소를 신뢰한다”는 의미입니다
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
    sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    # Docker 공식 저장소 등록
    echo \
    "deb [arch=$(dpkg --print-architecture) \
    signed-by=/etc/apt/keyrings/docker.gpg] \
    https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    # Docker 엔진 설치
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
    # Docker 정상 설치 확인
    docker --version
    
    # sudo 없이 docker 쓰기 설정
    sudo usermod -aG docker $USER
    
    # 테스트 
    docker run hello-world
  • oracle 설치

    docker run -d --name oracle-free -p 1521:1521 -e ORACLE_PASSWORD=oracle gvenzl/oracle-free:23-slim
  • 테스트 DB 사용자 및 테이블 생성

    docker exec -it oracle-free /bin/bash
    sqlplus system/oracle
    CREATE USER scott IDENTIFIED BY tiger;
    GRANT connect, resource TO scott;
    ALTER USER scott QUOTA UNLIMITED ON users;
    connect scott/tiger;
    
    DROP TABLE EMP;
    DROP TABLE DEPT;
    DROP TABLE BONUS;
    DROP TABLE SALGRADE;
    
    
    CREATE TABLE DEPT (
     DEPTNO              NUMBER(2) NOT NULL,
     DNAME               VARCHAR2(14),
     LOC                 VARCHAR2(13),
     CONSTRAINT DEPT_PRIMARY_KEY PRIMARY KEY (DEPTNO));
    
    INSERT INTO DEPT VALUES (10,'ACCOUNTING','NEW YORK');
    INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS');
    INSERT INTO DEPT VALUES (30,'SALES','CHICAGO');
    INSERT INTO DEPT VALUES (40,'OPERATIONS','BOSTON');
    
    CREATE TABLE EMP (
     EMPNO               NUMBER(4) NOT NULL,
     ENAME               VARCHAR2(10),
     JOB                 VARCHAR2(9),
     MGR                 NUMBER(4) ,
     HIREDATE            DATE,
     SAL                 NUMBER(7,2),
     COMM                NUMBER(7,2),
     DEPTNO              NUMBER(2) ,
     CONSTRAINT EMP_FOREIGN_KEY FOREIGN KEY (DEPTNO) REFERENCES DEPT (DEPTNO),
     CONSTRAINT EMP_PRIMARY_KEY PRIMARY KEY (EMPNO));
    
    INSERT INTO EMP VALUES (7369,'SMITH','CLERK',7902,NULL,800,NULL,20);
    INSERT INTO EMP VALUES (7499,'ALLEN','SALESMAN',7698,NULL,1600,300,30);
    INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698,NULL,1250,500,30);
    INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839,NULL,2975,NULL,20);
    INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN',7698,NULL,1250,1400,30);
    INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,NULL,2850,NULL,30);
    INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,NULL,2450,NULL,10);
    INSERT INTO EMP VALUES (7788,'SCOTT','ANALYST',7566,NULL,3000,NULL,20);
    INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,NULL,5000,NULL,10);
    INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,NULL,1500,0,30);
    INSERT INTO EMP VALUES (7876,'ADAMS','CLERK',7788,NULL,1100,NULL,20);
    INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,NULL,950,NULL,30);
    INSERT INTO EMP VALUES (7902,'FORD','ANALYST',7566,NULL,3000,NULL,20);
    INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,NULL,1500,0,30);
    
    CREATE TABLE BONUS (
     ENAME               VARCHAR2(10),
     JOB                 CHAR(9),
     SAL                 NUMBER,
     COMM                NUMBER);
    
    CREATE TABLE SALGRADE (
     GRADE               NUMBER,
     LOSAL               NUMBER,
     HISAL               NUMBER);
    
    INSERT INTO SALGRADE VALUES (1,700,1200);
    INSERT INTO SALGRADE VALUES (2,1201,1400);
    INSERT INTO SALGRADE VALUES (3,1401,2000);
    INSERT INTO SALGRADE VALUES (4,2001,3000);
    INSERT INTO SALGRADE VALUES (5,3001,9999);
    
    COMMIT;

4. Lovable 앱 개발

# Lovable 프롬프트: 다중 DBMS SQL 편집기

---

## 📋 프로젝트 개요

여러 데이터베이스 시스템(Oracle, MySQL, PostgreSQL, MariaDB, SQL Server)에 연결하여 SQL 쿼리를 작성, 실행, 관리할 수 있는 전문적인 웹 기반 SQL 편집기를 만들어주세요.

---

## 🎯 핵심 기능

### 1. 데이터베이스 연결 관리자
- **DBMS 선택기**: 5개의 다른 DBMS를 전환할 수 있는 드롭다운 메뉴
  - Oracle 11g XE (localhost:1521)
  - MySQL 8.0 (localhost:3306)
  - PostgreSQL 15 (localhost:5432)
  - MariaDB 10.11 (localhost:3307)
  - SQL Server 2022 (localhost:1433)

- **연결 상태 표시기**: 
  - 실시간 연결 상태를 색상 인디케이터로 표시
  - 표시 예: "● 연결됨 (scott@oracle11g:1521)" 또는 "○ 연결 안됨"
  - 연결됨은 초록색 점, 연결 안됨은 회색 점

- **사전 구성된 인증 정보**:
  - 사용자: `scott`
  - 비밀번호: `tiger`
  - 데이터베이스: Oracle은 `XE`, 나머지는 `testdb`

### 2. SQL 편집기 컴포넌트
- **Monaco Editor 통합** (선호) 또는 CodeMirror를 대안으로 사용
- **SQL 문법 하이라이팅**: 키워드(SELECT, FROM, WHERE), 함수, 문자열, 주석
- **줄 번호**: 왼쪽에 줄 번호 표시
- **자동 들여쓰기**: SQL 문에 대한 스마트 들여쓰기
- **괄호 매칭**: 일치하는 괄호와 대괄호 강조 표시
- **여러 줄 지원**: 여러 SQL 문 처리 가능

**편집기 플레이스홀더 텍스트**:
```
-- 여기에 SQL 쿼리를 작성하세요
-- 팁: Ctrl + Enter를 눌러 실행하세요
-- 예제: SELECT * FROM emp WHERE deptno = 10;
```

**키보드 단축키**:
- `Ctrl + Enter`: SQL 실행
- `Ctrl + /`: 주석 토글
- `Ctrl + F`: 찾기
- `Ctrl + Shift + F`: SQL 포맷팅
- `Ctrl + Shift + K`: 편집기 지우기

### 3. 액션 버튼
편집기 아래에 다음 버튼들이 있는 툴바를 만들어주세요:

| 버튼 | 아이콘 | 기능 | 스타일 |
|--------|------|----------|-------|
| SQL 포맷팅 | 🎨 | SQL 코드를 자동으로 정렬하고 예쁘게 만들기 | 보조 버튼 |
| 지우기 | 🗑️ | 편집기의 모든 내용 지우기 | 보조 버튼 |
| 실행 | ▶️ | SQL 쿼리 실행 | 주요 버튼 (파란색) |
| CSV 내보내기 | 📥 | 결과를 CSV로 다운로드 | 보조 버튼 |
| 히스토리 | 🕐 | 쿼리 히스토리 보기 | 보조 버튼 |

**버튼 상태**:
- 편집기가 비어있거나 연결되지 않았을 때 "실행" 비활성화
- SELECT 결과가 없을 때 "CSV 내보내기" 비활성화
- 쿼리 실행 중에는 "실행" 버튼에 로딩 스피너 표시

### 4. 결과 패널
**빈 상태** (첫 실행 전):
```
아직 결과가 없습니다.
SQL 쿼리를 실행하여 여기에서 결과를 확인하세요.
```

**SELECT 쿼리 결과**:
- 인터랙티브 데이터 테이블로 표시
- 정렬 가능한 컬럼 헤더
- 실행 시간 표시: "실행 시간: 0.045초"
- 행 개수: "행: 14개"
- 대용량 결과에 대한 페이지네이션 (페이지당 100행)
- 가로 및 세로 스크롤
- 가독성을 위한 교대 행 색상

**DML 쿼리 결과** (INSERT/UPDATE/DELETE):
```
✓ 쿼리가 성공적으로 실행되었습니다
영향받은 행: 5개
실행 시간: 0.032초
```

**에러 메시지**:
```
❌ 쿼리 실행 중 오류:
ORA-00942: 테이블 또는 뷰가 존재하지 않습니다

라인 1, 위치 15
SELECT * FROM employee;
              ^
```

### 5. 추가 기능
- **CSV 내보내기**: 쿼리 결과를 CSV 파일로 다운로드
- **결과 복사**: 결과를 클립보드에 복사
- **쿼리 히스토리**: 타임스탬프와 함께 마지막 10개의 실행된 쿼리 저장
- **연결 테스트**: DBMS가 선택되면 자동으로 연결 테스트
- **반응형 디자인**: 모바일 친화적 레이아웃

---

## 🎨 UI/UX 디자인 요구사항

### 레이아웃 구조
```
┌─────────────────────────────────────────────────────┐
│  [🗄️ 로고] 다중 DBMS SQL 편집기     [👤 사용자 정보] │
├─────────────────────────────────────────────────────┤
│  데이터베이스: [Oracle ▼] [MySQL ▼] [PostgreSQL ▼]  │
│  상태: ● 연결됨 (scott@oracle11g:1521)              │
├─────────────────────────────────────────────────────┤
│                                                     │
│  [ SQL 편집기 - 전체 너비, 높이: 300px ]            │
│  - SQL 문법 하이라이팅이 있는 Monaco 편집기         │
│  - 줄 번호, 자동완성                                │
│                                                     │
├─────────────────────────────────────────────────────┤
│  [SQL 포맷팅] [지우기] [실행] [내보내기] [히스토리]  │
├─────────────────────────────────────────────────────┤
│  결과 패널                                          │
│  ┌───────────────────────────────────────────────┐ │
│  │ 실행 시간: 0.045초  |  행: 14개              │ │
│  ├───────┬────────┬──────────┬─────┬──────────┤ │
│  │ EMPNO │ ENAME  │ JOB      │ SAL │ DEPTNO   │ │
│  ├───────┼────────┼──────────┼─────┼──────────┤ │
│  │ 7369  │ SMITH  │ CLERK    │ 800 │ 20       │ │
│  │ 7499  │ ALLEN  │ SALESMAN │1600 │ 30       │ │
│  └───────┴────────┴──────────┴─────┴──────────┘ │
│  [결과 복사] [CSV 내보내기]                         │
└─────────────────────────────────────────────────────┘
```

### 색상 구성
- **주요 색상**: 파란색 (#2563eb) - 실행 버튼용
- **보조 색상**: 회색 (#6b7280) - 다른 버튼용
- **성공**: 초록색 (#10b981) - 성공적인 쿼리용
- **오류**: 빨간색 (#ef4444) - 오류 메시지용
- **배경**: 연한 회색 (#f9fafb) - 결과 패널용
- **편집기 배경**: 어두운 색 (#1e1e1e) 또는 밝은 색 (#ffffff) 토글 가능

### 타이포그래피
- **글꼴 패밀리**: 'Inter', 'Segoe UI', sans-serif (UI용)
- **편집기 글꼴**: 'Fira Code', 'Consolas', monospace
- **글꼴 크기**: 
  - 헤더: 24px
  - 본문: 14px
  - 편집기: 14px
  - 버튼: 14px

---

## 🔧 기술 구현

### 프론트엔드 스택
- **프레임워크**: React 18+ with TypeScript
- **코드 편집기**: Monaco Editor (@monaco-editor/react 사용)
- **UI 컴포넌트**: shadcn/ui 또는 Ant Design
- **상태 관리**: React Context API 또는 Zustand
- **HTTP 클라이언트**: Axios (API 호출용)
- **스타일링**: Tailwind CSS

### 백엔드 API 엔드포인트 (현재는 Mock)

**POST /api/sql/execute**
```json
요청:
{
  "dbms": "oracle",
  "sql": "SELECT * FROM emp WHERE deptno = 10",
  "connectionId": "conn_12345"
}

응답 (성공):
{
  "success": true,
  "data": {
    "columns": ["EMPNO", "ENAME", "JOB", "SAL", "DEPTNO"],
    "rows": [
      [7782, "CLARK", "MANAGER", 2450, 10],
      [7839, "KING", "PRESIDENT", 5000, 10]
    ],
    "rowCount": 2,
    "executionTime": 0.045
  }
}

응답 (오류):
{
  "success": false,
  "error": {
    "code": "ORA-00942",
    "message": "테이블 또는 뷰가 존재하지 않습니다",
    "line": 1,
    "position": 15
  }
}
```

**POST /api/connection/test**
```json
요청:
{
  "dbms": "mysql",
  "host": "localhost",
  "port": 3306,
  "database": "testdb",
  "username": "scott",
  "password": "tiger"
}

응답:
{
  "success": true,
  "message": "성공적으로 연결되었습니다",
  "serverVersion": "MySQL 8.0.35"
}
```

### 샘플 Mock 데이터 (초기 개발용)
```javascript
const mockEmployees = [
  { empno: 7369, ename: 'SMITH', job: 'CLERK', sal: 800, deptno: 20 },
  { empno: 7499, ename: 'ALLEN', job: 'SALESMAN', sal: 1600, deptno: 30 },
  { empno: 7521, ename: 'WARD', job: 'SALESMAN', sal: 1250, deptno: 30 },
  { empno: 7566, ename: 'JONES', job: 'MANAGER', sal: 2975, deptno: 20 },
  { empno: 7654, ename: 'MARTIN', job: 'SALESMAN', sal: 1250, deptno: 30 },
  { empno: 7698, ename: 'BLAKE', job: 'MANAGER', sal: 2850, deptno: 30 },
  { empno: 7782, ename: 'CLARK', job: 'MANAGER', sal: 2450, deptno: 10 },
  { empno: 7788, ename: 'SCOTT', job: 'ANALYST', sal: 3000, deptno: 20 },
  { empno: 7839, ename: 'KING', job: 'PRESIDENT', sal: 5000, deptno: 10 },
  { empno: 7844, ename: 'TURNER', job: 'SALESMAN', sal: 1500, deptno: 30 },
  { empno: 7876, ename: 'ADAMS', job: 'CLERK', sal: 1100, deptno: 20 },
  { empno: 7900, ename: 'JAMES', job: 'CLERK', sal: 950, deptno: 30 },
  { empno: 7902, ename: 'FORD', job: 'ANALYST', sal: 3000, deptno: 20 }
];

const mockDepartments = [
  { deptno: 10, dname: 'ACCOUNTING', loc: 'NEW YORK' },
  { deptno: 20, dname: 'RESEARCH', loc: 'DALLAS' },
  { deptno: 30, dname: 'SALES', loc: 'CHICAGO' },
  { deptno: 40, dname: 'OPERATIONS', loc: 'BOSTON' }
];
```

---

## 📝 컴포넌트 구조

```
src/
├── components/
│   ├── Header.tsx                 # 로고, 타이틀, 사용자 정보
│   ├── DatabaseSelector.tsx       # DBMS 드롭다운 선택기
│   ├── ConnectionStatus.tsx       # 연결 인디케이터
│   ├── SqlEditor.tsx              # Monaco 편집기 래퍼
│   ├── ActionButtons.tsx          # 포맷, 지우기, 실행 버튼
│   ├── ResultsPanel.tsx           # 쿼리 결과 표시
│   ├── DataTable.tsx              # SELECT 결과용 테이블 컴포넌트
│   ├── ErrorMessage.tsx           # 오류 표시 컴포넌트
│   ├── QueryHistory.tsx           # 히스토리 사이드바/모달
│   └── ExportDialog.tsx           # CSV 내보내기 모달
├── hooks/
│   ├── useConnection.ts           # 데이터베이스 연결 로직
│   ├── useQueryExecution.ts       # SQL 실행 로직
│   └── useQueryHistory.ts         # 히스토리 관리
├── services/
│   ├── api.ts                     # API 클라이언트 (Axios)
│   └── sqlFormatter.ts            # SQL 포맷팅 유틸리티
├── types/
│   ├── database.ts                # 데이터베이스 타입
│   └── query.ts                   # 쿼리 결과 타입
└── App.tsx                        # 메인 애플리케이션
```

---

## 🚀 구현 단계

### 1단계: 기본 레이아웃
1. 헤더, 편집기, 결과 섹션이 있는 메인 레이아웃 생성
2. 5개 옵션이 있는 DBMS 선택기 드롭다운 추가
3. 연결 상태 인디케이터 구현
4. Tailwind CSS로 스타일링

### 2단계: SQL 편집기
1. Monaco Editor 통합
2. SQL 문법 하이라이팅 추가
3. 키보드 단축키 구현 (Ctrl+Enter 등)
4. 플레이스홀더 텍스트 추가

### 3단계: 쿼리 실행
1. Mock API 엔드포인트 생성
2. 로딩 상태가 있는 실행 버튼 구현
3. SQL 파싱 후 Mock 결과 반환
4. 결과를 테이블 형식으로 표시

### 4단계: 추가 기능
1. SQL 포맷팅 버튼 추가 (sql-formatter 라이브러리 사용)
2. 지우기 버튼 구현
3. CSV 내보내기 기능 추가
4. 쿼리 히스토리 패널 생성

### 5단계: 오류 처리
1. 줄/위치가 포함된 SQL 오류 표시
2. 연결 오류 표시
3. 빈 쿼리에 대한 유효성 검사 추가

---

## 🎨 테스트용 샘플 SQL 쿼리

```sql
-- 기본 SELECT
SELECT * FROM emp;

-- JOIN 쿼리
SELECT e.empno, e.ename, e.job, d.dname, d.loc
FROM emp e
INNER JOIN dept d ON e.deptno = d.deptno;

-- WHERE 절
SELECT * FROM emp WHERE sal > 2000 ORDER BY sal DESC;

-- 집계 함수
SELECT deptno, COUNT(*) as emp_count, AVG(sal) as avg_salary
FROM emp
GROUP BY deptno;

-- 오류 쿼리 (테스트용)
SELECT * FROM employee;  -- 테이블이 존재하지 않음
```

---

## 🔐 보안 참고사항

- 데이터베이스 인증 정보에는 환경 변수 사용
- 백엔드에서 SQL 인젝션 방지 구현
- 인증/권한 추가 (향후 단계)
- 프로덕션에서는 HTTPS 사용

---

## 📦 권장 라이브러리

```json
{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^5.0.0",
    "@monaco-editor/react": "^4.6.0",
    "axios": "^1.6.0",
    "sql-formatter": "^15.0.0",
    "lucide-react": "^0.300.0",
    "tailwindcss": "^3.4.0",
    "@tanstack/react-table": "^8.10.0"
  }
}
```

---

## 🎯 성공 기준

- [ ] 사용자가 5개의 다른 DBMS 중에서 선택 가능
- [ ] SQL 편집기에 문법 하이라이팅과 줄 번호 있음
- [ ] 실행 버튼이 SQL을 실행하고 결과를 테이블로 표시
- [ ] SQL 포맷팅 버튼이 SQL 코드를 적절히 들여쓰기
- [ ] 지우기 버튼이 편집기를 비움
- [ ] 결과에 실행 시간과 행 개수 표시
- [ ] 오류 메시지가 줄 번호와 함께 명확히 표시
- [ ] CSV 내보내기가 결과를 CSV 파일로 다운로드
- [ ] 쿼리 히스토리가 마지막 10개 쿼리 저장
- [ ] 태블릿과 데스크톱에서 반응형 디자인 작동
- [ ] 쿼리 실행 중 로딩 상태 표시

---

## 🎨 디자인 참고

- 다음과 유사한 깔끔하고 전문적인 디자인 사용:
  - Azure Data Studio
  - DBeaver
  - TablePlus
  - phpMyAdmin

- 현대적인 UI:
  - 미묘한 그림자와 테두리
  - 부드러운 애니메이션 (0.2초 전환)
  - 명확한 시각적 계층 구조
  - 접근 가능한 색상 대비 (WCAG AA)

---

## 💡 추가 참고사항

- 깔끔하고 읽기 쉬운 코드에 집중
- 복잡한 함수에는 JSDoc 주석 추가
- 적절한 TypeScript 타입 구현
- React 모범 사례 사용 (hooks, custom hooks)
- 재사용 가능한 컴포넌트 만들기
- 더 나은 UX를 위한 로딩 스켈레톤 추가
- 자동 저장을 위한 디바운싱 구현 (선택사항)
- 다크 모드 토글 고려 (선택사항)

---

**1단계부터 시작하여 점진적으로 구축하세요. 초기에는 Mock 데이터를 사용하고 나중에 실제 데이터베이스에 연결하세요.**
"실행" 버튼을 클릭하면 emp Mock 데이터를 보여줘야되. 다시 수정해줘.
  • 이기종 DBMS에 접속하는 "관리" 기능 만들기 위해서 Gemini를 github 연동해서 PRD 작성

"이기종 DBMS 등록 및 관리 기능 추가를 위한 프롬프트" 뿐만이 아니라 모든 기능은 로컬에 데이터가 파일로 저장이 되어야 되. 소스를 다운로드 받고 로컬에서 실행을 할 거야. 프롬프트 다시 작성해줘.
  • Gemini에서 작성된 PRD를 Lovable에 다시 실행

제목: 로컬 파일 기반의 다중 DBMS 연결 관리자 및 데이터 영속성 구현

요청 내용: 현재 프로젝트의 고정된 DBMS 설정을 사용자가 직접 관리하고, 모든 데이터(연결 정보, 쿼리 기록 등)를 로컬에 파일로 저장하거나 브라우저에 영구적으로 보관할 수 있는 기능을 추가해줘.

1. 데이터 모델 및 로컬 스토리지 확장 (src/types/database.ts, src/store/sqlEditorStore.ts):

DBMSConfig 확장: DBMSConfig 인터페이스에 실제 접속에 필요한 상세 정보(username, password, description 등)를 포함하도록 수정해줘.

상태 관리: sqlEditorStore.ts에 userConnections (사용자 등록 연결 리스트) 상태를 추가해줘.

자동 저장: Zustand의 persist 미들웨어를 사용하여 userConnections, history, selectedDbms 등 모든 중요 상태가 로컬 스토리지에 즉시 저장되도록 설정해줘. 초기 실행 시 DBMS_CONFIGS를 기본값으로 시드 데이터로 넣어줘.

2. 로컬 파일 기반 저장 및 불러오기 기능 (File System API/JSON):

설정 내보내기 (Export): 현재 등록된 모든 연결 정보와 쿼리 히스토리를 sql_chum_data.json 파일로 로컬에 다운로드하는 기능을 추가해줘.

설정 불러오기 (Import): 사용자가 가지고 있는 JSON 파일을 업로드하여 연결 정보를 복원하거나 병합하는 기능을 구현해줘.

이 기능은 '설정' 모달 또는 '연결 관리' 화면 내에 배치해줘.

3. DBMS 연결 관리 UI (CRUD) 구현:

ConnectionManagerModal: 연결을 추가, 수정, 삭제할 수 있는 관리 화면을 Shadcn UI의 Dialog와 Form을 사용해 만들어줘.

연결 테스트: 폼 내에 sqlExecutor.ts의 testConnection을 호출하는 버튼을 두어 실제 연결 가능 여부를 시뮬레이션해줘.

DatabaseSelector.tsx를 수정하여 하드코딩된 리스트 대신 스토어의 userConnections를 표시하고, 하단에 '연결 관리...' 메뉴를 추가해줘.

4. 쿼리 히스토리 및 결과 보존:

실행된 쿼리와 결과 리스트(history)가 로컬에 계속 유지되어, 앱을 재실행하거나 소스를 다시 빌드해도 데이터가 날아가지 않게 보장해줘.

5. 기술 스택 및 디자인:

기존의 lucide-react 아이콘과 shadcn/ui 컴포넌트들을 활용해 일관된 다크 모드 디자인을 유지해줘.

파일 저장 시 개인정보(비밀번호 등)가 포함되므로, 내보내기 시 주의 문구를 UI에 표시해줘.
  • Lovable 공식문서에서 명시된 프롬프트 기법 사용
    "제가 이 기능에서 원하는 바와 구상하는 바를 완전히 이해하는 데 필요한 질문이 있으면 무엇이든 물어보세요."

    팁 : 해당 프롬프트 실행 시 Lovable "Plan"로 실행

나는 실제 이기종 데이터베이스를 접속을 해서 테스트를 할거야. 이제부터는 목업 데이터가 아니라 실제 데이터가 나와야 되.

제가 이 기능에서 원하는 바와 구상하는 바를 완전히 이해하는 데 필요한 질문이 있으면 무엇이든 물어보세요.

플랜 모드로 진행

자연어를 입력하면 SQL을 자동 생성하고 싶어. ChatGPT, Claude, Gemini API 등을 연동할거야. 구현해줘.

사본

버튼이 보이지 않아. 버튼 보이게 수정해줘.
  • Github push

5. Cursor ai 앱 실행

  • Github

    git clone https://github.com/JwaSeongHoon/sql-chum.git
  • Cursor AI 실행

    cd C:\workspace\sql-chum
    cursor .
  • APP 실행

    # Terminal 1
    cd sql-proxy-server
    npm install
    npm run dev

    # Terminal 2
    npm install
    npm run dev
  • 관리 : 데이터베이스 정보 입력, LLM 키 입력

  • "emp 테이블에서 급여가 3000 이상인 사람만 조회" 하면 아래 그림과 같이 SQL이 자동 실행됨.

한국사이트 스크린샷
  • 실행 버튼 클릭하면 데이터가 조회됨

결과와 배운 점

이기종 DBMS SQL 실습을 보다 효율적으로 진행하기 위해 다중 DBMS SQL 편집기와 자연어 기반 SQL 생성 애플리케이션을 기획하고 구현하였습니다. WSL2 기반 Ubuntu 환경과 Docker 단일 컨테이너를 활용하여 Oracle을 포함한 교육용 표준 계정과 테스트 데이터를 안정적으로 구성하였습니다. 또한 Monaco Editor 중심의 SQL 편집기와 실행, 포맷, 히스토리, 결과 패널을 구현하여 학습자가 실습 흐름을 직관적으로 이해할 수 있도록 하였습니다. 초기 목업 데이터 중심의 구조에서 실제 데이터베이스 접속 결과가 출력되도록 전환하면서, 실데이터 기반 실습이 교육 몰입도와 이해도를 크게 높인다는 점을 확인할 수 있었습니다. 더불어 연결 정보와 쿼리 이력을 로컬 영속성으로 관리하여 소스를 다시 실행하더라도 실습 환경이 유지되도록 개선하였습니다. 마지막으로 자연어를 SQL로 자동 변환하는 생성형 AI 연동을 통해, 복잡한 조인과 같은 난이도 높은 SQL 학습 부담을 줄일 수 있는 교육 보조 도구로서의 가능성을 확인하였습니다.

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요