Skip to content

Commit f8bc39f

Browse files
committed
refactor: SEO improve
1 parent f1f5276 commit f8bc39f

6 files changed

Lines changed: 82 additions & 31 deletions

File tree

src/app/layout.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ export const metadata: Metadata = {
4747
title: "Git Ranker | 개발자 전투력 측정",
4848
description: "GitHub 활동 기반 개발자 전투력 측정 및 티어 랭킹 서비스.",
4949
},
50+
robots: {
51+
index: true,
52+
follow: true,
53+
googleBot: {
54+
index: true,
55+
follow: true,
56+
'max-video-preview': -1,
57+
'max-image-preview': 'large',
58+
'max-snippet': -1,
59+
},
60+
},
61+
alternates: {
62+
canonical: BASE_URL,
63+
languages: {
64+
'ko-KR': BASE_URL,
65+
'x-default': BASE_URL,
66+
},
67+
},
5068
};
5169

5270
export const viewport: Viewport = {

src/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default function Home() {
6262
url: "https://www.git-ranker.com",
6363
logo: {
6464
"@type": "ImageObject",
65-
url: "https://www.git-ranker.com/logo.png",
65+
url: "https://www.git-ranker.com/og-image.png",
6666
},
6767
sameAs: ["https://github.com/alexization"],
6868
},

src/app/ranking/layout.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { Metadata } from "next"
22

3+
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || "https://www.git-ranker.com"
4+
35
export const metadata: Metadata = {
46
title: "개발자 랭킹 | 글로벌 리더보드",
57
description: "GitHub 활동 기반 개발자 전투력 글로벌 랭킹. Challenger, Master, Diamond부터 Iron까지 전 세계 개발자들의 순위를 확인하세요.",
@@ -14,7 +16,7 @@ export const metadata: Metadata = {
1416
openGraph: {
1517
type: "website",
1618
locale: "ko_KR",
17-
url: "https://www.git-ranker.com/ranking",
19+
url: `${BASE_URL}/ranking`,
1820
title: "개발자 랭킹 | Git Ranker 글로벌 리더보드",
1921
description: "GitHub 활동 기반 개발자 전투력 글로벌 랭킹. 전 세계 개발자들의 순위를 확인하세요.",
2022
siteName: "Git Ranker",
@@ -25,7 +27,7 @@ export const metadata: Metadata = {
2527
description: "GitHub 활동 기반 개발자 전투력 글로벌 랭킹",
2628
},
2729
alternates: {
28-
canonical: "https://www.git-ranker.com/ranking",
30+
canonical: `${BASE_URL}/ranking`,
2931
},
3032
}
3133

@@ -34,5 +36,27 @@ export default function RankingLayout({
3436
}: {
3537
children: React.ReactNode
3638
}) {
37-
return children
39+
const jsonLd = {
40+
"@context": "https://schema.org",
41+
"@type": "CollectionPage",
42+
name: "개발자 랭킹 | Git Ranker 글로벌 리더보드",
43+
description: "GitHub 활동 기반 개발자 전투력 글로벌 랭킹. Challenger, Master, Diamond부터 Iron까지 전 세계 개발자들의 순위를 확인하세요.",
44+
url: `${BASE_URL}/ranking`,
45+
isPartOf: {
46+
"@type": "WebSite",
47+
"@id": `${BASE_URL}/#website`,
48+
name: "Git Ranker",
49+
url: BASE_URL,
50+
},
51+
}
52+
53+
return (
54+
<>
55+
<script
56+
type="application/ld+json"
57+
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
58+
/>
59+
{children}
60+
</>
61+
)
3862
}

src/app/sitemap.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,6 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
8585
changeFrequency: "hourly",
8686
priority: 0.9,
8787
},
88-
{
89-
url: `${BASE_URL}/login`,
90-
lastModified: currentDate,
91-
changeFrequency: "monthly",
92-
priority: 0.5,
93-
},
9488
]
9589

9690
// Dynamic user pages

src/app/users/[username]/page.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,34 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
7575

7676
export default async function UserDetailPage({ params }: PageProps) {
7777
const { username } = await params
78-
return <UserProfileClient username={username} />
78+
79+
let jsonLd = null
80+
try {
81+
const user = await getUser(username)
82+
jsonLd = {
83+
"@context": "https://schema.org",
84+
"@type": "ProfilePage",
85+
mainEntity: {
86+
"@type": "Person",
87+
name: user.username,
88+
url: `${BASE_URL}/users/${username}`,
89+
image: user.profileImage,
90+
sameAs: [`https://github.com/${user.username}`],
91+
},
92+
}
93+
} catch {
94+
// no JSON-LD for users not found
95+
}
96+
97+
return (
98+
<>
99+
{jsonLd && (
100+
<script
101+
type="application/ld+json"
102+
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
103+
/>
104+
)}
105+
<UserProfileClient username={username} />
106+
</>
107+
)
79108
}

src/middleware.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,21 @@ export function middleware(request: NextRequest) {
2525
"form-action 'self'",
2626
].join("; ")
2727

28-
// Content Security Policy
28+
// Content Security Policy (Nginx에서 설정하지 않는 헤더)
2929
response.headers.set("Content-Security-Policy", cspDirectives)
3030

31-
// Prevent clickjacking
32-
response.headers.set("X-Frame-Options", "DENY")
33-
34-
// Prevent MIME type sniffing
35-
response.headers.set("X-Content-Type-Options", "nosniff")
36-
37-
// Enable XSS protection
38-
response.headers.set("X-XSS-Protection", "1; mode=block")
39-
40-
// Control referrer information
31+
// Referrer Policy (Nginx에서 설정하지 않는 헤더)
4132
response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
4233

43-
// HSTS - Force HTTPS (프로덕션에서만)
44-
if (!isDev) {
45-
response.headers.set(
46-
"Strict-Transport-Security",
47-
"max-age=31536000; includeSubDomains; preload"
48-
)
49-
}
50-
51-
// Permissions Policy - Restrict browser features
34+
// Permissions Policy (Nginx에서 설정하지 않는 헤더)
5235
response.headers.set(
5336
"Permissions-Policy",
5437
"camera=(), microphone=(), geolocation=(), interest-cohort=()"
5538
)
5639

40+
// X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, HSTS는
41+
// Nginx에서 관리 (중복 방지)
42+
5743
return response
5844
}
5945

0 commit comments

Comments
 (0)