feat: 뷰성형외과 미팅 대비 — 데이터 갱신(2026-04-28) + URL 7분할 + 가격 개편
- mockReport.ts (view-clinic): 8채널 실측 갱신 · YouTube · 강남언니 · 네이버 플레이스 · 네이버 블로그 → Firecrawl · Instagram (KR · EN) · Facebook (KR · EN) → Apify · createdAt 2026-04-13 → 2026-04-28 - mockPlan.ts (view-clinic): KPI 베이스라인 동기화 + scheduledDate 5월로 이동 - MultiChannelInput: 단일 textarea → 7-필드 분할 (홈페이지 · YT · IG · FB · 네이버플레이스 · 블로그 · 강남언니), 채널별 실시간 검증 아이콘 - PricingPage / FeatureComparisonTable: 49만/149만/399만 → 9만/29만/99만, 월 리포트 수 1회/4회/10회, 경쟁사 추적 1/3/5 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>main
parent
938ebacbf9
commit
dc8a1db3f2
|
|
@ -1,21 +1,22 @@
|
||||||
/**
|
/**
|
||||||
* MultiChannelInput — 랜딩 Hero / CTA 공용 멀티 URL 입력 컴포넌트.
|
* MultiChannelInput — 랜딩 Hero / CTA 공용 멀티 URL 입력 컴포넌트.
|
||||||
*
|
*
|
||||||
* 설계 배경 (PART III 피봇):
|
* 설계 배경 (PART III 피봇 + 2026-04 입력 분할 개편):
|
||||||
* - 기존 Hero/CTA의 단일 URL input은 "홈페이지 URL → 자동 SNS 발견"을 전제로 했지만,
|
* - 영업 현장에서는 병원이 본인들의 YouTube/Instagram/FB/네이버플레이스/블로그/강남언니 URL을
|
||||||
* 영업 현장에서는 병원이 본인들의 YouTube/Instagram/FB/네이버플레이스/블로그/강남언니 URL을
|
|
||||||
* 이미 알고 있는 경우가 많아 이를 직접 받는 편이 정확도·속도 면에서 우월합니다.
|
* 이미 알고 있는 경우가 많아 이를 직접 받는 편이 정확도·속도 면에서 우월합니다.
|
||||||
* - Hero와 CTA가 동일한 입력 로직(url state + handleAnalyze + navigate)을 **중복 구현**하던
|
* - 단일 textarea + 자동 분류 방식은 사용자가 "어떻게 입력해야 하는지" 직관이 없어
|
||||||
* 문제를 이 컴포넌트 하나로 해소합니다.
|
* 공란이 되거나 잘못된 URL이 섞이는 경우가 많았습니다.
|
||||||
|
* - 따라서 채널별로 7개 필드를 명시적으로 노출 — 빈 칸을 보면 "여기에 무엇을 넣어야 하는지"가 명확합니다.
|
||||||
*
|
*
|
||||||
* 동작:
|
* 동작:
|
||||||
* 1) Textarea에 URL을 공백/쉼표/줄바꿈으로 구분해 붙여넣기
|
* 1) 7개 필드 각각에 URL 입력 (한 줄에 하나)
|
||||||
* 2) `classifyUrls()`로 실시간 7채널 분류 (`useMemo`)
|
* 2) 입력 시 `classifyUrls()`로 검증 — 해당 채널 패턴과 매치되는지 실시간 확인
|
||||||
* 3) 채널별 칩 프리뷰 — 검출 건수 표시, unknown URL은 경고
|
* 3) 매치 성공: 우측에 체크 아이콘, 실패: 경고 아이콘
|
||||||
* 4) "채널 분석 시작" 버튼 클릭 → onAnalyze(payload) 호출 (부모가 navigation 처리)
|
* 4) 1개 이상 유효 입력 시 Analyze 버튼 활성화
|
||||||
|
* 5) Submit 시 onAnalyze(payload) 호출 (부모가 navigation 처리)
|
||||||
*
|
*
|
||||||
* DS 준수:
|
* DS 준수:
|
||||||
* - Filled Icons Only (lucide 무단 사용 금지 — 이모지·outlined 금지)
|
* - Filled Icons Only (lucide 무단 사용 금지)
|
||||||
* - DS Primary pill: rounded-full + gradient `from-[#4F1DA1] to-[#021341]`
|
* - DS Primary pill: rounded-full + gradient `from-[#4F1DA1] to-[#021341]`
|
||||||
* - variant='hero': 글래스 배경 (랜딩 Hero)
|
* - variant='hero': 글래스 배경 (랜딩 Hero)
|
||||||
* - variant='cta': 다크 배경 (CTA 섹션)
|
* - variant='cta': 다크 배경 (CTA 섹션)
|
||||||
|
|
@ -31,6 +32,7 @@ import {
|
||||||
DatabaseFilled,
|
DatabaseFilled,
|
||||||
FileTextFilled,
|
FileTextFilled,
|
||||||
MessageFilled,
|
MessageFilled,
|
||||||
|
CheckFilled,
|
||||||
WarningFilled,
|
WarningFilled,
|
||||||
} from './icons/FilledIcons';
|
} from './icons/FilledIcons';
|
||||||
import {
|
import {
|
||||||
|
|
@ -64,137 +66,137 @@ interface MultiChannelInputProps {
|
||||||
onAnalyze: (payload: AnalyzePayload) => void;
|
onAnalyze: (payload: AnalyzePayload) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 채널 칩 메타 — 렌더링 순서·아이콘·한글명. */
|
type ChannelKey = keyof Omit<ClassifiedUrls, 'unknown'>;
|
||||||
|
|
||||||
|
/** 채널별 메타 — 라벨/아이콘/색상/플레이스홀더 (뷰성형외과 실 URL을 데모 placeholder로). */
|
||||||
const CHANNEL_META: Array<{
|
const CHANNEL_META: Array<{
|
||||||
key: keyof Omit<ClassifiedUrls, 'unknown'>;
|
key: ChannelKey;
|
||||||
label: string;
|
label: string;
|
||||||
Icon: (props: { size?: number; className?: string }) => ReactElement;
|
Icon: (props: { size?: number; className?: string }) => ReactElement;
|
||||||
color: string; // 활성화 시 텍스트/아이콘 색
|
color: string;
|
||||||
|
placeholder: string;
|
||||||
}> = [
|
}> = [
|
||||||
{ key: 'homepage', label: '홈페이지', Icon: GlobeFilled, color: 'text-[#4F1DA1]' },
|
{ key: 'homepage', label: '홈페이지', Icon: GlobeFilled, color: 'text-[#4F1DA1]', placeholder: 'viewclinic.com' },
|
||||||
{ key: 'youtube', label: 'YouTube', Icon: YoutubeFilled, color: 'text-[#FF0000]' },
|
{ key: 'youtube', label: 'YouTube', Icon: YoutubeFilled, color: 'text-[#FF0000]', placeholder: 'youtube.com/@ViewclinicKR' },
|
||||||
{ key: 'instagram', label: 'Instagram', Icon: InstagramFilled,color: 'text-[#E1306C]' },
|
{ key: 'instagram', label: 'Instagram', Icon: InstagramFilled,color: 'text-[#E1306C]', placeholder: 'instagram.com/viewplastic' },
|
||||||
{ key: 'facebook', label: 'Facebook', Icon: FacebookFilled, color: 'text-[#1877F2]' },
|
{ key: 'facebook', label: 'Facebook', Icon: FacebookFilled, color: 'text-[#1877F2]', placeholder: 'facebook.com/viewps1' },
|
||||||
{ key: 'naverPlace', label: '네이버 플레이스', Icon: DatabaseFilled, color: 'text-[#03C75A]' },
|
{ key: 'naverPlace', label: '네이버 플레이스', Icon: DatabaseFilled, color: 'text-[#03C75A]', placeholder: 'place.naver.com/hospital/11709005' },
|
||||||
{ key: 'naverBlog', label: '네이버 블로그', Icon: FileTextFilled, color: 'text-[#03C75A]' },
|
{ key: 'naverBlog', label: '네이버 블로그', Icon: FileTextFilled, color: 'text-[#03C75A]', placeholder: 'blog.naver.com/viewclinicps' },
|
||||||
{ key: 'gangnamUnni', label: '강남언니', Icon: MessageFilled, color: 'text-[#FF5C89]' },
|
{ key: 'gangnamUnni', label: '강남언니', Icon: MessageFilled, color: 'text-[#FF5C89]', placeholder: 'gangnamunni.com/hospitals/189' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
type EmptyClassified = Record<ChannelKey, string>;
|
||||||
|
|
||||||
|
const EMPTY_URLS: EmptyClassified = {
|
||||||
|
homepage: '', youtube: '', instagram: '', facebook: '',
|
||||||
|
naverPlace: '', naverBlog: '', gangnamUnni: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 단일 입력값 검증 — 해당 채널 패턴과 매치되는지.
|
||||||
|
* 빈 값: 'empty', 매치 성공: 'valid', SNS인데 다른 채널: 'wrong', 파싱 실패: 'invalid'
|
||||||
|
*/
|
||||||
|
function validateField(value: string, expected: ChannelKey): 'empty' | 'valid' | 'wrong' | 'invalid' {
|
||||||
|
if (!value.trim()) return 'empty';
|
||||||
|
const c = classifyUrls(value);
|
||||||
|
if (c[expected].length > 0) return 'valid';
|
||||||
|
// 다른 채널로 분류됐으면 'wrong', unknown이면 'invalid'
|
||||||
|
for (const k of Object.keys(c) as Array<keyof ClassifiedUrls>) {
|
||||||
|
if (k !== 'unknown' && k !== expected && c[k].length > 0) return 'wrong';
|
||||||
|
}
|
||||||
|
return 'invalid';
|
||||||
|
}
|
||||||
|
|
||||||
export default function MultiChannelInput({ variant = 'hero', onAnalyze }: MultiChannelInputProps) {
|
export default function MultiChannelInput({ variant = 'hero', onAnalyze }: MultiChannelInputProps) {
|
||||||
const [text, setText] = useState('');
|
const [urls, setUrls] = useState<EmptyClassified>(EMPTY_URLS);
|
||||||
|
|
||||||
// 실시간 분류 — text가 바뀔 때만 재계산.
|
// 통합 분류 결과 — 7개 필드 값을 join해 classifyUrls에 한 번에 통과시켜 manualChannels 구성.
|
||||||
const classified = useMemo(() => classifyUrls(text), [text]);
|
const aggregated = useMemo(() => {
|
||||||
|
const joined = Object.values(urls).filter(Boolean).join('\n');
|
||||||
|
return classifyUrls(joined);
|
||||||
|
}, [urls]);
|
||||||
|
|
||||||
const canAnalyze = hasAnalyzableChannels(classified);
|
const canAnalyze = hasAnalyzableChannels(aggregated);
|
||||||
const primaryUrl = pickPrimaryUrl(classified);
|
const primaryUrl = pickPrimaryUrl(aggregated);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!canAnalyze || !primaryUrl) return;
|
if (!canAnalyze || !primaryUrl) return;
|
||||||
const payload: AnalyzePayload = {
|
const payload: AnalyzePayload = {
|
||||||
primaryUrl,
|
primaryUrl,
|
||||||
manualChannels: {
|
manualChannels: {
|
||||||
// homepage는 primaryUrl로 들어가므로 manualChannels에서는 제외 (Edge Function에서 `url`을 쓰므로)
|
youtube: aggregated.youtube.length ? aggregated.youtube : undefined,
|
||||||
youtube: classified.youtube.length ? classified.youtube : undefined,
|
instagram: aggregated.instagram.length ? aggregated.instagram : undefined,
|
||||||
instagram: classified.instagram.length ? classified.instagram : undefined,
|
facebook: aggregated.facebook.length ? aggregated.facebook : undefined,
|
||||||
facebook: classified.facebook.length ? classified.facebook : undefined,
|
naverPlace: aggregated.naverPlace.length ? aggregated.naverPlace : undefined,
|
||||||
naverPlace: classified.naverPlace.length ? classified.naverPlace : undefined,
|
naverBlog: aggregated.naverBlog.length ? aggregated.naverBlog : undefined,
|
||||||
naverBlog: classified.naverBlog.length ? classified.naverBlog : undefined,
|
gangnamUnni: aggregated.gangnamUnni.length ? aggregated.gangnamUnni : undefined,
|
||||||
gangnamUnni: classified.gangnamUnni.length ? classified.gangnamUnni : undefined,
|
|
||||||
},
|
},
|
||||||
rawInput: text,
|
rawInput: Object.entries(urls)
|
||||||
|
.filter(([, v]) => v.trim())
|
||||||
|
.map(([k, v]) => `${k}: ${v}`)
|
||||||
|
.join('\n'),
|
||||||
};
|
};
|
||||||
onAnalyze(payload);
|
onAnalyze(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
// variant별 스타일 토큰
|
// variant별 스타일 토큰
|
||||||
// ▸ `text-center` 추가 (원본 Hero 단일 URL input과 일관): Form 필드가 아닌
|
|
||||||
// "검색창 같은 자유 입력" 시그널로 전환. placeholder 여러 줄도 중앙 정렬.
|
|
||||||
const isHero = variant === 'hero';
|
const isHero = variant === 'hero';
|
||||||
const textareaClass = isHero
|
const inputClass = isHero
|
||||||
? 'w-full px-6 py-4 text-sm md:text-base text-center bg-white/80 backdrop-blur-sm border border-slate-200 rounded-2xl focus:outline-none focus:ring-2 focus:ring-accent/20 focus:border-accent/40 shadow-sm text-primary-900 placeholder:text-slate-400 transition-all resize-none leading-relaxed'
|
? 'w-full pl-11 pr-10 py-2.5 text-sm bg-white/80 backdrop-blur-sm border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/20 focus:border-accent/40 shadow-sm text-primary-900 placeholder:text-slate-400 transition-all'
|
||||||
: 'w-full px-6 py-4 text-sm md:text-base text-center bg-white/5 backdrop-blur-sm border border-white/15 rounded-2xl focus:outline-none focus:ring-2 focus:ring-accent/30 focus:border-accent/60 text-white placeholder:text-white/40 transition-all resize-none leading-relaxed';
|
: 'w-full pl-11 pr-10 py-2.5 text-sm bg-white/5 backdrop-blur-sm border border-white/15 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/30 focus:border-accent/60 text-white placeholder:text-white/40 transition-all';
|
||||||
|
|
||||||
|
const labelClass = isHero ? 'text-slate-600' : 'text-white/70';
|
||||||
const helperClass = isHero ? 'text-slate-500' : 'text-white/60';
|
const helperClass = isHero ? 'text-slate-500' : 'text-white/60';
|
||||||
const chipInactiveBg = isHero ? 'bg-slate-50 border-slate-100' : 'bg-white/5 border-white/10';
|
|
||||||
const chipInactiveText = isHero ? 'text-slate-400' : 'text-white/40';
|
|
||||||
const chipActiveBg = isHero ? 'bg-white border-slate-200 shadow-sm' : 'bg-white/10 border-white/25';
|
|
||||||
const chipActiveText = isHero ? 'text-primary-900' : 'text-white';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-2xl mx-auto">
|
<div className="w-full max-w-2xl mx-auto">
|
||||||
{/* URL Textarea
|
{/* 7개 채널별 입력 필드 — 한 줄에 하나, 좌측 아이콘 + 우측 검증 상태 */}
|
||||||
Placeholder 카피 원칙: "한 줄씩" 같은 입력 규칙 제거.
|
<div className="flex flex-col gap-2">
|
||||||
classifyUrls.ts가 공백·쉼표·줄바꿈·임의 텍스트 섞임 모두 처리하므로
|
{CHANNEL_META.map(({ key, label, Icon, color, placeholder }) => {
|
||||||
사용자에게 입력 형식 고민을 넘기지 않고, "뭉치 → 자동 분류" 를 제품 약속으로 선언.
|
const value = urls[key];
|
||||||
정렬: `text-center` — 원본 Hero의 단일 URL input과 일관, Form 필드 인상을 줄여
|
const status = validateField(value, key);
|
||||||
"검색창 같은 자유 입력" 느낌으로 전환. */}
|
|
||||||
<textarea
|
|
||||||
value={text}
|
|
||||||
onChange={(e) => setText(e.target.value)}
|
|
||||||
placeholder={
|
|
||||||
'URL을 한 번에 붙여넣어 주세요\n홈페이지 · YouTube · Instagram · Facebook · 네이버 플레이스 · 블로그 · 강남언니를 AI가 자동으로 분류합니다'
|
|
||||||
}
|
|
||||||
rows={5}
|
|
||||||
className={textareaClass}
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 채널 칩 프리뷰 */}
|
|
||||||
<div className="flex flex-wrap gap-2 mt-4 justify-center">
|
|
||||||
{CHANNEL_META.map(({ key, label, Icon, color }) => {
|
|
||||||
const count = classified[key].length;
|
|
||||||
const isActive = count > 0;
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div key={key} className="relative">
|
||||||
key={key}
|
{/* 좌측 채널 아이콘 — 입력 시 컬러 적용, 빈 칸일 땐 회색 */}
|
||||||
className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full border text-xs font-semibold transition-all ${
|
<div className="absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none flex items-center gap-2">
|
||||||
isActive ? `${chipActiveBg} ${chipActiveText}` : `${chipInactiveBg} ${chipInactiveText}`
|
<Icon size={16} className={value ? color : isHero ? 'text-slate-400' : 'text-white/40'} />
|
||||||
}`}
|
</div>
|
||||||
>
|
{/* 채널 라벨 — 좌측 상단 작은 라벨로 placeholder 위에 노출 */}
|
||||||
<Icon size={14} className={isActive ? color : ''} />
|
<input
|
||||||
<span>{label}</span>
|
type="url"
|
||||||
{isActive && (
|
inputMode="url"
|
||||||
<span className={`ml-0.5 px-1.5 py-0.5 text-[10px] rounded-full bg-accent/10 text-accent`}>
|
value={value}
|
||||||
{count}
|
onChange={(e) => setUrls((prev) => ({ ...prev, [key]: e.target.value }))}
|
||||||
</span>
|
placeholder={`${label} · ${placeholder}`}
|
||||||
)}
|
aria-label={label}
|
||||||
|
className={inputClass}
|
||||||
|
spellCheck={false}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
{/* 우측 검증 상태 아이콘 */}
|
||||||
|
<div className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none">
|
||||||
|
{status === 'valid' && (
|
||||||
|
<CheckFilled size={16} className="text-emerald-500" />
|
||||||
|
)}
|
||||||
|
{(status === 'wrong' || status === 'invalid') && (
|
||||||
|
<WarningFilled size={16} className={isHero ? 'text-amber-500' : 'text-amber-300'} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Unknown URL 경고 */}
|
{/* 보조 안내 — 1개 이상 입력 시 어느 채널이 분석 대상인지 요약 */}
|
||||||
{classified.unknown.length > 0 && (
|
<p className={`text-xs font-medium mt-3 text-center leading-relaxed break-keep ${labelClass}`}>
|
||||||
<div
|
7개 채널 중 알고 계신 URL만 입력해주세요 — 1개만 입력하셔도 분석이 시작됩니다.
|
||||||
className={`flex items-start gap-2 mt-3 px-4 py-3 rounded-xl border ${
|
</p>
|
||||||
isHero
|
|
||||||
? 'bg-amber-50/80 border-amber-200 text-amber-800'
|
|
||||||
: 'bg-amber-500/10 border-amber-400/30 text-amber-100'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<WarningFilled size={16} className={isHero ? 'text-amber-500 shrink-0 mt-0.5' : 'text-amber-300 shrink-0 mt-0.5'} />
|
|
||||||
<div className="text-xs leading-relaxed break-keep">
|
|
||||||
<span className="font-semibold">분석 대상이 아닌 URL {classified.unknown.length}건</span>이 있어요.
|
|
||||||
(게시물·검색 페이지·미지원 플랫폼 등) — 해당 URL은 제외하고 진행합니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 분석 시작 버튼 — "Analyze" pill. 모양·크기는 원본 CTA 스펙 고정.
|
{/* 분석 시작 버튼 — DS Primary pill */}
|
||||||
▸ 모양·크기·너비: `rounded-full px-10 py-4 text-lg font-medium`, `max-w-md` (~448px) 캡
|
|
||||||
▸ 색 (variant별 분기 — 대비 + 브랜드 시그니처 통일):
|
|
||||||
- hero (라이트 배경): 다크 브랜드 `#4F1DA1 → #021341` + `text-white`,
|
|
||||||
hover 시 `#AF90FF` 라벤더 단색 — 밝기 역전
|
|
||||||
- cta (다크 `bg-primary-900` 배경): 브랜드 시그니처 3-stop warm gradient
|
|
||||||
`#fff3eb → #e4cfff → #f5f9ff` + `text-primary-900`,
|
|
||||||
이미 Hero/CTA 헤드라인 텍스트와 동일 팔레트라 섹션 내 색언어 통일.
|
|
||||||
이미 밝은 톤이라 hover 밝기 역전 불가 → `hover:scale-[1.02]` + `shadow-2xl` 로 부양 피드백.
|
|
||||||
▸ disabled: HTML `disabled` 속성만, opacity 변화 없음 (46b911d 원칙) */}
|
|
||||||
<button
|
<button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={!canAnalyze}
|
disabled={!canAnalyze}
|
||||||
className={`w-full max-w-md mx-auto mt-5 px-10 py-4 text-lg font-medium rounded-full transition-all duration-150 shadow-xl hover:shadow-2xl flex items-center justify-center gap-2 group bg-gradient-to-r active:scale-[0.98] ${
|
className={`w-full max-w-md mx-auto mt-4 px-10 py-4 text-lg font-medium rounded-full transition-all duration-150 shadow-xl hover:shadow-2xl flex items-center justify-center gap-2 group bg-gradient-to-r active:scale-[0.98] ${
|
||||||
isHero
|
isHero
|
||||||
? 'from-[#4F1DA1] to-[#021341] text-white hover:from-[#AF90FF] hover:to-[#AF90FF]'
|
? 'from-[#4F1DA1] to-[#021341] text-white hover:from-[#AF90FF] hover:to-[#AF90FF]'
|
||||||
: 'from-[#fff3eb] via-[#e4cfff] to-[#f5f9ff] text-primary-900 hover:scale-[1.02]'
|
: 'from-[#fff3eb] via-[#e4cfff] to-[#f5f9ff] text-primary-900 hover:scale-[1.02]'
|
||||||
|
|
@ -204,7 +206,7 @@ export default function MultiChannelInput({ variant = 'hero', onAnalyze }: Multi
|
||||||
<ArrowRight className="w-5 h-5 group-hover:translate-x-1" />
|
<ArrowRight className="w-5 h-5 group-hover:translate-x-1" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* 보조 안내 */}
|
{/* 보조 안내 (하단) */}
|
||||||
<p className={`text-xs font-medium mt-3 text-center leading-relaxed break-keep ${helperClass}`}>
|
<p className={`text-xs font-medium mt-3 text-center leading-relaxed break-keep ${helperClass}`}>
|
||||||
네이버 블로그 · 플레이스 · 소셜미디어 등 Online Presence 종합 분석 리포트를 제공합니다.
|
네이버 블로그 · 플레이스 · 소셜미디어 등 Online Presence 종합 분석 리포트를 제공합니다.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,8 @@ const categories: FeatureCategory[] = [
|
||||||
{
|
{
|
||||||
label: '월 리포트 수',
|
label: '월 리포트 수',
|
||||||
insight: '1회',
|
insight: '1회',
|
||||||
intelligence: '2회 + on-demand 4회',
|
intelligence: '4회',
|
||||||
intelligencePlus: '월 20회',
|
intelligencePlus: '10회',
|
||||||
hint: 'on-demand는 영업일 기준 24시간 내 재실행',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '전 채널 커버리지',
|
label: '전 채널 커버리지',
|
||||||
|
|
@ -99,7 +98,7 @@ const categories: FeatureCategory[] = [
|
||||||
label: '경쟁사 추적',
|
label: '경쟁사 추적',
|
||||||
insight: '1개',
|
insight: '1개',
|
||||||
intelligence: '3개',
|
intelligence: '3개',
|
||||||
intelligencePlus: '10개',
|
intelligencePlus: '5개',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '변동 알림',
|
label: '변동 알림',
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
reportId: 'view-clinic',
|
reportId: 'view-clinic',
|
||||||
clinicName: '뷰성형외과의원',
|
clinicName: '뷰성형외과의원',
|
||||||
clinicNameEn: 'VIEW Plastic Surgery',
|
clinicNameEn: 'VIEW Plastic Surgery',
|
||||||
createdAt: '2026-04-13',
|
createdAt: '2026-04-28',
|
||||||
targetUrl: 'https://www.viewclinic.com',
|
targetUrl: 'https://www.viewclinic.com',
|
||||||
|
|
||||||
// ─── Section 1: Brand Guide ───
|
// ─── Section 1: Brand Guide ───
|
||||||
|
|
@ -96,7 +96,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channelId: 'instagram_kr', channelName: 'Instagram KR', icon: 'instagram',
|
channelId: 'instagram_kr', channelName: 'Instagram KR', icon: 'instagram',
|
||||||
currentStatus: '14K 팔로워, Reels 0개', targetGoal: '50K 팔로워, Reels 주 5개',
|
currentStatus: '14,047 팔로워, Reels 0개', targetGoal: '50K 팔로워, Reels 주 5개',
|
||||||
contentTypes: ['Reels', 'Carousel', 'Stories', 'Feed Image'],
|
contentTypes: ['Reels', 'Carousel', 'Stories', 'Feed Image'],
|
||||||
postingFrequency: '일 1회 + Stories 일 2-3개',
|
postingFrequency: '일 1회 + Stories 일 2-3개',
|
||||||
tone: '차분하지만 접근 가능한 — 환자 관점의 Q&A',
|
tone: '차분하지만 접근 가능한 — 환자 관점의 Q&A',
|
||||||
|
|
@ -105,7 +105,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channelId: 'instagram_en', channelName: 'Instagram EN', icon: 'instagram',
|
channelId: 'instagram_en', channelName: 'Instagram EN', icon: 'instagram',
|
||||||
currentStatus: '70K 팔로워, Reels 활발', targetGoal: '120K 팔로워',
|
currentStatus: '70,537 팔로워, Reels 활발', targetGoal: '120K 팔로워',
|
||||||
contentTypes: ['Reels', 'Before/After', 'Patient Stories'],
|
contentTypes: ['Reels', 'Before/After', 'Patient Stories'],
|
||||||
postingFrequency: '주 5회',
|
postingFrequency: '주 5회',
|
||||||
tone: 'Professional & warm — medical tourism storytelling',
|
tone: 'Professional & warm — medical tourism storytelling',
|
||||||
|
|
@ -114,7 +114,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channelId: 'facebook', channelName: 'Facebook', icon: 'facebook',
|
channelId: 'facebook', channelName: 'Facebook', icon: 'facebook',
|
||||||
currentStatus: 'KR 253명 + EN 88K, 로고 불일치', targetGoal: '통합 관리, 광고 리타겟 전용',
|
currentStatus: 'KR 254명 + EN 88,333명, 로고 불일치', targetGoal: '통합 관리, 광고 리타겟 전용',
|
||||||
contentTypes: ['광고 크리에이티브', '리타겟 콘텐츠'],
|
contentTypes: ['광고 크리에이티브', '리타겟 콘텐츠'],
|
||||||
postingFrequency: '주 2-3회 (광고 소재 위주)',
|
postingFrequency: '주 2-3회 (광고 소재 위주)',
|
||||||
tone: '신뢰 기반 — 안전, 경험, 결과 강조',
|
tone: '신뢰 기반 — 안전, 경험, 결과 강조',
|
||||||
|
|
@ -123,7 +123,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channelId: 'naver_blog', channelName: 'Naver Blog', icon: 'globe',
|
channelId: 'naver_blog', channelName: 'Naver Blog', icon: 'globe',
|
||||||
currentStatus: '활성 — 550개 게시글, 월 2~3회 포스팅', targetGoal: '주 2회 포스팅, 월 30,000 방문자',
|
currentStatus: '활성 — 551개 게시글, 월 2~3회 포스팅 (최근 2026.4.22)', targetGoal: '주 2회 포스팅, 월 30,000 방문자',
|
||||||
contentTypes: ['SEO 블로그 포스트', '시술 가이드', '환자 후기'],
|
contentTypes: ['SEO 블로그 포스트', '시술 가이드', '환자 후기'],
|
||||||
postingFrequency: '주 3회',
|
postingFrequency: '주 3회',
|
||||||
tone: '정보성 전문가 — 키워드 중심, 환자 고민 해결',
|
tone: '정보성 전문가 — 키워드 중심, 환자 고민 해결',
|
||||||
|
|
@ -266,7 +266,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
{ id: 'a6', source: 'social', sourceLabel: '소셜미디어', type: 'photo', title: 'Instagram EN Before/After 사진', description: '@view_plastic_surgery 계정의 2,524개 게시물 중 B/A 사진', repurposingSuggestions: ['KR 계정 크로스포스팅', '유튜브 롱폼 삽입', 'Naver 블로그 활용'], status: 'collected' },
|
{ id: 'a6', source: 'social', sourceLabel: '소셜미디어', type: 'photo', title: 'Instagram EN Before/After 사진', description: '@view_plastic_surgery 계정의 2,524개 게시물 중 B/A 사진', repurposingSuggestions: ['KR 계정 크로스포스팅', '유튜브 롱폼 삽입', 'Naver 블로그 활용'], status: 'collected' },
|
||||||
{ id: 'a7', source: 'social', sourceLabel: '소셜미디어', type: 'text', title: '강남언니 환자 리뷰 18,840건', description: '9.5점 평균, 시술별 실 환자 후기 텍스트', repurposingSuggestions: ['후기 기반 Carousel 시리즈', '블로그 환자 스토리', '광고 사회적 증거'], status: 'pending' },
|
{ id: 'a7', source: 'social', sourceLabel: '소셜미디어', type: 'text', title: '강남언니 환자 리뷰 18,840건', description: '9.5점 평균, 시술별 실 환자 후기 텍스트', repurposingSuggestions: ['후기 기반 Carousel 시리즈', '블로그 환자 스토리', '광고 사회적 증거'], status: 'pending' },
|
||||||
{ id: 'a8', source: 'naver_place', sourceLabel: '네이버 플레이스', type: 'photo', title: '네이버 플레이스 사진', description: '병원 외관, 위치, 시설 사진', repurposingSuggestions: ['블로그 위치 안내 포스트', '구글 마이비즈니스 동기화'], status: 'pending' },
|
{ id: 'a8', source: 'naver_place', sourceLabel: '네이버 플레이스', type: 'photo', title: '네이버 플레이스 사진', description: '병원 외관, 위치, 시설 사진', repurposingSuggestions: ['블로그 위치 안내 포스트', '구글 마이비즈니스 동기화'], status: 'pending' },
|
||||||
{ id: 'a9', source: 'blog', sourceLabel: '블로그', type: 'text', title: '네이버 블로그 기존 포스트 550개', description: '기존 블로그 포스트 550개 (월 2~3회 업데이트 중)', repurposingSuggestions: ['SEO 최적화 리라이팅', '영상 스크립트 소스'], status: 'collected' },
|
{ id: 'a9', source: 'blog', sourceLabel: '블로그', type: 'text', title: '네이버 블로그 기존 포스트 551개', description: '기존 블로그 포스트 551개 (월 2~3회 업데이트 중)', repurposingSuggestions: ['SEO 최적화 리라이팅', '영상 스크립트 소스'], status: 'collected' },
|
||||||
{ id: 'a10', source: 'homepage', sourceLabel: '홈페이지', type: 'video', title: '개원 20주년 기념 영상', description: '뷰성형외과 20년 역사 + 시설 소개 영상 (1:30)', repurposingSuggestions: ['브랜드 스토리 Reel', '웹사이트 히어로 영상', '신뢰 광고 소재'], status: 'collected' },
|
{ id: 'a10', source: 'homepage', sourceLabel: '홈페이지', type: 'video', title: '개원 20주년 기념 영상', description: '뷰성형외과 20년 역사 + 시설 소개 영상 (1:30)', repurposingSuggestions: ['브랜드 스토리 Reel', '웹사이트 히어로 영상', '신뢰 광고 소재'], status: 'collected' },
|
||||||
{ id: 'a11', source: 'homepage', sourceLabel: '홈페이지', type: 'photo', title: '시술별 전후 사진 갤러리', description: '눈, 코, 가슴, 윤곽 시술별 비포/애프터 사진', repurposingSuggestions: ['Instagram B/A 시리즈', 'Shorts 전환 소스', '상담 자료'], status: 'needs_creation' },
|
{ id: 'a11', source: 'homepage', sourceLabel: '홈페이지', type: 'photo', title: '시술별 전후 사진 갤러리', description: '눈, 코, 가슴, 윤곽 시술별 비포/애프터 사진', repurposingSuggestions: ['Instagram B/A 시리즈', 'Shorts 전환 소스', '상담 자료'], status: 'needs_creation' },
|
||||||
],
|
],
|
||||||
|
|
@ -388,7 +388,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
channel: 'Naver Blog',
|
channel: 'Naver Blog',
|
||||||
channelIcon: 'globe',
|
channelIcon: 'globe',
|
||||||
stage: 'approved',
|
stage: 'approved',
|
||||||
scheduledDate: '2026-04-14',
|
scheduledDate: '2026-05-06',
|
||||||
imageTextDraft: {
|
imageTextDraft: {
|
||||||
type: 'blog',
|
type: 'blog',
|
||||||
headline: '눈성형 2주 후 솔직 리뷰 — VIEW 성형외과 후기',
|
headline: '눈성형 2주 후 솔직 리뷰 — VIEW 성형외과 후기',
|
||||||
|
|
@ -409,7 +409,7 @@ export const mockPlan: MarketingPlan = {
|
||||||
channel: 'TikTok',
|
channel: 'TikTok',
|
||||||
channelIcon: 'video',
|
channelIcon: 'video',
|
||||||
stage: 'scheduled',
|
stage: 'scheduled',
|
||||||
scheduledDate: '2026-04-10',
|
scheduledDate: '2026-05-02',
|
||||||
videoDraft: {
|
videoDraft: {
|
||||||
script: `"21년 동안 단 한 건의 의료사고도 없었습니다."\n(숫자 카운터 애니메이션: 0 → 21)\n"이게 VIEW의 자랑입니다."\n#강남성형외과 #무사고 #VIEW성형외과`,
|
script: `"21년 동안 단 한 건의 의료사고도 없었습니다."\n(숫자 카운터 애니메이션: 0 → 21)\n"이게 VIEW의 자랑입니다."\n#강남성형외과 #무사고 #VIEW성형외과`,
|
||||||
shootingGuide: [
|
shootingGuide: [
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import type { MarketingReport } from '../types/report';
|
import type { MarketingReport } from '../types/report';
|
||||||
|
|
||||||
|
// Last verified: 2026-04-28 (전 채널 실측 — Firecrawl + Apify)
|
||||||
|
// YouTube · 강남언니 · 네이버 플레이스 · 네이버 블로그: Firecrawl
|
||||||
|
// Instagram (KR · EN) · Facebook (KR · EN): Apify (apify/instagram-profile-scraper, apify/facebook-pages-scraper)
|
||||||
export const mockReport: MarketingReport = {
|
export const mockReport: MarketingReport = {
|
||||||
id: 'view-clinic',
|
id: 'view-clinic',
|
||||||
createdAt: '2026-04-13',
|
createdAt: '2026-04-28',
|
||||||
targetUrl: 'https://www.viewclinic.com',
|
targetUrl: 'https://www.viewclinic.com',
|
||||||
overallScore: 62,
|
overallScore: 62,
|
||||||
|
|
||||||
|
|
@ -19,7 +22,7 @@ export const mockReport: MarketingReport = {
|
||||||
reviewCount: 1805,
|
reviewCount: 1805,
|
||||||
},
|
},
|
||||||
overallRating: 9.5,
|
overallRating: 9.5,
|
||||||
totalReviews: 19030,
|
totalReviews: 19177,
|
||||||
priceRange: { min: '97,900', max: '13,200,000+', currency: '₩' },
|
priceRange: { min: '97,900', max: '13,200,000+', currency: '₩' },
|
||||||
certifications: [
|
certifications: [
|
||||||
'수술실 CCTV',
|
'수술실 CCTV',
|
||||||
|
|
@ -61,11 +64,11 @@ export const mockReport: MarketingReport = {
|
||||||
},
|
},
|
||||||
|
|
||||||
channelScores: [
|
channelScores: [
|
||||||
{ channel: 'YouTube', icon: 'youtube', score: 68, maxScore: 100, status: 'warning', headline: '104K 구독자, 주 2-3회 업로드, 최근 조회수 하락' },
|
{ channel: 'YouTube', icon: 'youtube', score: 68, maxScore: 100, status: 'warning', headline: '104K 구독자, 주 2-3회 업로드, 누적 1,035만 조회 (2주 +1.9%)' },
|
||||||
{ channel: 'Instagram KR', icon: 'instagram', score: 32, maxScore: 100, status: 'critical', headline: '14K 팔로워, Reels 0개, 모델 프사' },
|
{ channel: 'Instagram KR', icon: 'instagram', score: 32, maxScore: 100, status: 'critical', headline: '14,047 팔로워, Reels 0개, 모델 프사' },
|
||||||
{ channel: 'Instagram EN', icon: 'instagram', score: 62, maxScore: 100, status: 'warning', headline: '70K 팔로워, Reels 활발, 외국인 환자 중심' },
|
{ channel: 'Instagram EN', icon: 'instagram', score: 62, maxScore: 100, status: 'warning', headline: '70,537 팔로워, Reels 활발, 외국인 환자 중심' },
|
||||||
{ channel: 'Facebook', icon: 'facebook', score: 38, maxScore: 100, status: 'critical', headline: 'KR 253명 방치, EN 88K 활발, 3개 페이지 분산' },
|
{ channel: 'Facebook', icon: 'facebook', score: 38, maxScore: 100, status: 'critical', headline: 'KR 254명 방치, EN 88K 활발, 3개 페이지 분산' },
|
||||||
{ channel: '강남언니', icon: 'star', score: 96, maxScore: 100, status: 'excellent', headline: '9.5점/10, 19,030 리뷰, 고객평가우수병원' },
|
{ channel: '강남언니', icon: 'star', score: 96, maxScore: 100, status: 'excellent', headline: '9.5점/10, 19,177 리뷰, 고객평가우수병원' },
|
||||||
{ channel: 'Website', icon: 'globe', score: 65, maxScore: 100, status: 'warning', headline: 'Footer SNS 5개 연결, 트래킹 6개, SEO 기본 설정 양호' },
|
{ channel: 'Website', icon: 'globe', score: 65, maxScore: 100, status: 'warning', headline: 'Footer SNS 5개 연결, 트래킹 6개, SEO 기본 설정 양호' },
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
@ -73,13 +76,13 @@ export const mockReport: MarketingReport = {
|
||||||
channelName: '뷰성형외과 VIEW Plastic Surgery',
|
channelName: '뷰성형외과 VIEW Plastic Surgery',
|
||||||
handle: '@ViewclinicKR',
|
handle: '@ViewclinicKR',
|
||||||
subscribers: 104000,
|
subscribers: 104000,
|
||||||
totalVideos: 1064,
|
totalVideos: 1100,
|
||||||
totalViews: 9952722,
|
totalViews: 10348571,
|
||||||
weeklyViewGrowth: { absolute: 67097, percentage: 4.09 },
|
weeklyViewGrowth: { absolute: 197925, percentage: 1.91 },
|
||||||
estimatedMonthlyRevenue: { min: 499, max: 1000 },
|
estimatedMonthlyRevenue: { min: 499, max: 1000 },
|
||||||
avgVideoLength: '4.4분',
|
avgVideoLength: '4.4분',
|
||||||
uploadFrequency: '주 2~3회',
|
uploadFrequency: '주 2~3회',
|
||||||
channelCreatedDate: '2015-06-29',
|
channelCreatedDate: '2015-06-28',
|
||||||
subscriberRank: '#570K',
|
subscriberRank: '#570K',
|
||||||
channelDescription: '💜뷰성형외과💜\nVIEW가 예술이다! ✨\n19층 규모의 안전스마트 빌딩\n환자의 관점에서 생각하고\n환자의 입장에서 아름다움의 가치를 찾습니다.',
|
channelDescription: '💜뷰성형외과💜\nVIEW가 예술이다! ✨\n19층 규모의 안전스마트 빌딩\n환자의 관점에서 생각하고\n환자의 입장에서 아름다움의 가치를 찾습니다.',
|
||||||
linkedUrls: [
|
linkedUrls: [
|
||||||
|
|
@ -127,9 +130,9 @@ export const mockReport: MarketingReport = {
|
||||||
handle: '@viewplastic',
|
handle: '@viewplastic',
|
||||||
language: 'KR',
|
language: 'KR',
|
||||||
label: '국내 (한국어)',
|
label: '국내 (한국어)',
|
||||||
posts: 1420,
|
posts: 1429,
|
||||||
followers: 14000,
|
followers: 14047,
|
||||||
following: 3822,
|
following: 3774,
|
||||||
category: 'Health/beauty',
|
category: 'Health/beauty',
|
||||||
profileLink: 'litt.ly/viewplasticsurgery',
|
profileLink: 'litt.ly/viewplasticsurgery',
|
||||||
highlights: ['ABOUT VIEW', '수술정보', '모델 모집', 'VIEW EVENT', '진료안내'],
|
highlights: ['ABOUT VIEW', '수술정보', '모델 모집', 'VIEW EVENT', '진료안내'],
|
||||||
|
|
@ -142,9 +145,9 @@ export const mockReport: MarketingReport = {
|
||||||
handle: '@view_plastic_surgery',
|
handle: '@view_plastic_surgery',
|
||||||
language: 'EN',
|
language: 'EN',
|
||||||
label: '국제 (영어)',
|
label: '국제 (영어)',
|
||||||
posts: 2553,
|
posts: 2578,
|
||||||
followers: 70000,
|
followers: 70537,
|
||||||
following: 2840,
|
following: 2849,
|
||||||
category: 'Health/beauty',
|
category: 'Health/beauty',
|
||||||
profileLink: 'litt.ly/viewplasticsurgeryenglish',
|
profileLink: 'litt.ly/viewplasticsurgeryenglish',
|
||||||
highlights: ['Katerina', 'Mathilde', 'Kyle & Spizee', 'Chef Rush', 'Thet San', 'Yuri', 'Liposuction', 'Why VIEW?', 'Diana', 'Anti Aging', 'Julie', 'Male', 'Stem Cell', 'Dermatology'],
|
highlights: ['Katerina', 'Mathilde', 'Kyle & Spizee', 'Chef Rush', 'Thet San', 'Yuri', 'Liposuction', 'Why VIEW?', 'Diana', 'Anti Aging', 'Julie', 'Male', 'Stem Cell', 'Dermatology'],
|
||||||
|
|
@ -171,7 +174,7 @@ export const mockReport: MarketingReport = {
|
||||||
pageName: '뷰성형외과',
|
pageName: '뷰성형외과',
|
||||||
language: 'KR',
|
language: 'KR',
|
||||||
label: '국내 (한국어)',
|
label: '국내 (한국어)',
|
||||||
followers: 253,
|
followers: 254,
|
||||||
following: 0,
|
following: 0,
|
||||||
category: '성형외과 의사',
|
category: '성형외과 의사',
|
||||||
bio: '예쁨이 일상이 되는 순간! #뷰성형외과',
|
bio: '예쁨이 일상이 되는 순간! #뷰성형외과',
|
||||||
|
|
@ -191,7 +194,7 @@ export const mockReport: MarketingReport = {
|
||||||
pageName: 'View Plastic Surgery',
|
pageName: 'View Plastic Surgery',
|
||||||
language: 'EN',
|
language: 'EN',
|
||||||
label: '국제 (영어)',
|
label: '국제 (영어)',
|
||||||
followers: 88000,
|
followers: 88333,
|
||||||
following: 11,
|
following: 11,
|
||||||
category: '건강/뷰티',
|
category: '건강/뷰티',
|
||||||
bio: 'Official Account by VIEW Partners',
|
bio: 'Official Account by VIEW Partners',
|
||||||
|
|
@ -283,10 +286,10 @@ export const mockReport: MarketingReport = {
|
||||||
|
|
||||||
otherChannels: [
|
otherChannels: [
|
||||||
{ name: '카카오톡', status: 'active', details: '플러스친구 @뷰성형외과의원 — 상담 전용 채널', url: 'https://pf.kakao.com/_xbtVxjl' },
|
{ name: '카카오톡', status: 'active', details: '플러스친구 @뷰성형외과의원 — 상담 전용 채널', url: 'https://pf.kakao.com/_xbtVxjl' },
|
||||||
{ name: '네이버 블로그', status: 'active', details: '공식 블로그 활성 — 총 550개 게시글, 월 2~3회 포스팅, 최근 2026.4.8 업로드', url: 'https://blog.naver.com/viewclinicps' },
|
{ name: '네이버 블로그', status: 'active', details: '공식 블로그 활성 — 총 551개 게시글, 월 2~3회 포스팅, 최근 2026.4.22 업로드', url: 'https://blog.naver.com/viewclinicps' },
|
||||||
{ name: '네이버 플레이스', status: 'active', details: '별점 4.41/5, 방문자리뷰 777개, 블로그리뷰 1,480개, 성형외과 전문의 14명', url: 'https://m.place.naver.com/hospital/11709005' },
|
{ name: '네이버 플레이스', status: 'active', details: '별점 4.41/5, 방문자리뷰 776개, 블로그리뷰 1,508개, 성형외과 전문의 14명', url: 'https://m.place.naver.com/hospital/11709005' },
|
||||||
{ name: 'TikTok', status: 'not_found', details: '계정 없음 또는 비활성' },
|
{ name: 'TikTok', status: 'not_found', details: '계정 없음 또는 비활성' },
|
||||||
{ name: '강남언니', status: 'active', details: '9.5점/10, 19,030 리뷰, 25 의료진, 고객평가우수병원', url: 'https://www.gangnamunni.com/hospitals/189' },
|
{ name: '강남언니', status: 'active', details: '9.5점/10, 19,177 리뷰, 25 의료진, 고객평가우수병원', url: 'https://www.gangnamunni.com/hospitals/189' },
|
||||||
{ name: '네이버 카페', status: 'active', details: '"뷰성형외과 성형의 모든것" — 회원 5,984명, 비공개 카페, 시술별 Q&A/전후비교/수술후기 20개 게시판 운영', url: 'https://cafe.naver.com/bluectcom2' },
|
{ name: '네이버 카페', status: 'active', details: '"뷰성형외과 성형의 모든것" — 회원 5,984명, 비공개 카페, 시술별 Q&A/전후비교/수술후기 20개 게시판 운영', url: 'https://cafe.naver.com/bluectcom2' },
|
||||||
{ name: 'Threads', status: 'active', details: '@viewplastic + @view_plastic_surgery 계정 연동', url: 'https://www.threads.net/@viewplastic' },
|
{ name: 'Threads', status: 'active', details: '@viewplastic + @view_plastic_surgery 계정 연동', url: 'https://www.threads.net/@viewplastic' },
|
||||||
{ name: 'Facebook TH', status: 'inactive', details: '태국 파트너 페이지 14K 팔로워, 2024.7월 이후 방치', url: 'https://www.facebook.com/viewplasticsurgery' },
|
{ name: 'Facebook TH', status: 'inactive', details: '태국 파트너 페이지 14K 팔로워, 2024.7월 이후 방치', url: 'https://www.facebook.com/viewplasticsurgery' },
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,9 @@ const tiers: Tier[] = [
|
||||||
id: 'insight',
|
id: 'insight',
|
||||||
name: 'INSIGHT',
|
name: 'INSIGHT',
|
||||||
tagline: '매월 1번, 병원의 온라인 좌표를 점검하세요',
|
tagline: '매월 1번, 병원의 온라인 좌표를 점검하세요',
|
||||||
monthlyKRW: 490_000,
|
monthlyKRW: 90_000,
|
||||||
annualMonthlyKRW: 390_000,
|
annualMonthlyKRW: 72_000,
|
||||||
annualTotalKRW: 4_700_000,
|
annualTotalKRW: 864_000,
|
||||||
ctaLabel: '상담 문의',
|
ctaLabel: '상담 문의',
|
||||||
bullets: [
|
bullets: [
|
||||||
'월 1회 분석 리포트',
|
'월 1회 분석 리포트',
|
||||||
|
|
@ -73,13 +73,13 @@ const tiers: Tier[] = [
|
||||||
id: 'intelligence',
|
id: 'intelligence',
|
||||||
name: 'INTELLIGENCE',
|
name: 'INTELLIGENCE',
|
||||||
tagline: '경쟁사가 지금 무엇을 바꾸는지, 월 2번 확인하세요',
|
tagline: '경쟁사가 지금 무엇을 바꾸는지, 월 2번 확인하세요',
|
||||||
monthlyKRW: 1_490_000,
|
monthlyKRW: 290_000,
|
||||||
annualMonthlyKRW: 1_190_000,
|
annualMonthlyKRW: 232_000,
|
||||||
annualTotalKRW: 14_300_000,
|
annualTotalKRW: 2_784_000,
|
||||||
isPopular: true,
|
isPopular: true,
|
||||||
ctaLabel: '상담 문의',
|
ctaLabel: '상담 문의',
|
||||||
bullets: [
|
bullets: [
|
||||||
'월 2회 + on-demand 재실행 (월 4회까지)',
|
'월 4회 분석 리포트',
|
||||||
'8주 콘텐츠 캘린더 + 주간 KPI 기반 조정',
|
'8주 콘텐츠 캘린더 + 주간 KPI 기반 조정',
|
||||||
'Vision AI (의료진·슬로건·인증 자동 추출)',
|
'Vision AI (의료진·슬로건·인증 자동 추출)',
|
||||||
'경쟁사 추적 3개 · 주간 변동 알림',
|
'경쟁사 추적 3개 · 주간 변동 알림',
|
||||||
|
|
@ -93,15 +93,15 @@ const tiers: Tier[] = [
|
||||||
id: 'intelligence-plus',
|
id: 'intelligence-plus',
|
||||||
name: 'INTELLIGENCE+',
|
name: 'INTELLIGENCE+',
|
||||||
tagline: '매일 변하는 시장에 즉시 대응하세요',
|
tagline: '매일 변하는 시장에 즉시 대응하세요',
|
||||||
monthlyKRW: 3_990_000,
|
monthlyKRW: 990_000,
|
||||||
annualMonthlyKRW: 3_190_000,
|
annualMonthlyKRW: 792_000,
|
||||||
annualTotalKRW: 38_300_000,
|
annualTotalKRW: 9_504_000,
|
||||||
ctaLabel: '상담 문의',
|
ctaLabel: '상담 문의',
|
||||||
bullets: [
|
bullets: [
|
||||||
'월 20회 분석 리포트 (주간 자동 + on-demand)',
|
'월 10회 분석 리포트',
|
||||||
'12개월 로드맵 + 월간 전략 리뷰',
|
'12개월 로드맵 + 월간 전략 리뷰',
|
||||||
'최대 3개 분원 통합 대시보드',
|
'최대 3개 분원 통합 대시보드',
|
||||||
'경쟁사 추적 10개 · 일간 변동 모니터링',
|
'경쟁사 추적 5개 · 일간 변동 모니터링',
|
||||||
'브랜드 가이드 + 콘텐츠 필러 10종',
|
'브랜드 가이드 + 콘텐츠 필러 10종',
|
||||||
'커스텀 리포트 템플릿 (병원 CI 반영)',
|
'커스텀 리포트 템플릿 (병원 CI 반영)',
|
||||||
'신규 기능 베타 우선 접근',
|
'신규 기능 베타 우선 접근',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue