diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md
index f760373..27ab729 100644
--- a/docs/DESIGN_SYSTEM.md
+++ b/docs/DESIGN_SYSTEM.md
@@ -85,6 +85,15 @@
- 일반 본문 기본값은 `Body Small` 이상을 우선합니다.
- Figma token명이 바뀌면 CSS utility class 변경 전에 이 문서를 먼저 갱신합니다.
+
+### Fixed visual contracts for issue #14
+
+2026-06-23 기준, `LibraryBookCard`와 `PortfolioResumeSheet`는 범용 variant 시스템이 아니라 Figma 예시 화면을 코드로 고정한 초기 shared UI입니다.
+
+- `LibraryBookCard`는 도서관/레주메북 진입용 160×220 책 커버 카드입니다. 현재 커버는 `public/assets/library-book-cover.svg` 고정 asset을 사용하며, 이 파일명/경로는 issue #14 초기 카드 계약입니다. 카드 종류가 늘어나면 `cover` 또는 `variant` 계약을 별도 결정합니다.
+- `PortfolioResumeSheet`는 학생 포트폴리오 첫 자기소개/이력서 시트입니다. 사용자 지정 기준에 따라 이름은 `Title Small`, 전공 상태는 `Body Tiny`, 학번/학과/email 메타는 `Body very Tiny`를 사용합니다. `resume small` / `resume major` token은 PDF/고밀도 출력 기준이 확정될 때 별도 적용 여부를 결정합니다.
+- 공개 route와 `ComponentPreview`에서 쓰는 예시 데이터는 실제 API mock이 아니라 화면 확인용 fixture이므로 `src/shared/fixtures/examples/publicExamples.ts`에 둡니다.
+
### Spacing
TODO: spacing scale을 정리한다.
diff --git a/package.json b/package.json
index 6c20818..fea0c4d 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
"build": "next build",
"lint": "eslint .",
"start": "next start",
- "test:e2e": "playwright test"
+ "test:e2e": "playwright test",
+ "test:unit": "rm -rf /tmp/repo-v2-unit && tsc --ignoreConfig --types node --module NodeNext --moduleResolution NodeNext --target ES2022 --outDir /tmp/repo-v2-unit --rootDir . tests/unit/internalHref.test.ts src/shared/lib/internalHref.ts && node --test /tmp/repo-v2-unit/tests/unit/*.test.js"
},
"dependencies": {
"next": "^16.2.7",
diff --git a/public/assets/library-book-cover.svg b/public/assets/library-book-cover.svg
new file mode 100644
index 0000000..6333eb8
--- /dev/null
+++ b/public/assets/library-book-cover.svg
@@ -0,0 +1,46 @@
+
diff --git a/src/app/(public)/[portfolioSlug]/page.tsx b/src/app/(public)/[portfolioSlug]/page.tsx
index ea264be..d78d005 100644
--- a/src/app/(public)/[portfolioSlug]/page.tsx
+++ b/src/app/(public)/[portfolioSlug]/page.tsx
@@ -2,16 +2,14 @@ import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { isReservedPortfolioSlug, normalizePortfolioSlug } from '@/shared/lib/portfolioSlug'
+import { getSamplePortfolioResume, samplePortfolioResume } from '@/shared/fixtures/examples/publicExamples'
+import { PortfolioResumeSheet } from '@/shared/ui'
import styles from '../publicRoute.module.css'
-const mockPortfolio = {
- name: '오혜민',
- headline: '문제를 구조화하고 끝까지 구현하는 소프트웨어 메이커',
- school: '대덕소프트마이스터고등학교',
- skills: ['Product Thinking', 'Frontend', 'AI Native Workflow'],
+function getPortfolioDisplayName(decodedSlug: string) {
+ return decodedSlug === '오혜민' ? samplePortfolioResume.name : decodedSlug
}
-
type PortfolioPageProps = {
params: Promise<{
portfolioSlug: string
@@ -27,9 +25,11 @@ export async function generateMetadata({ params }: PortfolioPageProps): Promise<
const decodedSlug = normalizePortfolioSlug(portfolioSlug)
+ const displayName = getPortfolioDisplayName(decodedSlug)
+
return {
- title: `${decodedSlug} 포트폴리오`,
- description: `${decodedSlug} 학생의 공개 포트폴리오`,
+ title: `${displayName} 포트폴리오`,
+ description: `${displayName} 학생의 공개 포트폴리오`,
}
}
@@ -41,32 +41,13 @@ export default async function PortfolioPage({ params }: PortfolioPageProps) {
}
const decodedSlug = normalizePortfolioSlug(portfolioSlug)
- const displayName = decodedSlug === mockPortfolio.name ? mockPortfolio.name : decodedSlug
+ const displayName = getPortfolioDisplayName(decodedSlug)
+ const portfolio = getSamplePortfolioResume(displayName)
return (
-
-
- Public Portfolio
-
- {displayName}
-
-
{mockPortfolio.headline}
-
-
-
School
-
{mockPortfolio.school}
-
-
-
Slug
-
/{decodedSlug}
-
-
-
Skills
-
{mockPortfolio.skills.join(' · ')}
-
-
-
+
+
)
diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx
index 67cb9c2..6ae6edb 100644
--- a/src/app/(public)/page.tsx
+++ b/src/app/(public)/page.tsx
@@ -1,5 +1,8 @@
import Link from 'next/link'
+import { samplePortfolioHref, sampleResumeBookHref } from '@/shared/fixtures/examples/publicExamples'
+import { LibraryBookCard } from '@/shared/ui'
+
import styles from './publicRoute.module.css'
export default function HomePage() {
@@ -15,14 +18,31 @@ export default function HomePage() {
Repo는 학생의 이력서와 포트폴리오를 정리하고, 공개 URL을 통해 성장 기록을 보여주기 위한 서비스입니다.
-
+
공개 포트폴리오 예시
-
+
레주메북 예시
+
+
+
+ Examples
+
+ 바로 확인하는 포트폴리오와 레주메북 예시
+
+
+ 실제 데이터 연동 전에도 공개 포트폴리오와 레주메북의 진입 카드를 같은 컴포넌트 패턴으로 확인합니다.
+