VibeCraft: 민관협력 공모전 특별상 수상기
Gemini CLI로 원샷 대시보드 생성 에이전트를 만들어 민관협력 공모전에서 특별상을 수상한 이야기
대학 동기들과 4년만에 공모전에 다시 나가기로 했습니다. 아이디어를 정하는 과정에서, 제가 만들어본 원샷 대시보드 생성기가 채택되었습니다. 당시 이런 방식이 “바이브 코딩”이라 불리고 있어서, 팀 이름을 VibeCraft로 정했습니다.
아이디어의 시작: 물고기 도감
공모전 아이디어의 시작점은 스쿠버 다이빙이었습니다. 어종 정보를 쉽게 찾아보고 싶어서, GBIF(Global Biodiversity Information Facility)에서 FishBase 데이터를 다운받아 GIS 기반 도감을 만들어본 적이 있었습니다.
46만 건의 물고기 데이터를 가지고, 프롬프트 한 번으로 지도 기반 대시보드를 만들었습니다:
fishbasedatabase.csv 파일이 있어. GBIF에서 다운받은 물고기 데이터야. (46만건)
이걸로 지도 기반 대시보드 만들어줘.- 지도에서 물고기 분포를 지역별로 볼 수 있게- 과/속/국가/연도로 필터링- 전체 통계도 보여주면 좋겠어이걸 동기들에게 보여줬더니 반응이 좋았습니다. “이게 한번에 돼?” 그래서 이 방향으로 발전시켜보기로 했습니다.


역할 분담
디지털 사회혁신 서비스 개발·아이디어 공모전. 과학기술정보통신부 주최, NIA 주관의 민관협력 공모전이었습니다. 2021년에 함께 공모전을 많이 다녔던 친구들인데, 졸업 후에도 종종 만나긴 했지만 공모전은 4년만이었습니다.
다만 다들 회사 일에 바빠서 최소한의 시간 투자만 할 수 있었습니다. 역할 분담은 자연스럽게 이루어졌고, 저는 에이전트 코어 개발을 맡았습니다.
다른 팀원들은 사용자 편의를 위한 프론트엔드와 백엔드를 개발했습니다. 사용자가 웹에서 데이터를 업로드하고 원하는 시각화 유형을 선택하면, 백엔드에서 데이터를 SQLite로 가공하고 요구사항을 프롬프트 형태로 정제해서 에이전트에 전달하는 구조입니다.
flowchart LR A[사용자] --> B[프론트엔드] B --> C[백엔드] C --> D[SQLite 생성] C --> E[프롬프트 정제] D --> F[VibeCraft Agent] E --> F F --> G[React 대시보드]원샷 프롬프트 아키텍처
제가 담당한 부분입니다. 핵심 질문은 이거였습니다: “어떻게 하면 프롬프트 한 번으로 바로 실행 가능한 코드를 만들 수 있을까?”
왜 “원샷”이 어려운가
LLM에게 “대시보드 만들어줘”라고만 하면 기술 스택 선택부터 시작해서 수많은 결정을 내려야 합니다. 이 과정에서 모호함이 생기고, 결과물의 품질이 들쭉날쭉해집니다. 특히 데이터베이스 구조를 모르는 상태에서 SQL 쿼리를 작성하면 거의 확실히 실패합니다.
이 아키텍처는 모호함을 계층별로 제거합니다:
- GEMINI.md: 기술 스택과 필수 패턴 고정 (선택지 제거)
- TemplateEngine: 시각화 타입별 상세 요구사항 (구조 강제)
- MCP 서버: 실제 데이터베이스 구조 분석 (컨텍스트 제공)
- PromptBuilder: 모든 정보를 하나로 조합
전체 파이프라인
flowchart TB subgraph 입력 A[SQLite 파일] B[시각화 타입] C[사용자 요청] end
subgraph 분석 D[SchemaAnalyzer<br/>테이블/컬럼 추출] E[MCP 서버 설정<br/>mcp-server-sqlite] end
subgraph 프롬프트 조합 F[GEMINI.md<br/>시스템 프롬프트] G[TemplateEngine<br/>시각화 템플릿] H[PromptBuilder<br/>최종 조합] end
subgraph 실행 I[Gemini CLI] J[MCP로 DB 분석] K[React 앱 생성] end
A --> D A --> E B --> G C --> H D --> H F --> I G --> H H --> I E --> J I --> J J --> K핵심 1: MCP 서버로 데이터베이스 동적 분석
가장 중요한 부분입니다. Gemini CLI가 실행될 때, MCP(Model Context Protocol) 서버가 SQLite 파일을 실시간으로 분석합니다.
{ "mcpServers": { "sqlite": { "command": "uvx", "args": ["mcp-server-sqlite", "--db-path", "/path/to/data.sqlite"], "includeTools": [ "read_query", "list_tables", "describe_table" ] } }}이 설정 덕분에 Gemini는 프롬프트만 보는 게 아니라, 실제 데이터베이스를 직접 탐색할 수 있습니다:
list_tables: 어떤 테이블이 있는지describe_table: 각 테이블의 컬럼 구조read_query: 샘플 데이터 조회
프롬프트에 스키마를 텍스트로 넣는 것과 MCP로 직접 탐색하는 것은 다릅니다. LLM이 “이 컬럼이 정말 있나?” 확인하고 싶을 때 바로 확인할 수 있으니까요.
핵심 2: 프롬프트 계층 구조
MCP가 데이터를 이해시킨다면, 프롬프트 계층은 구조를 강제합니다:
graph TB A[GEMINI.md<br/>시스템 프롬프트] --> E[Gemini CLI] B[템플릿 프롬프트<br/>templates/*/prompt.md] --> C[TemplateEngine] C --> D[PromptBuilder] F[사용자 입력<br/>User Request] --> D G[스키마 정보<br/>SchemaInfo] --> D D --> H[최종 프롬프트<br/>Final Prompt] H --> E E --> I[생성된 React 앱]1. GEMINI.md (시스템 프롬프트)
Gemini CLI가 자동으로 로드하는 파일입니다. 기술 스택(Vite, React 18, TypeScript, Recharts, Tailwind)과 필수 패턴을 강제합니다. LLM이 자주 실수하는 부분을 미리 막아두는 역할입니다.
## CRITICAL: sql.js Setup Pattern
**ALWAYS use this exact pattern for sql.js:**const SQL = await initSqlJs({ locateFile: (file) => `https://sql.js.org/dist/${file}`});2. TemplateEngine (시각화 타입별 요구사항)
time-series, geo-spatial, kpi-dashboard, comparison 등 시각화 타입별로 상세한 요구사항 템플릿을 준비해뒀습니다. 컴포넌트 구조, 필요한 기능, 패키지 버전까지 명시합니다. 아래는 kpi-dashboard 템플릿 예시입니다:
templates/kpi-dashboard/prompt.md (전체 보기)
# KPI Dashboard Implementation Request
## Project Information- **Project Name**: {{PROJECT_NAME}}- **Visualization Type**: {{VISUALIZATION_TYPE}}- **Generated At**: {{TIMESTAMP}}
## User Requirements{{USER_PROMPT}}
## Implementation Requirements
### 1. Technology Stack- **Framework**: React 18.x with TypeScript- **Charts**: Recharts for data visualization- **Database**: sql.js for in-browser SQLite- **Styling**: Tailwind CSS- **Icons**: Lucide React
### 2. Core Features to Implement
#### Dashboard Layout1. **Header Section** - Dashboard title: "{{DASHBOARD_TITLE}}" - Last updated timestamp - Refresh button (if {{REFRESH_INTERVAL}} > 0)
2. **KPI Cards Grid** - Display primary metrics in card format - Show current value, change percentage, and trend - Use appropriate icons for each metric - Color coding for positive/negative changes
3. **Charts Section** - Bar charts for comparisons - Pie/Donut charts for distributions - Line charts for trends - Responsive grid layout
4. **Data Table** - Sortable columns - Search/filter functionality - Pagination for large datasets - Export to CSV option
#### Key Metrics to CalculateBased on available numeric columns:- Total/Sum values- Averages- Min/Max values- Count of records- Growth rates (if date columns available)- Top N categories (if categorical data exists)
### 3. SQL Query ExamplesHere are relevant queries for your data:{{QUERY_EXAMPLES}}
### 4. Component Structuresrc/├── App.tsx # Main dashboard container├── components/│ ├── Dashboard/│ │ ├── DashboardHeader.tsx│ │ ├── KPICard.tsx│ │ └── KPIGrid.tsx│ ├── Charts/│ │ ├── BarChart.tsx│ │ ├── PieChart.tsx│ │ ├── LineChart.tsx│ │ └── ChartContainer.tsx│ ├── DataTable/│ │ ├── DataTable.tsx│ │ ├── TableFilters.tsx│ │ └── TablePagination.tsx│ └── Common/│ ├── LoadingSpinner.tsx│ └── ErrorBoundary.tsx├── hooks/│ ├── useSQLite.ts│ ├── useKPIData.ts│ └── useAutoRefresh.ts├── utils/│ ├── calculations.ts│ ├── formatters.ts│ └── sqlQueries.ts└── types/ └── index.ts
### 5. KPI Card DesignEach KPI card should include:interface KPICard { title: string; value: number | string; change?: { value: number; percentage: number; trend: 'up' | 'down' | 'neutral'; }; icon: string; color: string; sparkline?: number[];}
### 6. Implementation Guidelines1. **Performance** - Implement React.memo for chart components - Use virtualization for large tables - Cache SQL query results - Debounce search inputs
2. **Interactivity** - Click on KPI cards to drill down - Hover tooltips on all charts - Filter data across all components - Cross-filtering between charts
3. **Responsive Design** - Mobile-first approach - Collapsible sidebar on small screens - Stacked layout for mobile - Touch-friendly interactions
### 7. Package.json DependenciesEnsure your package.json includes these exact versions:{ "dependencies": { "react": "^18.3.1", "react-dom": "^18.3.1", "sql.js": "^1.12.0", "recharts": "^2.12.7", "lucide-react": "^0.454.0", "date-fns": "^3.6.0" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.3.3", "autoprefixer": "^10.4.20", "postcss": "^8.4.49", "tailwindcss": "^3.4.15", "typescript": "^5.6.2", "vite": "^5.4.10" }}
## Final Implementation Notes- Start with loading the SQLite database using the exact pattern shown in system prompt- Calculate all KPIs on initial load- Implement filtering that updates all components- Ensure smooth animations and transitions- Add loading states for all async operations- IMPORTANT: Use Vite, not Create React App- IMPORTANT: Include all required config files (vite.config.ts, tailwind.config.js, etc.)3. PromptBuilder (동적 조합)
DB 스키마 정보와 사용자 요청을 템플릿에 삽입해서 최종 프롬프트를 생성합니다:
buildPrompt(components: PromptComponents): string { return `## Database Schema:${this.formatSchema(schemaInfo)}
## Visualization Requirements:${templateContent}
## User Request:${userPrompt} `;}이 구조 덕분에 LLM이 모호함 없이 일관된 결과물을 만들어낼 수 있었습니다.
결과물
실행 로그 예시입니다:
vibecraft-agent \ --sqlite-path demo/metrics.sqlite \ --visualization-type comparison \ --user-prompt "제품 카테고리별 매출을 막대 차트로, 판매 채널별 비중을 파이 차트로 나란히 표시" \ --output-dir ./output \ --model pro🚀 VibeCraft-Agent starting...📊 Using model: gemini-2.5-pro (Premium quality - 5 req/min)Found Gemini CLI at: /Users/infograb/.nvm/versions/node/v22.16.0/bin/gemini[DEBUG] [MemoryDiscovery] Found readable global GEMINI.md: /Users/infograb/.gemini/GEMINI.md[DEBUG] [MemoryDiscovery] Determined project root: /Users/infograb/Workspace/Personal/Competitions/VibeCraft-Agent[DEBUG] [MemoryDiscovery] Final ordered GEMINI.md paths to read: ["/Users/infograb/.gemini/GEMINI.md", "/Users/infograb/Workspace/Personal/Competitions/VibeCraft-Agent/GEMINI.md"][DEBUG] [MemoryDiscovery] Combined instructions (snippet): --- Context from: ../../GEMINI.md --- # VibeCraft-viz System Prompt You are VibeCraft-viz, a specialized agent for creating beautiful, modern data visualization React applications. ...Session ID: d9caed68-897f-4810-9d89-2b1d9dc41e2bOkay, I will create a React application that visualizes product categoryrevenue with a bar chart and sales channel distribution with a pie chart,side-by-side.SQLite 데이터를 입력하면 바로 실행 가능한 React 앱이 생성됩니다.

수상 소감
결과는 특별상(한국상용SW협회장상)이었습니다.

3등부터는 상격이 달라지는데, 4등을 해서 아쉽기는 했지만 그래도 상을 받게 되어 기뻤습니다. 상금으로 맛있는 것도 먹고, 재밌는 경험이었습니다.
학생 때와는 느낌이 달랐습니다. 2021년에 공모전을 다닐 때는 몰랐는데, 현업을 경험하고 나니 대회를 열어준 주최사, 심사위원, 멘토분들께 감사하게 되더군요. 이런 자리를 만들어주신 모든 분들 덕분에 좋은 경험을 할 수 있었습니다.
VibeCraft-Agent는 공모전용 프로젝트라 퀄리티가 아쉬워서 적극적으로 공개하지는 않습니다.