AI와 음성으로 영어 대화를 연습할 수 있는 웹 애플리케이션입니다. Web Speech API를 활용한 실시간 음성 인식과 TTS(Text-to-Speech)로 자연스러운 대화형 학습 경험을 제공합니다.
- 🎤 음성 기반 대화: Web Speech API를 활용한 실시간 음성 인식 및 응답
- 🤖 AI 영어 튜터: OpenAI API 연동으로 자연스러운 영어 대화 제공
- 💳 멤버십 시스템: Basic/Premium 구독제 (카카오페이 결제 연동)
- 🎯 쿠폰 시스템: 프로모션 쿠폰으로 무료 체험 제공
- 📊 실시간 음성 시각화: 음성 입력 시 오디오 레벨 시각화
- 👤 개인정보 관리: 프로필 수정 및 비밀번호 변경
- RESTful API: 체계적인 백엔드 API 설계
- 반응형 디자인: 모바일/데스크톱 모두 지원
- 실시간 피드백: 음성 인식 중간 결과 표시
- 에러 핸들링: 사용자 친화적인 에러 메시지
graph TB
subgraph "Frontend"
A[React App<br/>:3007]
B[Web Speech API]
A --> B
end
subgraph "Backend"
C[Rails API<br/>:3001]
D[JWT Auth]
C --> D
end
subgraph "External APIs"
E[OpenAI API]
F[KakaoPay API]
end
G[(PostgreSQL)]
A -->|HTTPS| C
C -->|Chat| E
C -->|Payment| F
C -->|Query| G
erDiagram
users ||--o{ memberships : has
users ||--o{ chat_sessions : has
users ||--o{ payments : has
users ||--o{ coupons : has
chat_sessions ||--o{ chat_messages : contains
payments ||--o| memberships : creates
coupons ||--o| memberships : creates
users {
bigint id PK
string email UK
string name
string password_digest
string is_admin
timestamp created_at
}
memberships {
bigint id PK
bigint user_id FK
string membership_type
string status
datetime expires_at
integer duration_days
bigint payment_id FK
bigint coupon_id FK
}
chat_sessions {
bigint id PK
bigint user_id FK
string session_id UK
string status
datetime started_at
datetime ended_at
}
chat_messages {
bigint id PK
bigint chat_session_id FK
string role
text content
datetime timestamp
}
payments {
bigint id PK
bigint user_id FK
string provider
string payment_id
string status
integer amount
string membership_type
}
coupons {
bigint id PK
bigint user_id FK
string coupon_code UK
string membership_type
integer duration_days
string status
datetime expires_at
}
-
음성 인식 플로우
마이크 → Web Speech API → 텍스트 변환 → Rails API → OpenAI API → 응답 생성 → TTS → 스피커 -
인증 플로우
로그인 → JWT 토큰 발급 → localStorage 저장 → API 요청 시 Bearer 토큰 → 검증 -
결제 플로우
멤버십 선택 → KakaoPay 결제 준비 → 리다이렉트 → 결제 승인 → 멤버십 활성화
- Frontend: HTTPS, Content Security Policy
- API: JWT 인증, Rate Limiting, CORS
- Database: BCrypt 암호화, SQL Injection 방지
- Infrastructure: 환경변수 관리, API 키 보호
- Framework: Ruby on Rails (요구사항)
- Database: PostgreSQL
- 선정 이유: JSONB 타입 지원으로 유연한 데이터 저장, 안정성과 성능
- Authentication: JWT (JSON Web Token) 기반 인증
- 선정 이유: 무상태(stateless) 인증으로 확장성 우수, 업계 표준
- BCrypt로 비밀번호 암호화, Bearer 토큰 사용
- 24시간 만료 정책, X-User-ID 헤더 하위 호환성 유지
- Payment: KakaoPay API
- 선정 이유: 한국 사용자 대상 가장 보편적인 결제 수단
- Framework: React with JavaScript
- 선정 이유: 컴포넌트 기반 아키텍처로 재사용성 높음, 풍부한 생태계
- Speech Recognition: Web Speech API
- 선정 이유: 브라우저 네이티브 지원으로 별도 라이브러리 불필요
- Audio Visualization: Web Audio API
- 선정 이유: 실시간 오디오 분석 및 시각화 가능
- Styling: CSS Modules + styled-components
- 선정 이유: 스타일 격리 및 동적 스타일링 지원
- State Management: React Context API
- 선정 이유: 중규모 앱에 적합, Redux보다 간단
- OpenAI API: GPT-4 모델 사용
- 선정 이유: 자연스러운 영어 대화 생성, 문맥 이해 능력 우수
- Prompt Engineering: 영어 튜터 역할 최적화
- 학습자 수준별 맞춤 응답
- 문법 오류 자연스럽게 교정
- Ruby 3.3.0+
- Rails 8.0+
- PostgreSQL 14+
- Node.js 18+
- Chrome/Safari (음성 인식 지원 브라우저)
git clone https://github.com/lim950808/aiTutor.git
cd aiTutorcd backend
bundle install# config/database.yml 수정
# username을 본인 시스템 사용자명으로 변경
# 데이터베이스 생성 및 마이그레이션
rails db:create
rails db:migrate
# 대규모 시드 데이터 적용 (121명 사용자 + 샘플 데이터)
rails runner db/seeds_large.rb# .env 파일 생성
cp .env.example .env
# 필수 설정
OPENAI_API_KEY=your_openai_api_key
KAKAO_ADMIN_KEY=your_kakao_admin_key # 카카오페이용
KAKAO_CID=TC0ONETIME # 테스트용 CIDrails server -p 3001cd ../frontend
npm install# .env 파일 생성
echo "REACT_APP_API_BASE_URL=http://localhost:3001" > .envnpm start # http://localhost:3007cd backend
# 전체 API 엔드포인트 테스트
ruby test_all_apis.rb
# 개별 테스트
rails test
rspec spec/cd frontend
# 유닛 테스트
npm test
# E2E 테스트 (Cypress)
npm run cypress:open-
회원가입/로그인
- 이메일 중복 체크
- 비밀번호 검증 (생성시 6자 이상, 수정시 8자 이상 + 대소문자/숫자/특수문자)
- JWT 토큰 발급 및 검증
-
음성 대화
- 마이크 권한 요청
- 음성 인식 정확도
- AI 응답 속도
- TTS 음성 출력
-
결제 플로우
- 멤버십 구매
- 카카오페이 연동
- 결제 성공/실패 처리
users (사용자)
├── id: bigint (PK)
├── name: string
├── email: string (unique)
├── password_digest: string (BCrypt hash)
├── is_admin: string ('Y'/'N')
└── timestamps
memberships (멤버십)
├── id: bigint (PK)
├── user_id: bigint (FK)
├── membership_type: string ('basic'/'premium')
├── status: string ('active'/'expired')
├── expires_at: datetime
├── purchased_at: datetime
├── payment_id: bigint (FK)
└── timestamps
payments (결제)
├── id: bigint (PK)
├── user_id: bigint (FK)
├── provider: string ('kakao')
├── payment_id: string (TID)
├── status: string ('ready'/'completed'/'failed')
├── amount: integer
└── timestamps
coupons (쿠폰)
├── id: bigint (PK)
├── user_id: bigint (FK)
├── coupon_code: string (unique)
├── membership_type: string
├── duration_days: integer
├── status: string ('active'/'used'/'expired')
└── timestamps
chat_sessions (채팅 세션)
├── id: bigint (PK)
├── user_id: bigint (FK)
├── session_id: string (unique)
├── status: string ('active'/'ended')
├── started_at: datetime
├── ended_at: datetime
└── timestamps
chat_messages (채팅 메시지)
├── id: bigint (PK)
├── chat_session_id: bigint (FK)
├── role: string ('user'/'assistant')
├── content: text
├── timestamp: datetime
└── timestamps
-- 성능 향상을 위한 인덱스
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_memberships_user_status ON memberships(user_id, status);
CREATE INDEX idx_chat_sessions_user ON chat_sessions(user_id);
CREATE INDEX idx_chat_messages_session ON chat_messages(chat_session_id);- OpenAI Platform 접속
- API Key 생성
.env파일에 추가:OPENAI_API_KEY=sk-xxxxxxxxxxxxx
- Kakao Developers 접속
- 애플리케이션 생성
- 카카오페이 API 활성화
- Admin Key 복사
.env파일에 추가:KAKAO_ADMIN_KEY=xxxxxxxxxxxxx KAKAO_CID=TC0ONETIME # 테스트용
# 카카오페이 Redirect URL 등록
- 성공: https://yourdomain.com/payment/success
- 취소: https://yourdomain.com/payment/cancel
- 실패: https://yourdomain.com/payment/fail"Ruby on Rails와 React를 사용해서 AI 영어 회화 학습 앱을 만들어줘.
음성 인식과 TTS 기능이 필요하고, 멤버십 시스템과 결제 기능도 포함해줘."
"Web Speech API를 사용해서 음성 인식 기능을 구현해줘.
음성 인식 중에는 interim results를 보여주고,
AI가 말하는 동안에는 마이크를 비활성화해줘."
"InvalidStateError: Failed to execute 'start' on 'SpeechRecognition'
에러가 발생해. 이미 인식이 시작된 상태에서 다시 start를
호출하는 문제인 것 같은데 해결해줘."
- 각 기능 구현 후 즉시 테스트
- 콘솔 로그로 디버깅 정보 확인
- 네트워크 탭에서 API 호출 검증
# Rubocop으로 Rails 코드 검증
rubocop -a
# ESLint로 React 코드 검증
npm run lint
# 타입 체크 (TypeScript 사용 시)
npm run type-check- API 키 하드코딩 여부 확인
- SQL Injection 취약점 검사
- XSS 공격 방어 확인
- CORS 설정 검증
aiTutor/
├── backend/ # Rails API 서버
│ ├── app/
│ │ ├── controllers/ # API 컨트롤러
│ │ ├── models/ # 데이터 모델
│ │ └── services/ # 비즈니스 로직
│ ├── config/ # 설정 파일
│ ├── db/ # 데이터베이스 관련
│ │ ├── migrate/ # 마이그레이션
│ │ └── seeds_large.rb # 대규모 시드 데이터
│ └── test/ # 테스트 파일
│
├── frontend/ # React 클라이언트
│ ├── src/
│ │ ├── components/ # 재사용 컴포넌트
│ │ ├── pages/ # 페이지 컴포넌트
│ │ ├── hooks/ # 커스텀 훅
│ │ ├── services/ # API 서비스
│ │ └── utils/ # 유틸리티 함수
│ └── public/ # 정적 파일
│
└── README.md # 프로젝트 문서
# 필수 설정
OPENAI_API_KEY=sk-xxxxxxxxxxxxx # OpenAI API 키
KAKAO_ADMIN_KEY=xxxxxxxxxxxxx # 카카오 Admin 키
KAKAO_CID=TC0ONETIME # 카카오페이 CID
# 선택 설정
DATABASE_URL=postgresql://localhost/ai_tutor_development
RAILS_MASTER_KEY=xxxxxxxxxxxxx # Production용
ADMIN_TOKEN=admin123 # 관리자 토큰# API 서버 주소
REACT_APP_API_BASE_URL=http://localhost:3001
# 선택 설정
REACT_APP_ENV=development
REACT_APP_VERSION=1.0.0-
브라우저 호환성
- Chrome, Safari 권장
- Firefox는 Web Speech API 미지원
-
마이크 권한
- HTTPS 환경에서만 작동
- 개발 시 localhost는 예외
-
InvalidStateError 해결
// 이미 실행 중인지 체크 if (recognition.readyState === 'running') { recognition.stop(); }
-
카카오페이 테스트
- CID: TC0ONETIME 사용
- 실제 결제 발생하지 않음
-
도메인 검증 실패
- 개발: localhost 허용
- 운영: 등록된 도메인만 가능
-
PostgreSQL 연결 오류
# macOS brew services restart postgresql@14 # Ubuntu sudo systemctl restart postgresql
-
마이그레이션 오류
# 강제 리셋 (주의!) rails db:drop db:create db:migrate
-
API 키 관리
- 절대 Git에 커밋하지 않기
- 환경 변수로 관리
- Production에서는 암호화된 credentials 사용
-
인증 및 권한
- JWT Bearer 토큰 인증 (24시간 만료)
- BCrypt로 비밀번호 해싱 (salt rounds: 12)
- X-User-ID 헤더 하위 호환성 유지 (JWT 우선)
- Admin 토큰 별도 관리
- Rate Limiting 적용
-
데이터 보호
- 비밀번호 BCrypt 암호화 (cost factor: 12)
- JWT 토큰 서명 검증
- HTTPS 필수 사용
- SQL Injection 방어
- XSS 방지
-
Backend
- N+1 쿼리 방지 (includes 사용)
- 데이터베이스 인덱스 최적화
- Redis 캐싱 (선택사항)
-
Frontend
- React.memo로 불필요한 리렌더링 방지
- 이미지 lazy loading
- 코드 스플리팅
짧은 시간동안 아쉬움이 많이 남는 과제였다. 기존 회사 일도 바쁜데 욕심이 나서 더 많은 기능과 퍼포먼스를 보여주려고 하다보니 정작 필수구현사항이 제대로 구현이 되었는지 모르겠다. 조금더 코드 개선과 질좋은 구조에 힘을 썼어야하지 않나 싶다. AI를 사용하면서 이제는 많은 기술들이 자동으로 만들어질 수 있겠다라는 기대감과 두려움이 컸다. 하지만 아직은 아쉬움이 많고 실수가 많고 인간의 도움이 필요하다. 그래서 끝까지 개발주도권은 내가 가지려고 노력하였다. 그렇기에 개발 뿐만 아니라 설계, 기획, 정책, 디자인, 테스트까지 모두 내가 경험할 수 있는 기회였다.