Bolt 사례 연구: 비영리 교육 스타트업이 72시간 만에 다국어 학부모 소통 포털을 구축한 방법
프로젝트 배경: 6주 개발 일정을 72시간으로 단축
서울 기반 비영리 교육 스타트업 ‘글로벌에듀커넥트’는 다문화 가정 학부모를 위한 다국어 소통 포털이 시급했습니다. 기존 견적은 6주, 예산은 2,500만 원이었지만, Bolt를 활용해 72시간 만에 프로덕션 수준의 포털을 완성했습니다. 이 사례 연구에서는 AI 생성 React 컴포넌트, Supabase 인증 및 행 수준 보안(RLS), Vercel Edge Function 기반 현지화를 결합한 전체 워크플로우를 공개합니다.
기술 스택 및 아키텍처
| 레이어 | 기술 | 역할 |
|---|---|---|
| 프론트엔드 | React + Tailwind CSS (Bolt 생성) | AI 자동 생성 컴포넌트 |
| 인증/DB | Supabase Auth + RLS | 학부모별 데이터 격리 |
| 현지화 | Vercel Edge Functions | 엣지 기반 실시간 번역 |
| 배포 | Vercel | 글로벌 CDN 배포 |
Bolt 프롬프트 예시
다국어 학부모 소통 포털을 만들어주세요.
- 로그인/회원가입 페이지 (이메일 + 소셜 로그인)
- 대시보드: 공지사항 목록, 자녀 출석 현황
- 메시지 센터: 교사-학부모 1:1 채팅
- 언어 선택 드롭다운 (한국어, 영어, 베트남어, 중국어)
- Supabase를 백엔드로 사용
- Tailwind CSS로 반응형 디자인
모든 텍스트는 i18n 키로 처리Bolt가 생성한 프로젝트를 로컬에 클론하고 의존성을 설치합니다.
git clone https://github.com/your-org/parent-portal.git cd parent-portal npm install
Bolt 생성 컴포넌트 구조
src/
├── components/
│ ├── Dashboard.tsx
│ ├── MessageCenter.tsx
│ ├── AnnouncementList.tsx
│ ├── LanguageSelector.tsx
│ └── AttendanceChart.tsx
├── lib/
│ ├── supabase.ts
│ └── i18n.ts
└── pages/
├── login.tsx
└── index.tsx
2단계: Supabase 인증 및 행 수준 보안 (12~36시간)
Supabase 프로젝트 설정
npm install @supabase/supabase-js
Supabase 클라이언트 초기화
// src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
'https://YOUR_PROJECT_ID.supabase.co',
'YOUR_ANON_KEY'
)
행 수준 보안(RLS) 정책 SQL
-- 학부모는 자신의 자녀 데이터만 조회 가능
CREATE POLICY "parents_own_children" ON students
FOR SELECT
USING (parent_id = auth.uid());
-- 메시지는 발신자 또는 수신자만 조회 가능
CREATE POLICY "message_access" ON messages
FOR SELECT
USING (
sender_id = auth.uid() OR
receiver_id = auth.uid()
);
-- 공지사항은 같은 학교 소속만 조회
CREATE POLICY "school_announcements" ON announcements
FOR SELECT
USING (
school_id IN (
SELECT school_id FROM students
WHERE parent_id = auth.uid()
)
);
-- 모든 테이블에 RLS 활성화
ALTER TABLE students ENABLE ROW LEVEL SECURITY;
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE announcements ENABLE ROW LEVEL SECURITY;
인증 컴포넌트 (Bolt 생성 후 수정)
// src/pages/login.tsx
import { supabase } from '../lib/supabase'
import { useState } from 'react'
export default function Login() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleLogin = async () => {
const { error } = await supabase.auth.signInWithPassword({
email, password
})
if (error) alert(error.message)
}
const handleGoogleLogin = async () => {
await supabase.auth.signInWithOAuth({ provider: 'google' })
}
return (
setEmail(e.target.value)}
className="w-full p-3 border rounded mb-3"
placeholder="이메일" />
setPassword(e.target.value)}
className="w-full p-3 border rounded mb-3"
placeholder="비밀번호" />
)
}
3단계: Vercel Edge Function 현지화 (36~60시간)
Edge Function으로 실시간 언어 감지 및 번역
// api/localize.ts (Vercel Edge Function)
export const config = { runtime: 'edge' }
const translations: Record> = {
ko: { welcome: '환영합니다', dashboard: '대시보드', messages: '메시지' },
en: { welcome: 'Welcome', dashboard: 'Dashboard', messages: 'Messages' },
vi: { welcome: 'Chào mừng', dashboard: 'Bảng điều khiển', messages: 'Tin nhắn' },
zh: { welcome: '欢迎', dashboard: '仪表板', messages: '消息' }
}
export default async function handler(req: Request) {
const url = new URL(req.url)
const lang = url.searchParams.get('lang')
|| req.headers.get('accept-language')?.split(',')[0]?.substring(0, 2)
|| 'ko'
const t = translations[lang] || translations['ko']
return new Response(JSON.stringify(t), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, s-maxage=3600'
}
})
}
Vercel 배포
npm install -g vercel
vercel --prod
4단계: 최종 통합 및 배포 (60~72시간)
환경 변수를 Vercel 대시보드에 설정합니다.
vercel env add NEXT_PUBLIC_SUPABASE_URL
vercel env add NEXT_PUBLIC_SUPABASE_ANON_KEY
## 성과 비교
| 항목 | 기존 방식 | Bolt 활용 |
|---|---|---|
| 개발 기간 | 6주 | 72시간 |
| 투입 인원 | 프론트 2명 + 백엔드 1명 | 1명 |
| 예상 비용 | 2,500만 원 | 약 150만 원 |
| 지원 언어 | 2개 (한/영) | 4개 (한/영/베/중) |
| RLS 보안 | 수동 구현 2주 | SQL 정책 3시간 |
SET request.jwt.claim.sub = 'test-user-id';를 사용해 다른 사용자 관점에서 정책을 검증하세요.- **Edge Function 캐싱**: s-maxage=3600 헤더로 번역 응답을 CDN 레벨에서 캐싱하면 응답 시간이 50ms 이하로 줄어듭니다.- **Bolt 코드 리팩토링**: Bolt가 생성한 코드를 그대로 쓰지 말고, 비즈니스 로직은 반드시 분리하여 lib/ 디렉토리에 정리하세요.
## Troubleshooting: 자주 발생하는 오류
RLS 정책으로 인한 빈 데이터 반환
**증상**: 로그인 후 대시보드에 데이터가 표시되지 않음
-- 해결: RLS 정책에서 auth.uid() 확인
SELECT auth.uid(); -- 현재 인증된 사용자 ID 확인
— students 테이블의 parent_id가 실제 auth.uid()와 매칭되는지 검증
SELECT * FROM students WHERE parent_id = auth.uid();
Edge Function 한글 깨짐
**증상**: 베트남어/중국어 문자가 깨져서 표시됨
// 해결: Response에 charset 명시
return new Response(JSON.stringify(t), {
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
### Supabase 인증 리다이렉트 오류
**증상**: Google 소셜 로그인 후 localhost로 리다이렉트됨 **해결**: Supabase 대시보드 > Authentication > URL Configuration에서 Site URL과 Redirect URLs를 프로덕션 도메인으로 업데이트하세요. ## 자주 묻는 질문 (FAQ)
Q1: Bolt가 생성한 코드의 품질은 프로덕션에 적합한가요?
Bolt가 생성하는 React 컴포넌트는 기본적인 UI 구조와 스타일링에서 높은 품질을 보여줍니다. 다만 비즈니스 로직, 에러 핸들링, 접근성(a11y) 측면에서는 반드시 개발자 검수가 필요합니다. 이 사례에서는 Bolt 생성 코드의 약 70%를 그대로 활용하고 30%를 수정했습니다.
Q2: Supabase RLS만으로 비영리 교육 데이터의 보안 요구사항을 충족할 수 있나요?
RLS는 데이터베이스 레벨의 강력한 보안을 제공합니다. 학부모별 자녀 데이터 격리, 교사-학부모 메시지 프라이버시 등 핵심 요구사항은 충분히 충족됩니다. 다만 FERPA나 개인정보보호법 규정에 따라 추가적인 감사 로그와 데이터 암호화가 필요할 수 있습니다.
Q3: 4개 이상의 언어를 추가하려면 Edge Function 구조를 변경해야 하나요?
아닙니다. translations 객체에 새 언어 키를 추가하기만 하면 됩니다. 대규모 번역이 필요한 경우 JSON 파일을 외부로 분리하고 Edge Function에서 동적으로 불러오는 방식을 권장합니다. Vercel Edge Function의 번들 크기 제한(1MB)에 유의하세요.