Skip to main content
Glama
signup.md11.4 kB
# 회원가입 구현 가이드 AIApp BaaS 인증 시스템의 회원가입 기능을 구현하기 위한 핵심 가이드입니다. **Keywords**: signup, 회원가입, register, validation, user creation, form, 사용자등록, HTML, JavaScript, Vanilla, vanilla **Focus**: 회원가입 API 구현, 유효성 검사, HTML/Vanilla JavaScript/React 예제 ## 1. API 명세 ### 기본 정보 - **URL**: `/account/signup` - **Method**: `POST` - **Base URL**: `https://api.aiapp.link` - **Content-Type**: `application/json` - **Description**: 새로운 사용자 계정을 생성합니다. 각 프로젝트는 독립적인 사용자 관리를 위해 project_id가 필수입니다. ### 요청 스키마 #### 필수 필드 ```json { "user_id": "string", // 사용자 ID (4-20자, 영문/숫자) "user_pw": "string", // 비밀번호 (8자 이상) "name": "string", // 사용자 이름 "phone": "string", // 전화번호 (010-1234-5678 형식) "project_id": "string" // 프로젝트 ID (UUID) - 필수 } ``` #### 선택 필드 ```json { "is_reserved": boolean, // 예약 계정 여부 (기본값: false) "data": { // 커스텀 데이터 필드 "age": 25, "interests": ["coding", "music"], "company": "Example Corp" } } ``` ### 요청 예시 ```json { "user_id": "johndoe", "user_pw": "password123", "name": "John Doe", "phone": "010-1234-5678", "is_reserved": false, "project_id": "[PROJECT_ID]", "data": { "age": 25, "department": "Engineering" } } ``` ### 응답 스키마 #### 성공 응답 (201 Created) ```json { "result": "SUCCESS", "message": "회원가입이 완료되었습니다.", "data": { "id": "user-uuid-here", "user_id": "johndoe", "name": "John Doe", "phone": "010-1234-5678", "is_reserved": false, "created_at": "2024-01-15T10:30:00Z", "project_id": "[PROJECT_ID]" } } ``` #### 에러 응답 ##### 422 Validation Error ```json { "result": "FAIL", "errorCode": "VALIDATION_ERROR", "message": "요청 값이 올바르지 않습니다.", "detail": [ { "field": "user_id", "reason": "이미 사용 중인 사용자 ID입니다" } ] } ``` ##### 409 Conflict ```json { "result": "FAIL", "errorCode": "USER_EXISTS", "message": "이미 존재하는 사용자입니다" } ``` ## 2. React 구현 ### 핵심 회원가입 구현 ```tsx import React, { useState } from 'react'; const SignupForm = ({ onSuccess, projectId }) => { const [formData, setFormData] = useState({ user_id: '', user_pw: '', name: '', phone: '', is_reserved: false }); const [loading, setLoading] = useState(false); const [errors, setErrors] = useState({}); const validateForm = () => { const newErrors = {}; if (!formData.user_id || formData.user_id.length < 4) { newErrors.user_id = '사용자 ID는 4자 이상이어야 합니다'; } if (!formData.user_pw || formData.user_pw.length < 8) { newErrors.user_pw = '비밀번호는 8자 이상이어야 합니다'; } if (!formData.name.trim()) { newErrors.name = '이름을 입력해주세요'; } if (!formData.phone || !/^010-\d{4}-\d{4}$/.test(formData.phone)) { newErrors.phone = '올바른 전화번호 형식이 아닙니다 (010-1234-5678)'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = async (e) => { e.preventDefault(); if (!validateForm()) return; setLoading(true); try { const response = await fetch('https://api.aiapp.link/account/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ ...formData, project_id: projectId }) }); const result = await response.json(); if (result.result === 'SUCCESS') { onSuccess?.(result.data); } else { // 서버 에러를 필드별로 매핑 if (result.detail) { const serverErrors = {}; result.detail.forEach(error => { serverErrors[error.field] = error.reason; }); setErrors(serverErrors); } else { setErrors({ general: result.message || '회원가입에 실패했습니다' }); } } } catch (err) { setErrors({ general: '네트워크 오류가 발생했습니다' }); } finally { setLoading(false); } }; const handleChange = (field, value) => { setFormData(prev => ({ ...prev, [field]: value })); // 필드 수정 시 해당 에러 제거 if (errors[field]) { setErrors(prev => ({ ...prev, [field]: '' })); } }; return ( <form onSubmit={handleSubmit}> <div> <input type="text" placeholder="사용자 ID (4-20자)" value={formData.user_id} onChange={(e) => handleChange('user_id', e.target.value)} required /> {errors.user_id && <span className="error">{errors.user_id}</span>} </div> <div> <input type="password" placeholder="비밀번호 (8자 이상)" value={formData.user_pw} onChange={(e) => handleChange('user_pw', e.target.value)} required /> {errors.user_pw && <span className="error">{errors.user_pw}</span>} </div> <div> <input type="text" placeholder="이름" value={formData.name} onChange={(e) => handleChange('name', e.target.value)} required /> {errors.name && <span className="error">{errors.name}</span>} </div> <div> <input type="tel" placeholder="전화번호 (010-1234-5678)" value={formData.phone} onChange={(e) => handleChange('phone', e.target.value)} required /> {errors.phone && <span className="error">{errors.phone}</span>} </div> {errors.general && <div className="error">{errors.general}</div>} <button type="submit" disabled={loading}> {loading ? '가입 중...' : '회원가입'} </button> </form> ); }; ``` ## 3. Vanilla JavaScript 구현 ### 핵심 회원가입 기능 ```javascript class SignupManager { constructor(projectId) { this.projectId = projectId; this.loading = false; } validateForm(formData) { const errors = {}; if (!formData.user_id || formData.user_id.length < 4) { errors.user_id = '사용자 ID는 4자 이상이어야 합니다'; } if (!formData.user_pw || formData.user_pw.length < 8) { errors.user_pw = '비밀번호는 8자 이상이어야 합니다'; } if (!formData.name || !formData.name.trim()) { errors.name = '이름을 입력해주세요'; } if (!formData.phone || !/^010-\d{4}-\d{4}$/.test(formData.phone)) { errors.phone = '올바른 전화번호 형식이 아닙니다 (010-1234-5678)'; } return { isValid: Object.keys(errors).length === 0, errors }; } async signup(formData) { if (this.loading) return; const validation = this.validateForm(formData); if (!validation.isValid) { this.onValidationError(validation.errors); return; } this.loading = true; try { const response = await fetch('https://api.aiapp.link/account/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ ...formData, project_id: this.projectId }) }); const result = await response.json(); if (result.result === 'SUCCESS') { this.onSignupSuccess(result.data); return result.data; } else { throw new Error(result.message || '회원가입 실패'); } } catch (error) { this.onSignupError(error); throw error; } finally { this.loading = false; } } onSignupSuccess(data) { console.log('회원가입 성공:', data); alert('회원가입이 완료되었습니다!'); window.location.href = '/login'; } onSignupError(error) { console.error('회원가입 실패:', error); alert(error.message); } onValidationError(errors) { console.log('유효성 검사 실패:', errors); // 에러 메시지 표시 Object.keys(errors).forEach(field => { const errorElement = document.getElementById(`${field}_error`); if (errorElement) { errorElement.textContent = errors[field]; errorElement.style.display = 'block'; } }); } } // 사용 예시 const signupManager = new SignupManager('[PROJECT_ID]'); document.getElementById('signupForm').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const signupData = { user_id: formData.get('user_id'), user_pw: formData.get('user_pw'), name: formData.get('name'), phone: formData.get('phone'), is_reserved: formData.get('is_reserved') === 'on' }; try { await signupManager.signup(signupData); } catch (error) { // 에러는 이미 처리됨 } }); ``` ## 4. 유효성 검사 규칙 ### 클라이언트 검증 - **user_id**: 4-20자, 영문/숫자만 허용 - **user_pw**: 8자 이상 - **name**: 필수 입력, 공백 불가 - **phone**: 010-1234-5678 형식 - **is_reserved**: boolean 값 (선택사항, 기본값: false) ### 서버 검증 모든 클라이언트 검증 + 추가 검증: - 중복 사용자 ID 확인 - project_id 유효성 확인 - 데이터베이스 제약사항 검증 ## 5. 자동 적용 보안 설정 이 API는 다음 보안 설정이 자동으로 적용됩니다: - ✅ **입력값 검증**: SQL Injection, XSS 방지 - ✅ **비밀번호 해싱**: 평문 저장 금지 - ✅ **프로젝트 격리**: project_id 기반 멀티테넌트 - ✅ **중복 방지**: 사용자 ID 유일성 보장 상세 보안 설정: [보안 가이드](../common/security.md) ## 6. 에러 처리 ### 주요 에러 코드 | 에러 코드 | 설명 | 처리 방법 | |-----------|------|-----------| | `USER_EXISTS` | 중복된 사용자 ID | 다른 ID 사용 안내 | | `VALIDATION_ERROR` | 입력값 유효성 오류 | 필드별 상세 오류 표시 | | `PROJECT_NOT_FOUND` | 잘못된 Project ID | Project ID 확인 | ### 에러 처리 전략 1. **필드별 오류 표시**: 각 입력 필드에 해당하는 오류 메시지 표시 2. **실시간 검증**: 사용자가 입력하는 동안 유효성 검사 3. **사용자 친화적 메시지**: 기술적 오류를 이해하기 쉬운 언어로 변환 ## 7. 관련 문서 ### 구현 시 필수 참조 문서 다음 문서들을 함께 참조하여 보안과 상태 관리를 올바르게 구현하세요: - [상태 관리 가이드](../common/state-management.md) - 회원가입 후 로그인 상태 전환, 조건부 렌더링 - [보안 가이드](../common/security.md) - HttpOnly 쿠키, CORS, XSS/CSRF 방지, 입력값 검증 - [에러 처리 가이드](../common/errors.md) - ServiceException 처리 패턴, 유효성 검사 오류 ### 관련 API 구현 문서 - [로그인 구현 가이드](./login.md) - [사용자 정보 조회 가이드](./user-info.md) - [로그아웃 구현 가이드](./logout.md)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mbaas-inc/BaaS-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server