feat(ia): SaaS 제품 카탈로그(/packages) + 네비를 SaaS·음악·외주 3축으로 재편
- lib/saas-catalog.ts: 확장 가능한 SaaS 제품 데이터 모델(배열에 추가 시 자동 노출) - app/packages: 카탈로그 페이지 — available 카드 그리드 / coming_soon / 빈 상태 예고+출시 알림 수집(ContactModal 재사용) - TopNav·Footer: SaaS 제품(/packages)·AI 음악(/music)·커스텀 외주(/work) 3축 - 홈 Hero·라벨 카피를 새 정체성으로 정렬, 'Custom Build/사업부' 잔재 정리 - sitemap에 /packages 등록, STRATEGY.md에 크몽·숨고 미사용+인스타 유입 정책 명시 - 음악은 카탈로그에 넣지 않고 단품 라인(/music) 유지 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
12
STRATEGY.md
12
STRATEGY.md
@@ -1,8 +1,18 @@
|
|||||||
# 쟁승메이드 사업 전략 플레이북
|
# 쟁승메이드 사업 전략 플레이북
|
||||||
|
|
||||||
> 최초 작성: 2026-03-24 | 마지막 업데이트: 2026-03-24
|
> 최초 작성: 2026-03-24 | 마지막 업데이트: 2026-05-31
|
||||||
> 작성 방식: 마케터 · 인플루언서 · 사업가 3인 원탁 회의 기반
|
> 작성 방식: 마케터 · 인플루언서 · 사업가 3인 원탁 회의 기반
|
||||||
|
|
||||||
|
> **⚠️ 정체성 재정의 (2026-05-29, 본 문서 일부 전제 갱신)**
|
||||||
|
> 현재 정체성은 **"SaaS 제품 판매(메인) + 커스텀 외주(보조) 병행"**이다.
|
||||||
|
> - **외주 유입 채널: 크몽·숨고 등 외부 프리랜서 마켓은 사용하지 않는다.**
|
||||||
|
> 대신 **인스타 카드뉴스(Hedgy75) 직접 유입**으로 전환한다.
|
||||||
|
> → 아래 "크몽/숨고 AI 자동화 세팅 대행" 등 마켓 전제 섹션은 과거 전략 기록이며,
|
||||||
|
> 현 방침과 충돌 시 본 정책이 우선한다.
|
||||||
|
> - SaaS 제품 카탈로그는 `/packages`, AI 음악은 단품 가이드 패키지(`/music`)로 분리.
|
||||||
|
> - 블로그 자동화는 폐기(2026-05-17 결정, 코드 제거 완료).
|
||||||
|
> 상세: `docs/superpowers/plans/2026-05-31-saas-pivot-migration.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📊 현황 진단 — 3인 전문가 평가
|
## 📊 현황 진단 — 3인 전문가 평가
|
||||||
|
|||||||
@@ -75,17 +75,24 @@ export default function PublicShell({ children }: { children: React.ReactNode })
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 우 — Link groups */}
|
{/* 우 — Link groups */}
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-10">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-10">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-[11px] tracking-widest uppercase text-white/40 mb-4">Music</p>
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/40 mb-4">SaaS 제품</p>
|
||||||
<ul className="space-y-2.5">
|
<ul className="space-y-2.5">
|
||||||
<li><Link href="/music/packs" className="hover:text-white transition">AI 음악 팩</Link></li>
|
<li><Link href="/packages" className="hover:text-white transition">제품 카탈로그</Link></li>
|
||||||
|
<li><Link href="/packages" className="hover:text-white transition">출시 알림 신청</Link></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/40 mb-4">AI 음악</p>
|
||||||
|
<ul className="space-y-2.5">
|
||||||
|
<li><Link href="/music/packs" className="hover:text-white transition">음악 가이드 패키지</Link></li>
|
||||||
<li><Link href="/music/samples" className="hover:text-white transition">샘플 갤러리</Link></li>
|
<li><Link href="/music/samples" className="hover:text-white transition">샘플 갤러리</Link></li>
|
||||||
<li><Link href="/music/packs#pricing" className="hover:text-white transition">가격</Link></li>
|
<li><Link href="/music/packs#pricing" className="hover:text-white transition">가격</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-[11px] tracking-widest uppercase text-white/40 mb-4">Custom Build</p>
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/40 mb-4">커스텀 외주</p>
|
||||||
<ul className="space-y-2.5">
|
<ul className="space-y-2.5">
|
||||||
<li><Link href="/work/freelance" className="hover:text-white transition">외주 개발</Link></li>
|
<li><Link href="/work/freelance" className="hover:text-white transition">외주 개발</Link></li>
|
||||||
<li><Link href="/work/website" className="hover:text-white transition">웹사이트 제작</Link></li>
|
<li><Link href="/work/website" className="hover:text-white transition">웹사이트 제작</Link></li>
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import { createClient } from '@/lib/supabase/client';
|
|||||||
import type { User } from '@supabase/supabase-js';
|
import type { User } from '@supabase/supabase-js';
|
||||||
|
|
||||||
const LINKS = [
|
const LINKS = [
|
||||||
{ href: '/music', label: 'Music' },
|
{ href: '/packages', label: 'SaaS 제품' },
|
||||||
{ href: '/work', label: 'Custom Build' },
|
{ href: '/music', label: 'AI 음악' },
|
||||||
|
{ href: '/work', label: '커스텀 외주' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function TopNav() {
|
export default function TopNav() {
|
||||||
|
|||||||
18
app/packages/layout.tsx
Normal file
18
app/packages/layout.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'SaaS 제품 · 월 구독 패키지',
|
||||||
|
description:
|
||||||
|
'현직 엔지니어가 실제 운영하며 검증한 자동화를 월 구독 SaaS 제품으로 제공합니다. 첫 제품 준비 중 — 출시 알림을 신청하세요.',
|
||||||
|
keywords: ['SaaS', '자동화 구독', '월 구독 자동화', 'AI 자동화 제품', '쟁승메이드'],
|
||||||
|
openGraph: {
|
||||||
|
title: 'SaaS 제품 · 월 구독 패키지 | 쟁승메이드',
|
||||||
|
description:
|
||||||
|
'검증된 자동화를 SaaS로. 현직 엔지니어가 직접 운영·검증한 자동화 제품 카탈로그.',
|
||||||
|
url: 'https://jaengseung-made.com/packages',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PackagesLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
173
app/packages/page.tsx
Normal file
173
app/packages/page.tsx
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import ContactModal from '@/app/components/ContactModal';
|
||||||
|
import { trackCTAClick } from '@/lib/gtag';
|
||||||
|
import {
|
||||||
|
getAvailablePackages,
|
||||||
|
getComingSoonPackages,
|
||||||
|
type SaasCatalogItem,
|
||||||
|
} from '@/lib/saas-catalog';
|
||||||
|
|
||||||
|
const WAITLIST_SERVICE = 'SaaS 출시 알림 신청';
|
||||||
|
|
||||||
|
function PackageCard({ pkg, dimmed }: { pkg: SaasCatalogItem; dimmed?: boolean }) {
|
||||||
|
const inner = (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<p className="font-mono text-[10px] uppercase tracking-widest text-white/50">
|
||||||
|
{pkg.category}
|
||||||
|
</p>
|
||||||
|
{pkg.badge && (
|
||||||
|
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-full border border-white/30 text-white/80">
|
||||||
|
{pkg.badge}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{dimmed && !pkg.badge && (
|
||||||
|
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-full border border-white/20 text-white/50">
|
||||||
|
Coming Soon
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<h3 className="kx-display text-xl font-bold text-white mb-1.5">{pkg.name}</h3>
|
||||||
|
<p className="text-sm text-white/70 mb-3">{pkg.tagline}</p>
|
||||||
|
<p className="text-xs text-white/55 leading-relaxed mb-4 flex-1">{pkg.description}</p>
|
||||||
|
<ul className="space-y-2 mb-5">
|
||||||
|
{pkg.features.map((f) => (
|
||||||
|
<li key={f} className="flex gap-2 text-xs text-white/70">
|
||||||
|
<span className="text-white/40">·</span>
|
||||||
|
<span className="leading-relaxed">{f}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="mt-auto flex items-center justify-between">
|
||||||
|
{pkg.priceLabel ? (
|
||||||
|
<span className="font-mono text-sm text-white">{pkg.priceLabel}</span>
|
||||||
|
) : (
|
||||||
|
<span className="font-mono text-xs text-white/40">가격 준비 중</span>
|
||||||
|
)}
|
||||||
|
{!dimmed && <span aria-hidden className="text-white/50 text-sm">→</span>}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const base =
|
||||||
|
'group rounded-2xl border p-6 flex flex-col transition';
|
||||||
|
if (dimmed) {
|
||||||
|
return (
|
||||||
|
<div className={`${base} border-white/10 bg-white/[0.01] opacity-60`}>{inner}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={pkg.href ?? '#'}
|
||||||
|
onClick={() => trackCTAClick(`packages_card_${pkg.slug}`)}
|
||||||
|
className={`${base} border-white/15 bg-white/[0.02] hover:border-white/40 hover:bg-white/[0.05]`}
|
||||||
|
style={{ textDecoration: 'none' }}
|
||||||
|
>
|
||||||
|
{inner}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PackagesPage() {
|
||||||
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
const available = getAvailablePackages();
|
||||||
|
const comingSoon = getComingSoonPackages();
|
||||||
|
const isEmpty = available.length === 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-black text-white">
|
||||||
|
<ContactModal
|
||||||
|
isOpen={modalOpen}
|
||||||
|
onClose={() => setModalOpen(false)}
|
||||||
|
service={WAITLIST_SERVICE}
|
||||||
|
checklist={['관심 있는 업무·자동화 분야', '연락받을 이메일', '현재 겪는 반복 업무(선택)']}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="relative w-full min-h-[60vh] flex items-center justify-center px-6 border-b border-white/10">
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-[#0a0618] to-black pointer-events-none" />
|
||||||
|
<div className="relative z-10 max-w-3xl mx-auto text-center">
|
||||||
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4">
|
||||||
|
SaaS Products
|
||||||
|
</p>
|
||||||
|
<h1
|
||||||
|
className="kx-display text-4xl md:text-6xl font-bold mb-5"
|
||||||
|
style={{ wordBreak: 'keep-all', letterSpacing: '-0.02em' }}
|
||||||
|
>
|
||||||
|
검증된 자동화를
|
||||||
|
<br />SaaS로 만듭니다.
|
||||||
|
</h1>
|
||||||
|
<p className="text-base md:text-lg text-white/70 max-w-2xl mx-auto leading-relaxed">
|
||||||
|
현직 엔지니어가 실제로 운영하며 검증한 자동화를 월 구독 제품으로.
|
||||||
|
{isEmpty ? ' 첫 제품을 준비하고 있습니다.' : ''}
|
||||||
|
</p>
|
||||||
|
{isEmpty && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
trackCTAClick('packages_waitlist_hero');
|
||||||
|
setModalOpen(true);
|
||||||
|
}}
|
||||||
|
className="kx-btn-primary inline-flex items-center px-7 py-3 rounded-full text-sm mt-8"
|
||||||
|
>
|
||||||
|
출시 알림 받기
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Available 카탈로그 */}
|
||||||
|
{available.length > 0 && (
|
||||||
|
<section className="py-20 px-6">
|
||||||
|
<div className="max-w-6xl mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{available.map((pkg) => (
|
||||||
|
<PackageCard key={pkg.slug} pkg={pkg} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Coming Soon 예고 */}
|
||||||
|
{comingSoon.length > 0 && (
|
||||||
|
<section className="py-20 px-6 bg-white/[0.02] border-t border-white/10">
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4 text-center">
|
||||||
|
Coming Soon
|
||||||
|
</p>
|
||||||
|
<h2 className="kx-display text-2xl md:text-3xl font-bold text-center mb-10">
|
||||||
|
곧 만나볼 제품
|
||||||
|
</h2>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{comingSoon.map((pkg) => (
|
||||||
|
<PackageCard key={pkg.slug} pkg={pkg} dimmed />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 출시 알림 CTA — 항상 노출(빈 상태 아닐 때도 대기자 수집) */}
|
||||||
|
<section className="py-20 px-6 border-t border-white/10">
|
||||||
|
<div className="max-w-3xl mx-auto text-center">
|
||||||
|
<h2 className="kx-display text-2xl md:text-4xl font-bold mb-5">
|
||||||
|
새 제품이 나오면 가장 먼저 알려드릴까요?
|
||||||
|
</h2>
|
||||||
|
<p className="text-base text-white/70 mb-8">
|
||||||
|
관심 분야를 남겨주시면 출시 시 이메일로 안내드립니다. 원하는 자동화 제안도 환영합니다.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
trackCTAClick('packages_waitlist_cta');
|
||||||
|
setModalOpen(true);
|
||||||
|
}}
|
||||||
|
className="kx-btn-primary inline-flex items-center px-7 py-3 rounded-full text-sm"
|
||||||
|
>
|
||||||
|
출시 알림 받기
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
app/page.tsx
16
app/page.tsx
@@ -92,11 +92,11 @@ export default function Home() {
|
|||||||
className="kx-display text-4xl md:text-6xl lg:text-7xl font-bold mb-5 leading-[1.1]"
|
className="kx-display text-4xl md:text-6xl lg:text-7xl font-bold mb-5 leading-[1.1]"
|
||||||
style={{ wordBreak: 'keep-all', letterSpacing: '-0.02em' }}
|
style={{ wordBreak: 'keep-all', letterSpacing: '-0.02em' }}
|
||||||
>
|
>
|
||||||
현직 엔지니어가 만드는
|
현직 엔지니어가
|
||||||
<br />두 가지.
|
<br />직접 만듭니다.
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-base md:text-xl text-white/70 leading-relaxed">
|
<p className="text-base md:text-xl text-white/70 leading-relaxed">
|
||||||
AI 제품, 그리고 맞춤 개발.
|
검증된 자동화는 SaaS로. AI 음악 가이드와 커스텀 외주까지.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -140,7 +140,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Custom Build 카드 */}
|
{/* 커스텀 외주 카드 */}
|
||||||
<Link
|
<Link
|
||||||
href="/work"
|
href="/work"
|
||||||
onClick={() => trackCTAClick('home_v7_card_work')}
|
onClick={() => trackCTAClick('home_v7_card_work')}
|
||||||
@@ -153,10 +153,10 @@ export default function Home() {
|
|||||||
>
|
>
|
||||||
<div className="relative z-10">
|
<div className="relative z-10">
|
||||||
<p className="font-mono text-[11px] tracking-widest uppercase text-white/60 mb-3">
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/60 mb-3">
|
||||||
Custom Build
|
Custom Work
|
||||||
</p>
|
</p>
|
||||||
<h2 className="kx-display text-2xl md:text-3xl font-bold text-white mb-2">
|
<h2 className="kx-display text-2xl md:text-3xl font-bold text-white mb-2">
|
||||||
맞춤 개발 사업부
|
커스텀 외주
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm md:text-base text-white/70 mb-4">
|
<p className="text-sm md:text-base text-white/70 mb-4">
|
||||||
외주 · 웹사이트 · AI 사주
|
외주 · 웹사이트 · AI 사주
|
||||||
@@ -351,12 +351,12 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* 4. Custom Build 섹션 — 4 카드 + 5건 사례 + 견적 CTA */}
|
{/* 4. 커스텀 외주 섹션 — 카드 + 5건 사례 + 견적 CTA */}
|
||||||
<section className="py-24 px-6 bg-black text-white border-b border-white/10">
|
<section className="py-24 px-6 bg-black text-white border-b border-white/10">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="text-center mb-14">
|
<div className="text-center mb-14">
|
||||||
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4">
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4">
|
||||||
Custom Build
|
Custom Work
|
||||||
</p>
|
</p>
|
||||||
<h2
|
<h2
|
||||||
className="kx-display text-3xl md:text-5xl font-bold mb-5"
|
className="kx-display text-3xl md:text-5xl font-bold mb-5"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{ url: base, lastModified: now, changeFrequency: 'weekly', priority: 1.0 },
|
{ url: base, lastModified: now, changeFrequency: 'weekly', priority: 1.0 },
|
||||||
|
{ url: `${base}/packages`, lastModified: now, changeFrequency: 'weekly', priority: 0.9 },
|
||||||
{ url: `${base}/services/music`, lastModified: now, changeFrequency: 'weekly', priority: 0.95 },
|
{ url: `${base}/services/music`, lastModified: now, changeFrequency: 'weekly', priority: 0.95 },
|
||||||
{ url: `${base}/saju`, lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
|
{ url: `${base}/saju`, lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
|
||||||
{ url: `${base}/legal/terms`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
|
{ url: `${base}/legal/terms`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ export default function WorkHub() {
|
|||||||
<div className="absolute inset-0 bg-gradient-to-b from-[#060e20] to-black pointer-events-none" />
|
<div className="absolute inset-0 bg-gradient-to-b from-[#060e20] to-black pointer-events-none" />
|
||||||
<div className="relative z-10 max-w-3xl mx-auto text-center">
|
<div className="relative z-10 max-w-3xl mx-auto text-center">
|
||||||
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4">
|
<p className="font-mono text-[11px] tracking-widest uppercase text-white/50 mb-4">
|
||||||
Custom Build
|
Custom Work
|
||||||
</p>
|
</p>
|
||||||
<h1
|
<h1
|
||||||
className="kx-display text-4xl md:text-6xl font-bold mb-5"
|
className="kx-display text-4xl md:text-6xl font-bold mb-5"
|
||||||
style={{ wordBreak: 'keep-all', letterSpacing: '-0.02em' }}
|
style={{ wordBreak: 'keep-all', letterSpacing: '-0.02em' }}
|
||||||
>
|
>
|
||||||
맞춤 개발 사업부
|
커스텀 외주
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-base md:text-lg text-white/70 max-w-2xl mx-auto leading-relaxed">
|
<p className="text-base md:text-lg text-white/70 max-w-2xl mx-auto leading-relaxed">
|
||||||
7년차 백엔드 개발자가 직접 설계·개발·납품. 외주, 웹사이트, AI 사주까지.
|
7년차 백엔드 개발자가 직접 설계·개발·납품. 외주, 웹사이트, AI 사주까지.
|
||||||
|
|||||||
64
lib/saas-catalog.ts
Normal file
64
lib/saas-catalog.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// SaaS 제품 카탈로그 (/packages)
|
||||||
|
//
|
||||||
|
// 확장 규칙: 새 SaaS 제품을 출시하면 SAAS_CATALOG 배열에 객체 하나만 추가하면
|
||||||
|
// /packages 페이지에 카드가 자동으로 노출된다. 결제는 productId로 lib/products.ts의
|
||||||
|
// PRODUCTS 정의와 subscriptions 인프라에 연결한다.
|
||||||
|
//
|
||||||
|
// 음악(AI 음악 생성 개발 가이드 패키지)은 단품 라인이므로 여기에 넣지 않는다(/music 유지).
|
||||||
|
|
||||||
|
export type SaasStatus = 'available' | 'coming_soon';
|
||||||
|
|
||||||
|
export interface SaasCatalogItem {
|
||||||
|
/** /packages 내 식별자 (향후 /packages/[slug] 상세에 사용) */
|
||||||
|
slug: string;
|
||||||
|
/** 카드 제목 */
|
||||||
|
name: string;
|
||||||
|
/** 한 줄 요약 (카드 상단) */
|
||||||
|
tagline: string;
|
||||||
|
/** 카드 본문 설명 */
|
||||||
|
description: string;
|
||||||
|
/** 가격 표시용 라벨 (예: "월 ₩29,000"). 미정이면 생략 */
|
||||||
|
priceLabel?: string;
|
||||||
|
/** 과금 형태 */
|
||||||
|
billing: 'monthly' | 'one_time';
|
||||||
|
/** 노출 상태 — available: 구매 가능 / coming_soon: 예고 */
|
||||||
|
status: SaasStatus;
|
||||||
|
/** 핵심 기능 목록 */
|
||||||
|
features: string[];
|
||||||
|
/** 분류 라벨 (예: '자동화') */
|
||||||
|
category: string;
|
||||||
|
/** lib/products.ts PRODUCTS 키 참조 (결제 연결, available일 때) */
|
||||||
|
productId?: string;
|
||||||
|
/** available일 때 상세/결제 경로 */
|
||||||
|
href?: string;
|
||||||
|
/** 카드 강조 뱃지 (예: 'NEW') */
|
||||||
|
badge?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 등록된 SaaS 제품 목록.
|
||||||
|
*
|
||||||
|
* 2026-05-31 현재 비어 있다. 메이킹 스페이스에서 검증된 자동화가 1개 확정되면
|
||||||
|
* 아래 형태로 항목을 추가한다:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* slug: 'making-verify',
|
||||||
|
* name: '메이킹 검증 자동화',
|
||||||
|
* tagline: '...',
|
||||||
|
* description: '...',
|
||||||
|
* priceLabel: '월 ₩29,000',
|
||||||
|
* billing: 'monthly',
|
||||||
|
* status: 'available',
|
||||||
|
* features: ['...'],
|
||||||
|
* category: '자동화',
|
||||||
|
* productId: 'making_verify_monthly', // lib/products.ts에 함께 추가
|
||||||
|
* href: '/packages/making-verify',
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const SAAS_CATALOG: SaasCatalogItem[] = [];
|
||||||
|
|
||||||
|
export const getAvailablePackages = () =>
|
||||||
|
SAAS_CATALOG.filter((p) => p.status === 'available');
|
||||||
|
|
||||||
|
export const getComingSoonPackages = () =>
|
||||||
|
SAAS_CATALOG.filter((p) => p.status === 'coming_soon');
|
||||||
@@ -35,7 +35,7 @@ const nextConfig: NextConfig = {
|
|||||||
{ source: '/services/music', destination: '/music/packs', permanent: true },
|
{ source: '/services/music', destination: '/music/packs', permanent: true },
|
||||||
{ source: '/services/music/samples', destination: '/music/samples', permanent: true },
|
{ source: '/services/music/samples', destination: '/music/samples', permanent: true },
|
||||||
{ source: '/studio', destination: '/music/studio', permanent: true },
|
{ source: '/studio', destination: '/music/studio', permanent: true },
|
||||||
// Custom Build 사업부 마이그
|
// 커스텀 외주 마이그
|
||||||
{ source: '/freelance', destination: '/work/freelance', permanent: true },
|
{ source: '/freelance', destination: '/work/freelance', permanent: true },
|
||||||
{ source: '/services/website', destination: '/work/website', permanent: true },
|
{ source: '/services/website', destination: '/work/website', permanent: true },
|
||||||
{ source: '/services/website/samples/:slug', destination: '/work/website/samples/:slug', permanent: true },
|
{ source: '/services/website/samples/:slug', destination: '/work/website/samples/:slug', permanent: true },
|
||||||
|
|||||||
Reference in New Issue
Block a user