import Link from 'next/link'; import type { Metadata } from 'next'; import { createAdminClient } from '@/lib/supabase/admin'; import { getListedProducts, type ProductRow } from '@/lib/supabase/product-files'; // 완성 소프트웨어 동적 카탈로그 (서버 컴포넌트). // DB 장애·마이그레이션 미적용 시 빈 배열로 폴백해 페이지가 항상 200으로 생존한다. export const metadata: Metadata = { title: '완성 소프트웨어', description: '쟁승메이드가 직접 운영하며 검증한 완성 소프트웨어 목록. 계좌이체 결제 후 입금 확인 즉시 마이페이지에서 다운로드할 수 있습니다.', }; // 카탈로그는 항상 최신 상품을 보여주도록 동적 렌더링. export const dynamic = 'force-dynamic'; const KOR_TIGHT = { letterSpacing: '-0.02em' } as const; const KOR_BODY = { letterSpacing: '-0.01em' } as const; const HOW = [ { n: '01', t: '계좌이체 신청', d: '구매할 도구를 고르고 입금자명과 함께 신청합니다.' }, { n: '02', t: '입금 확인', d: '입금이 확인되면 승인합니다. 최대 24시간 내 처리됩니다.' }, { n: '03', t: '마이페이지 다운로드', d: '마이페이지의 내 제품에서 파일을 바로 내려받습니다.' }, ]; function ArrowRight() { return ( ); } function CheckMark() { return ( ); } async function loadProducts(): Promise { try { return await getListedProducts(createAdminClient()); } catch (err) { // DB 장애·컬럼 미존재(마이그레이션 미적용) 등 — 페이지는 준비 중 폴백으로 생존 console.error('[Products] getListedProducts failed, falling back to empty:', err); return []; } } export default async function ProductsPage() { const products = await loadProducts(); const hasProducts = products.length > 0; return ( <> {/* ─── Hero ─── */}
완성 소프트웨어

직접 운영하며 검증한 도구를
그대로 가져가세요.

입금 확인 후 마이페이지에서 바로 다운로드할 수 있습니다.

{/* ─── 카탈로그 / 준비 중 ─── */} {hasProducts ? (
{products.map((p) => { const features = (p.features ?? []).slice(0, 3); return (

{p.name}

{p.description && (

{p.description}

)} {features.length > 0 && (
    {features.map((f) => (
  • {f}
  • ))}
)}
₩{p.price.toLocaleString('ko-KR')} 자세히 보기
); })}
) : (

출시 준비 중

현재 상품을 정비하고 있습니다.

로또 분석 도구, 주식 자동매매 유틸리티 등 실제로 운영 중인 도구들을 구매 가능한 형태로 순차 공개할 예정입니다. 출시 소식을 먼저 받고 싶다면 아래 링크로 문의해 주세요.

)} {/* ─── 구매 방식 안내 ─── */}

구매 방식

{HOW.map((step) => (
{step.n}

{step.t}

{step.d}

))}
{/* ─── CTA ─── */}
{hasProducts ? '맞춤 개발 문의' : '출시 소식 받기'} 외주 개발 알아보기
); }