에러 메시지 통일 및 UX 개선
parent
8a60d69467
commit
bf5fc05a25
|
|
@ -1 +0,0 @@
|
|||
google-site-verification: google60b514c02fd6af4e.html
|
||||
|
|
@ -1 +0,0 @@
|
|||
naver-site-verification: naver33dfe258205b0af1416aa0ac18c8c0b3.html
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>개인정보처리방침 - ADO2</title>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.8; color: #333; max-width: 800px; margin: 0 auto; padding: 40px 20px; }
|
||||
h1 { font-size: 28px; border-bottom: 2px solid #eee; padding-bottom: 12px; margin-bottom: 30px; }
|
||||
h2 { font-size: 19px; margin-top: 40px; color: #111; }
|
||||
p, li { font-size: 15px; color: #555; margin-bottom: 10px; }
|
||||
ul { padding-left: 20px; }
|
||||
.google-policy { background: #f0f7ff; border-left: 4px solid #4285f4; padding: 16px 20px; margin: 24px 0; border-radius: 4px; }
|
||||
.google-policy p { color: #1a1a2e; margin: 0; }
|
||||
.updated { color: #888; font-size: 14px; margin-bottom: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>개인정보처리방침 (Privacy Policy)</h1>
|
||||
<p class="updated"><strong>시행일:</strong> 2026년 5월 7일 | <strong>최종 수정일:</strong> 2026년 5월 7일</p>
|
||||
|
||||
<p>㈜에이아이오투오(이하 "회사")는 AI 마케팅 자동화 서비스 ADO2(이하 "서비스")를 제공함에 있어 사용자의 개인정보를 중요시하며, 「개인정보 보호법」 등 관련 법령을 성실히 준수합니다.</p>
|
||||
|
||||
<h2>1. 수집하는 개인정보 항목 및 수집 방법</h2>
|
||||
<p>회사는 서비스 제공을 위해 아래와 같은 개인정보를 수집합니다.</p>
|
||||
<ul>
|
||||
<li><strong>Google OAuth를 통한 수집:</strong> 이름, 이메일 주소, 프로필 사진</li>
|
||||
<li><strong>마케팅 자동화 서비스 제공용 (해당 권한 동의 시):</strong> YouTube 채널 데이터, Google 광고 계정 데이터 등 연동된 마케팅 채널 데이터</li>
|
||||
<li><strong>서비스 이용 과정에서 자동 수집:</strong> 접속 IP, 쿠키, 서비스 이용 기록</li>
|
||||
</ul>
|
||||
|
||||
<h2>2. 개인정보의 수집 및 이용 목적</h2>
|
||||
<ul>
|
||||
<li>AI 마케팅 콘텐츠 자동 생성 및 배포 서비스 제공</li>
|
||||
<li>계정 연동 및 사용자 식별·본인 인증</li>
|
||||
<li>서비스 품질 개선 및 통계 분석</li>
|
||||
<li>공지사항 전달 및 고객 상담</li>
|
||||
</ul>
|
||||
|
||||
<div class="google-policy">
|
||||
<p><strong>[Google API 서비스 사용자 데이터 정책 준수]</strong><br><br>
|
||||
㈜에이아이오투오가 운영하는 ADO2 서비스가 Google API로부터 수신한 정보의 사용 및 타 앱으로의 전송은,
|
||||
<a href="https://developers.google.com/terms/api-services-user-data-policy" target="_blank">Google API 서비스 사용자 데이터 정책</a>의
|
||||
제한적 사용(Limited Use) 요건을 포함한 모든 정책을 엄격히 준수합니다.</p>
|
||||
</div>
|
||||
|
||||
<h2>3. 개인정보의 보유 및 이용 기간</h2>
|
||||
<p>원칙적으로 회원 탈퇴 또는 개인정보 수집·이용 목적이 달성된 후에는 해당 정보를 지체 없이 파기합니다. 단, 관련 법령에 따라 보존이 필요한 경우 해당 기간 동안 보관합니다.</p>
|
||||
<ul>
|
||||
<li>전자상거래 관련 기록: 5년 (전자상거래 등에서의 소비자보호에 관한 법률)</li>
|
||||
<li>접속 로그 기록: 3개월 (통신비밀보호법)</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. 개인정보의 제3자 제공</h2>
|
||||
<p>회사는 사용자의 사전 동의 없이 개인정보를 외부에 제공하지 않습니다. 다만, 법령에 의거한 수사기관 등의 적법한 요청이 있는 경우는 예외로 합니다.</p>
|
||||
|
||||
<h2>5. 정보주체의 권리 및 행사 방법</h2>
|
||||
<p>사용자는 언제든지 자신의 개인정보에 대한 열람, 수정, 삭제, 처리 정지를 요청할 수 있습니다. 서비스 내 계정 설정에서 직접 처리하거나 아래 문의처로 연락해 주시기 바랍니다.</p>
|
||||
|
||||
<h2>6. 개인정보 보호책임자 및 문의처</h2>
|
||||
<p>개인정보 보호와 관련된 불만 처리 및 피해 구제에 관한 사항은 아래로 문의해 주시기 바랍니다.</p>
|
||||
<ul>
|
||||
<li><strong>회사명:</strong> ㈜에이아이오투오</li>
|
||||
<li><strong>서비스명:</strong> ADO2</li>
|
||||
<li><strong>이메일:</strong> o2oteam@o2o.kr</li>
|
||||
<li><strong>웹사이트:</strong> https://demo.castad.net</li>
|
||||
</ul>
|
||||
|
||||
<p style="margin-top:40px; font-size:14px; color:#999;">본 방침은 2026년 5월 7일부터 시행됩니다.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>서비스 약관 - ADO2</title>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.8; color: #333; max-width: 800px; margin: 0 auto; padding: 40px 20px; }
|
||||
h1 { font-size: 28px; border-bottom: 2px solid #eee; padding-bottom: 12px; margin-bottom: 30px; }
|
||||
h2 { font-size: 19px; margin-top: 40px; color: #111; }
|
||||
p, li { font-size: 15px; color: #555; margin-bottom: 10px; }
|
||||
ul { padding-left: 20px; }
|
||||
.updated { color: #888; font-size: 14px; margin-bottom: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>서비스 이용약관 (Terms of Service)</h1>
|
||||
<p class="updated"><strong>시행일:</strong> 2026년 5월 7일 | <strong>최종 수정일:</strong> 2026년 5월 7일</p>
|
||||
|
||||
<h2>제 1 조 (목적)</h2>
|
||||
<p>본 약관은 ㈜에이아이오투오(이하 "회사")가 제공하는 AI 마케팅 자동화 서비스 ADO2(이하 "서비스")의 이용과 관련하여, 회사와 이용자(이하 "회원") 간의 권리, 의무 및 책임사항을 규정함을 목적으로 합니다.</p>
|
||||
|
||||
<h2>제 2 조 (용어의 정의)</h2>
|
||||
<ul>
|
||||
<li>"서비스"라 함은 회사가 제공하는 ADO2 AI 마케팅 자동화 플랫폼 및 관련 제반 기능을 의미합니다.</li>
|
||||
<li>"회원"이라 함은 본 약관에 동의하고 회사와 이용계약을 체결하여 서비스를 이용하는 자를 말합니다.</li>
|
||||
<li>"콘텐츠"라 함은 서비스 내에서 AI가 생성하거나 회원이 등록하는 텍스트, 이미지, 음악, 영상 등 일체의 자료를 말합니다.</li>
|
||||
</ul>
|
||||
|
||||
<h2>제 3 조 (약관의 효력 및 변경)</h2>
|
||||
<p>회사는 본 약관의 내용을 서비스 화면에 게시하며, 관련 법령을 위배하지 않는 범위에서 약관을 개정할 수 있습니다. 약관이 변경되는 경우 시행일 7일 전부터 공지합니다.</p>
|
||||
|
||||
<h2>제 4 조 (서비스의 제공 및 변경)</h2>
|
||||
<p>회사는 AI 기반 마케팅 콘텐츠(가사, 이미지, 영상 등) 자동 생성, Google·YouTube 등 외부 플랫폼 연동, SNS 자동 배포 등의 서비스를 제공합니다. 운영상·기술상의 필요에 따라 서비스의 전부 또는 일부를 변경할 수 있습니다.</p>
|
||||
|
||||
<h2>제 5 조 (회원의 의무)</h2>
|
||||
<ul>
|
||||
<li>타인의 Google 계정 등 외부 서비스 계정을 무단으로 도용하여 서비스를 이용해서는 안 됩니다.</li>
|
||||
<li>스팸 발송, API 한도 고의 초과, 허위 정보 등록 등 비정상적인 방법으로 서비스를 이용해서는 안 됩니다.</li>
|
||||
<li>회사 또는 제3자의 지식재산권을 침해해서는 안 됩니다.</li>
|
||||
</ul>
|
||||
|
||||
<h2>제 6 조 (외부 API 연동 및 데이터 활용)</h2>
|
||||
<p>서비스는 Google, YouTube, Naver 등의 제3자 API를 활용하여 마케팅 자동화 기능을 제공합니다. 회원은 각 외부 서비스의 이용약관 및 정책을 준수할 의무가 있으며, 외부 API 제공사의 정책 변경으로 인한 서비스 제한에 대해 회사는 면책됩니다.</p>
|
||||
|
||||
<h2>제 7 조 (AI 생성 콘텐츠의 권리)</h2>
|
||||
<p>서비스 내에서 AI가 생성한 콘텐츠에 대한 권리 관계는 관련 법령 및 회사의 별도 정책에 따릅니다. 회원이 직접 입력한 정보(매장 URL, 상호명 등)를 기반으로 생성된 콘텐츠에 대한 책임은 회원에게 있습니다.</p>
|
||||
|
||||
<h2>제 8 조 (책임 제한)</h2>
|
||||
<p>회사는 천재지변, 외부 플랫폼(Google, YouTube, Naver 등)의 장애, 통신 장애 등 불가항력으로 서비스를 제공할 수 없는 경우 책임이 면제됩니다.</p>
|
||||
|
||||
<h2>제 9 조 (준거법 및 재판관할)</h2>
|
||||
<p>본 약관과 관련된 분쟁은 대한민국 법을 준거법으로 하며, 소송은 회사의 소재지를 관할하는 법원에 제소합니다.</p>
|
||||
|
||||
<h2>문의처</h2>
|
||||
<ul>
|
||||
<li><strong>회사명:</strong> ㈜에이아이오투오</li>
|
||||
<li><strong>서비스명:</strong> ADO2</li>
|
||||
<li><strong>이메일:</strong> o2oteam@o2o.kr</li>
|
||||
<li><strong>웹사이트:</strong> https://demo.castad.net</li>
|
||||
</ul>
|
||||
|
||||
<p style="margin-top:40px; font-size:14px; color:#999;">본 약관은 2026년 5월 7일부터 시행됩니다.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -275,8 +275,7 @@ const App: React.FC = () => {
|
|||
setIsAnalysisComplete(true);
|
||||
} catch (err) {
|
||||
console.error('Crawling failed:', err);
|
||||
const errorMessage = err instanceof Error ? err.message : t('app.analysisError');
|
||||
setError(errorMessage);
|
||||
setError(t('app.analysisError'));
|
||||
setViewMode('landing');
|
||||
}
|
||||
};
|
||||
|
|
@ -301,9 +300,7 @@ const App: React.FC = () => {
|
|||
setIsAnalysisComplete(true);
|
||||
} catch (err) {
|
||||
console.error('Autocomplete failed:', err);
|
||||
const is404 = err instanceof Error && err.message.includes('status: 404');
|
||||
const errorMessage = is404 ? t('app.autocompleteError') : (err instanceof Error ? err.message : t('app.autocompleteGeneralError'));
|
||||
setError(errorMessage);
|
||||
setError(t('app.autocompleteError'));
|
||||
setViewMode('landing');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -550,8 +550,8 @@
|
|||
"kakaoLoginFailed": "Kakao login failed. Please try again.",
|
||||
"loginUrlFailed": "Failed to get login URL. Please try again.",
|
||||
"invalidUrl": "Invalid URL. Please enter a Naver Map URL.",
|
||||
"analysisError": "An error occurred during analysis. Please try again.",
|
||||
"autocompleteError": "Failed to retrieve business information. Please enter the URL directly.",
|
||||
"analysisError": "No results found. Please check your input and try again.",
|
||||
"autocompleteError": "No results found. Please check your input and try again.",
|
||||
"autocompleteGeneralError": "An error occurred while retrieving business information. Please try again.",
|
||||
"pageComingSoon": "{{page}} page is coming soon."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,8 +550,8 @@
|
|||
"kakaoLoginFailed": "카카오 로그인에 실패했습니다. 다시 시도해주세요.",
|
||||
"loginUrlFailed": "로그인 URL을 가져오는데 실패했습니다. 다시 시도해주세요.",
|
||||
"invalidUrl": "유효하지 않은 URL입니다. 네이버 지도 URL을 입력해주세요.",
|
||||
"analysisError": "분석 중 오류가 발생했습니다. 다시 시도해주세요.",
|
||||
"autocompleteError": "업체 정보 조회에 실패했습니다. URL을 직접 입력해주세요.",
|
||||
"analysisError": "검색 정보를 찾을 수 없습니다. 입력 정보를 다시 확인해주세요.",
|
||||
"autocompleteError": "검색 정보를 찾을 수 없습니다. 입력 정보를 다시 확인해주세요.",
|
||||
"autocompleteGeneralError": "업체 정보 조회 중 오류가 발생했습니다. 다시 시도해주세요.",
|
||||
"pageComingSoon": "{{page}} 페이지 준비 중입니다."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ const CompletionContent: React.FC<CompletionContentProps> = ({
|
|||
|
||||
const handleCloseSocialConnect = () => {
|
||||
setShowSocialModal(false);
|
||||
onVideoComplete?.();
|
||||
};
|
||||
|
||||
const handleRetry = () => {
|
||||
|
|
@ -484,13 +485,13 @@ const CompletionContent: React.FC<CompletionContentProps> = ({
|
|||
<div className="comp2-lyrics-section">
|
||||
<span className="comp2-meta-label">{t('completion.lyrics')}</span>
|
||||
{(() => {
|
||||
const lyricsText = songCompletionData
|
||||
? (songCompletionData.lyrics || '')
|
||||
: t('completion.sampleLyrics');
|
||||
if (!songCompletionData?.lyrics) {
|
||||
return <p className="comp2-lyrics-text">{lyricsText}</p>;
|
||||
if (!songCompletionData) {
|
||||
return <p className="comp2-lyrics-text">{t('completion.sampleLyrics')}</p>;
|
||||
}
|
||||
const lines = lyricsText.split('\n').filter((l: string) => l.trim());
|
||||
if (!songCompletionData.lyrics) {
|
||||
return <p className="comp2-lyrics-text">{t('completion.noLyricsBGM')}</p>;
|
||||
}
|
||||
const lines = songCompletionData.lyrics.split('\n').filter((l: string) => l.trim());
|
||||
const size = Math.ceil(lines.length / 3);
|
||||
const sections = [
|
||||
{ tag: '[Verse]', lines: lines.slice(0, size) },
|
||||
|
|
|
|||
|
|
@ -130,6 +130,13 @@ const GenerationFlow: React.FC<GenerationFlowProps> = ({
|
|||
}
|
||||
}, []);
|
||||
|
||||
// 사운드 스튜디오, 영상 완성 진입 시 크레딧 갱신
|
||||
useEffect(() => {
|
||||
if (wizardStep === 2 || wizardStep === 3) {
|
||||
refreshCredits();
|
||||
}
|
||||
}, [wizardStep]);
|
||||
|
||||
// 로그인 직후 사용자 정보 + 크레딧 조회
|
||||
useEffect(() => {
|
||||
const fetchUserInfo = async () => {
|
||||
|
|
@ -248,8 +255,7 @@ const GenerationFlow: React.FC<GenerationFlowProps> = ({
|
|||
setIsAnalysisComplete(true);
|
||||
} catch (err) {
|
||||
console.error('Autocomplete error:', err);
|
||||
const msg = err instanceof Error ? err.message : '';
|
||||
setAnalysisError(/^HTTP error!/.test(msg) ? t('app.autocompleteError') : (msg || t('app.autocompleteError')));
|
||||
setAnalysisError(t('app.autocompleteError'));
|
||||
goToWizardStep(-2); // URL 입력으로 돌아가기
|
||||
}
|
||||
};
|
||||
|
|
@ -318,8 +324,7 @@ const GenerationFlow: React.FC<GenerationFlowProps> = ({
|
|||
setIsAnalysisComplete(true);
|
||||
} catch (err) {
|
||||
console.error('Crawling failed:', err);
|
||||
const errorMessage = err instanceof Error ? err.message : t('app.analysisError');
|
||||
setAnalysisError(errorMessage);
|
||||
setAnalysisError(t('app.analysisError'));
|
||||
goToWizardStep(-2); // URL 입력으로 돌아가기
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -160,14 +160,16 @@ const UrlInputContent: React.FC<UrlInputContentProps> = ({ onAnalyze, onAutocomp
|
|||
const handleAnalyzeClick = () => {
|
||||
if (!inputValue.trim()) return;
|
||||
|
||||
if (searchType === 'name' && selectedItem && onAutocomplete) {
|
||||
// 업체명 검색인 경우 autocomplete API 호출
|
||||
const request: AutocompleteRequest = {
|
||||
address: selectedItem.address,
|
||||
roadAddress: selectedItem.roadAddress,
|
||||
title: selectedItem.title,
|
||||
};
|
||||
onAutocomplete(request);
|
||||
if (searchType === 'name') {
|
||||
if (selectedItem && onAutocomplete) {
|
||||
const request: AutocompleteRequest = {
|
||||
address: selectedItem.address,
|
||||
roadAddress: selectedItem.roadAddress,
|
||||
title: selectedItem.title,
|
||||
};
|
||||
onAutocomplete(request);
|
||||
}
|
||||
// selectedItem 없으면 아무것도 하지 않음 (드롭다운에서 선택 필요)
|
||||
} else {
|
||||
// URL 검색인 경우 기존 로직
|
||||
onAnalyze(inputValue.trim(), searchType);
|
||||
|
|
|
|||
Loading…
Reference in New Issue