diff --git a/AGENTS.md b/AGENTS.md index 605505f..599b41f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # Devy's Blog - Project Guide ## Overview -React + TypeScript + Vite로 구축된 개인 기술 블로그. GitHub Pages 커스텀 도메인(`devy1540.dev`)에 배포. +React + TypeScript + Vite로 구축된 개인 기술 블로그. GitHub Pages 커스텀 도메인(`dev.devy.dev`)에 배포. 블로그 글은 Markdown 파일로 관리하며, 빌드 타임에 `import.meta.glob`으로 로드. ## Tech Stack @@ -159,9 +159,9 @@ pnpm type-check # TypeScript 타입 체크 ``` ## Deployment -- GitHub Pages: `devy1540.dev` (custom domain) -- BASE_URL: `https://devy1540.dev` -- Custom domain: `public/CNAME` = `devy1540.dev` +- GitHub Pages: `dev.devy.dev` (custom domain) +- BASE_URL: `https://dev.devy.dev` +- Custom domain: `public/CNAME` = `dev.devy.dev` - 댓글: Giscus → `devy1540/devy1540.github.io` repo의 GitHub Discussions ## Code Conventions diff --git a/CLAUDE.md b/CLAUDE.md index 605505f..599b41f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # Devy's Blog - Project Guide ## Overview -React + TypeScript + Vite로 구축된 개인 기술 블로그. GitHub Pages 커스텀 도메인(`devy1540.dev`)에 배포. +React + TypeScript + Vite로 구축된 개인 기술 블로그. GitHub Pages 커스텀 도메인(`dev.devy.dev`)에 배포. 블로그 글은 Markdown 파일로 관리하며, 빌드 타임에 `import.meta.glob`으로 로드. ## Tech Stack @@ -159,9 +159,9 @@ pnpm type-check # TypeScript 타입 체크 ``` ## Deployment -- GitHub Pages: `devy1540.dev` (custom domain) -- BASE_URL: `https://devy1540.dev` -- Custom domain: `public/CNAME` = `devy1540.dev` +- GitHub Pages: `dev.devy.dev` (custom domain) +- BASE_URL: `https://dev.devy.dev` +- Custom domain: `public/CNAME` = `dev.devy.dev` - 댓글: Giscus → `devy1540/devy1540.github.io` repo의 GitHub Discussions ## Code Conventions diff --git a/README.md b/README.md index e24cbb7..3a2372e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
- + Devy Archive preview @@ -13,15 +13,15 @@ React, TypeScript, Vite로 만든 개인 기술 블로그입니다.

-[![Deploy](https://img.shields.io/github/deployments/devy1540/devy1540.github.io/github-pages?label=github%20pages&logo=github&style=for-the-badge)](https://devy1540.dev) +[![Deploy](https://img.shields.io/github/deployments/devy1540/devy1540.github.io/github-pages?label=github%20pages&logo=github&style=for-the-badge)](https://dev.devy.dev) [![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white&style=for-the-badge)](https://react.dev) [![TypeScript](https://img.shields.io/badge/TypeScript-5.8-3178C6?logo=typescript&logoColor=white&style=for-the-badge)](https://www.typescriptlang.org) [![Vite](https://img.shields.io/badge/Vite-8-646CFF?logo=vite&logoColor=white&style=for-the-badge)](https://vite.dev) [![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-4-06B6D4?logo=tailwindcss&logoColor=white&style=for-the-badge)](https://tailwindcss.com) -[Live Site](https://devy1540.dev)  ·  -[RSS](https://devy1540.dev/rss.xml)  ·  -[Sitemap](https://devy1540.dev/sitemap.xml) +[Live Site](https://dev.devy.dev)  ·  +[RSS](https://dev.devy.dev/rss.xml)  ·  +[Sitemap](https://dev.devy.dev/sitemap.xml)
@@ -174,8 +174,8 @@ publishDate: "2025-12-01" # optional, 예약 발행 | Data Viz | Recharts | | Community | Giscus | | Analytics | Google Analytics, Google Apps Script API | -| Deploy | GitHub Pages, custom domain `devy1540.dev` | +| Deploy | GitHub Pages, custom domain `dev.devy.dev` | ## 배포 -GitHub Pages로 배포하며, 커스텀 도메인은 `public/CNAME`의 `devy1540.dev`를 사용합니다. 빌드 시 `rss.xml`, `sitemap.xml`, route별 prerendered HTML이 함께 생성됩니다. +GitHub Pages로 배포하며, 커스텀 도메인은 `public/CNAME`의 `dev.devy.dev`를 사용합니다. 빌드 시 `rss.xml`, `sitemap.xml`, route별 prerendered HTML이 함께 생성됩니다. diff --git a/content/posts/en/blog-dev-04-search-seo.md b/content/posts/en/blog-dev-04-search-seo.md index d5eb9e3..71b396a 100644 --- a/content/posts/en/blog-dev-04-search-seo.md +++ b/content/posts/en/blog-dev-04-search-seo.md @@ -90,7 +90,7 @@ export function useMetaTags({ title, description, url, type = "website" }) { setMeta("description", description || "Notes from development work.") setMeta("og:title", title || "Devy's Blog") - setMeta("og:url", `https://devy1540.dev${url || "/"}`) + setMeta("og:url", `https://dev.devy.dev${url || "/"}`) // ... }, [title, description, url, type]) } @@ -130,7 +130,7 @@ The same Vite plugin generates `rss.xml` at build time. It parses each post's fr ```html + href="https://dev.devy.dev/rss.xml" /> ``` --- diff --git a/content/posts/en/blog-dev-06-ux-seo.md b/content/posts/en/blog-dev-06-ux-seo.md index 36d1728..b4ef088 100644 --- a/content/posts/en/blog-dev-06-ux-seo.md +++ b/content/posts/en/blog-dev-06-ux-seo.md @@ -99,7 +99,7 @@ Add one file: `public/robots.txt`. Vite copies files under `public/` directly in ```text User-agent: * Allow: / -Sitemap: https://devy1540.dev/sitemap.xml +Sitemap: https://dev.devy.dev/sitemap.xml ``` - `User-agent: *` - applies to all crawlers @@ -110,9 +110,9 @@ Sitemap: https://devy1540.dev/sitemap.xml After preparing robots.txt and sitemap, register the site in [Google Search Console](https://search.google.com/search-console). -1. Register `https://devy1540.dev` with either URL prefix or domain property. +1. Register `https://dev.devy.dev` with either URL prefix or domain property. 2. Complete ownership verification. -3. Submit `https://devy1540.dev/sitemap.xml` from the Sitemaps menu. +3. Submit `https://dev.devy.dev/sitemap.xml` from the Sitemaps menu. It can take days or weeks for Google to index the site, so it is normal if it does not appear in search results immediately. diff --git a/content/posts/ko/blog-dev-04-search-seo.md b/content/posts/ko/blog-dev-04-search-seo.md index 27ca219..a76a7fe 100644 --- a/content/posts/ko/blog-dev-04-search-seo.md +++ b/content/posts/ko/blog-dev-04-search-seo.md @@ -90,7 +90,7 @@ export function useMetaTags({ title, description, url, type = "website" }) { setMeta("description", description || "개발하며 배운 것들을 정리하고 공유합니다.") setMeta("og:title", title || "Devy's Blog") - setMeta("og:url", `https://devy1540.dev${url || "/"}`) + setMeta("og:url", `https://dev.devy.dev${url || "/"}`) // ... }, [title, description, url, type]) } @@ -130,7 +130,7 @@ function sitemapPlugin() { ```html + href="https://dev.devy.dev/rss.xml" /> ``` --- diff --git a/content/posts/ko/blog-dev-06-ux-seo.md b/content/posts/ko/blog-dev-06-ux-seo.md index 4d28efd..f8cf714 100644 --- a/content/posts/ko/blog-dev-06-ux-seo.md +++ b/content/posts/ko/blog-dev-06-ux-seo.md @@ -97,7 +97,7 @@ const { isMobile, setOpenMobile } = useSidebar() ``` User-agent: * Allow: / -Sitemap: https://devy1540.dev/sitemap.xml +Sitemap: https://dev.devy.dev/sitemap.xml ``` - `User-agent: *` - 모든 크롤러에 적용 @@ -108,9 +108,9 @@ Sitemap: https://devy1540.dev/sitemap.xml robots.txt와 sitemap을 준비한 후, [Google Search Console](https://search.google.com/search-console)에서 사이트를 등록합니다. -1. **URL 접두어** 또는 **도메인 속성** 방식으로 `https://devy1540.dev` 등록 +1. **URL 접두어** 또는 **도메인 속성** 방식으로 `https://dev.devy.dev` 등록 2. 소유권 인증 완료 -3. Sitemaps 메뉴에서 `https://devy1540.dev/sitemap.xml` 제출 +3. Sitemaps 메뉴에서 `https://dev.devy.dev/sitemap.xml` 제출 Google이 색인하는 데 며칠~몇 주 걸릴 수 있으므로 바로 검색 결과에 나타나지 않아도 정상입니다. diff --git a/docs/admin.md b/docs/admin.md index 30e5f3a..38fc0c3 100644 --- a/docs/admin.md +++ b/docs/admin.md @@ -26,8 +26,8 @@ GitHub OAuth로 로그인한 관리자가 블로그 페이지 안에서 글의 * 1. https://github.com/settings/developers → **New OAuth App** 2. 입력: - **Application name**: `devy-blog-admin` (자유) - - **Homepage URL**: `https://devy1540.dev` - - **Authorization callback URL**: `https://devy1540.dev/admin/callback/` + - **Homepage URL**: `https://dev.devy.dev` + - **Authorization callback URL**: `https://dev.devy.dev/admin/callback/` - 로컬 테스트도 하려면 **Add another callback URL**로 `http://localhost:5173/admin/callback/` 추가 3. 생성 후 **Client ID** 복사. **Generate a new client secret**으로 secret도 발급(한 번만 표시되니 보관). @@ -40,7 +40,7 @@ GitHub OAuth로 로그인한 관리자가 블로그 페이지 안에서 글의 * 이 저장소는 OAuth 토큰 교환 서버를 포함하지 않습니다. 별도로 운영하는 HTTPS API가 `POST { "code": "..." }` 요청을 받아 GitHub OAuth App의 `client_secret`으로 토큰을 교환하고, 성공 시 `{ "access_token": "..." }`을 반환해야 합니다. API에서는 허용 Origin을 -`https://devy1540.dev`로 제한하고 `client_secret`을 서버 측 시크릿으로 관리하세요. +`https://dev.devy.dev`로 제한하고 `client_secret`을 서버 측 시크릿으로 관리하세요. --- @@ -68,7 +68,7 @@ git commit && git push # main 푸시 → GitHub Actions 배포 ## 5. 사용 -1. `https://devy1540.dev/admin` 접속 → **GitHub로 로그인** +1. `https://dev.devy.dev/admin` 접속 → **GitHub로 로그인** 2. 인증되면 글 목록이 뜨고, 각 글의 **초안으로 / 발행하기** 버튼으로 토글 3. 토글 시 frontmatter가 커밋되고, 재빌드 후 반영(목록 상단에 안내) 4. 로그인하면 사이드바에도 **관리자** 메뉴가 나타남 diff --git a/index.html b/index.html index 4c03711..fa78028 100644 --- a/index.html +++ b/index.html @@ -11,22 +11,22 @@ - + - + - + - + - - + + diff --git a/public/CNAME b/public/CNAME index f4ac655..d4d7845 100644 --- a/public/CNAME +++ b/public/CNAME @@ -1 +1 @@ -devy1540.dev +dev.devy.dev diff --git a/public/llms.txt b/public/llms.txt index 45f7b51..4623ec3 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -2,30 +2,30 @@ > Devy Archive is a bilingual Korean/English technical blog by backend engineer Hyeokjun Yoon. It focuses on backend architecture, authentication, payment systems, observability, Kubernetes operations, Java/Spring modernization, React blog platform engineering, and applied LLM engineering. -The canonical site is https://devy1540.dev. Korean is the default language, and English pages are served under the `/en` prefix. Posts are written as Markdown files with frontmatter, rendered through a React + TypeScript + Vite app, and published as hydrated static HTML on GitHub Pages. +The canonical site is https://dev.devy.dev. Korean is the default language, and English pages are served under the `/en` prefix. Posts are written as Markdown files with frontmatter, rendered through a React + TypeScript + Vite app, and published as hydrated static HTML on GitHub Pages. ## Site Structure -- Default Korean home: https://devy1540.dev/ -- English home: https://devy1540.dev/en/ -- Korean posts: https://devy1540.dev/posts -- English posts: https://devy1540.dev/en/posts -- Korean post URL pattern: `https://devy1540.dev/posts/{slug}/` -- English post URL pattern: `https://devy1540.dev/en/posts/{slug}/` -- Project URL pattern: `https://devy1540.dev/about/projects/{slug}/` -- English project URL pattern: `https://devy1540.dev/en/about/projects/{slug}/` +- Default Korean home: https://dev.devy.dev/ +- English home: https://dev.devy.dev/en/ +- Korean posts: https://dev.devy.dev/posts +- English posts: https://dev.devy.dev/en/posts +- Korean post URL pattern: `https://dev.devy.dev/posts/{slug}/` +- English post URL pattern: `https://dev.devy.dev/en/posts/{slug}/` +- Project URL pattern: `https://dev.devy.dev/about/projects/{slug}/` +- English project URL pattern: `https://dev.devy.dev/en/about/projects/{slug}/` ## Core Pages -- [Home](https://devy1540.dev/): Latest posts, popular posts, and blog statistics. -- [Posts](https://devy1540.dev/posts): Full article archive. -- [Tags](https://devy1540.dev/tags): Topic-based navigation. -- [Series](https://devy1540.dev/series): Multi-part article series. -- [Search](https://devy1540.dev/search): Search by keyword, tag, and date. -- [Analytics](https://devy1540.dev/analytics): Blog visit and page-view statistics. -- [About](https://devy1540.dev/about): Author profile, career history, skills, and projects. +- [Home](https://dev.devy.dev/): Latest posts, popular posts, and blog statistics. +- [Posts](https://dev.devy.dev/posts): Full article archive. +- [Tags](https://dev.devy.dev/tags): Topic-based navigation. +- [Series](https://dev.devy.dev/series): Multi-part article series. +- [Search](https://dev.devy.dev/search): Search by keyword, tag, and date. +- [Analytics](https://dev.devy.dev/analytics): Blog visit and page-view statistics. +- [About](https://dev.devy.dev/about): Author profile, career history, skills, and projects. -English equivalents use the same paths with `/en` prepended, for example https://devy1540.dev/en/posts and https://devy1540.dev/en/about. +English equivalents use the same paths with `/en` prepended, for example https://dev.devy.dev/en/posts and https://dev.devy.dev/en/about. ## Main Topics @@ -40,57 +40,57 @@ English equivalents use the same paths with `/en` prepended, for example https:/ ## Recommended Articles -- [JWT 서명 전환 - HS256에서 RS256/JWKS/KMS로](https://devy1540.dev/posts/jwt-hs256-to-rs256-jwks-kms): Migrating symmetric JWT signing to RS256/JWKS/KMS with key rotation and legacy token handling. -- [로그인 책임 분리 (1) - 프론트엔드에서 백엔드로 옮긴 이유](https://devy1540.dev/posts/backend-owned-login-flow): Why login responsibility moved from frontend-owned state to backend-owned authorization. -- [로그인 책임 분리 (2) - authorize/callback 흐름 연결하기](https://devy1540.dev/posts/auth-authorize-callback-flow): Connecting protected pages, backend authorize, callback handling, and token issuance. -- [로그인 책임 분리 (3) - 기존 토큰과 새 백엔드 토큰을 함께 검증하기](https://devy1540.dev/posts/auth-token-verification-migration): Token verification order and migration handling when old and new tokens coexist. -- [결제 시스템 재설계 (1) - PHP 레거시에서 Java/Spring으로](https://devy1540.dev/posts/payment-system-migration-php-to-spring): Migrating a legacy PHP payment system to Java/Spring. -- [결제 시스템 재설계 (2) - SQS를 걷어내고 동기 API로](https://devy1540.dev/posts/payment-system-redesign-sync-api): Simplifying payment flow from SQS-based async processing to synchronous APIs and webhooks. -- [멀티채널 알림 서버 구축기 - php 레거시에서 Java/Spring으로](https://devy1540.dev/posts/multi-channel-notification-server): Building a unified notification server for KakaoTalk, SMS, email, push, and Slack. -- [API 응답/에러 처리 구조 공통화 - HTTP 상태코드를 제대로 쓰기까지](https://devy1540.dev/posts/api-response-error-standardization): Replacing always-200 API responses with consistent HTTP status and error handling. -- [Spring MVC에 Facade 패턴 도입기 - @Gateway 어노테이션으로 레이어드 아키텍처 개선](https://devy1540.dev/posts/spring-facade-pattern-layered-architecture): Introducing a facade layer and custom gateway annotation in a Spring MVC architecture. -- [ECS에서 EKS로 - kustomize + Gateway API 기반 운영 환경 구축기](https://devy1540.dev/posts/ecs-to-eks-migration): Migrating from ECS to EKS with kustomize, Gateway API, Karpenter, and blue/green deployment. -- [Datadog 걷어내고 LGTM 스택 구축하기 - OTel Sidecar + Grafana/Loki/Tempo/Mimir](https://devy1540.dev/posts/lgtm-stack-observability): Replacing Datadog with an open-source LGTM observability stack. -- [EKS에 LGTM 스택 구축하기 - Loki, Grafana, Tempo, Mimir 실전 셋업 가이드](https://devy1540.dev/posts/lgtm-stack-setup-guide): Setting up the LGTM observability stack on EKS. -- [Spring AI 실전 적용기 - 7단계 AI 진단 파이프라인 구축](https://devy1540.dev/posts/spring-ai-pipeline-real-world): Applying Spring AI to a production multi-step AI diagnostic pipeline. -- [Spring AI 적용 가이드 (1) - 프로젝트 설정부터 첫 번째 AI 호출까지](https://devy1540.dev/posts/spring-ai-guide-01-setup): Starting a Spring AI project and making the first AI call. -- [Spring AI 적용 가이드 (2) - 멀티 프로바이더 전략](https://devy1540.dev/posts/spring-ai-guide-02-multi-provider): Designing a multi-provider AI strategy. -- [Spring AI 적용 가이드 (3) - 프롬프트 관리 & Structured Output](https://devy1540.dev/posts/spring-ai-guide-03-prompt-structured-output): Managing prompts and structured output in Spring AI. -- [JDK 마이그레이션 (1) - JDK 11에서 21로, Spring Boot 3.x 전환기](https://devy1540.dev/posts/jdk-migration-strategy-11-to-25): Moving from JDK 11 to 21 and Spring Boot 3.x. -- [JDK 마이그레이션 (2) - JDK 21에서 25로, Virtual Threads와 모던 Java](https://devy1540.dev/posts/jdk-migration-strategy-21-to-25): Moving from JDK 21 to 25 and adopting modern Java features. -- [Platform Thread vs Virtual Thread vs Coroutine - 10,000 태스크 벤치마크](https://devy1540.dev/posts/sync-virtual-coroutine-benchmark): Comparing platform threads, virtual threads, and coroutines in a 10,000-task benchmark. +- [JWT 서명 전환 - HS256에서 RS256/JWKS/KMS로](https://dev.devy.dev/posts/jwt-hs256-to-rs256-jwks-kms): Migrating symmetric JWT signing to RS256/JWKS/KMS with key rotation and legacy token handling. +- [로그인 책임 분리 (1) - 프론트엔드에서 백엔드로 옮긴 이유](https://dev.devy.dev/posts/backend-owned-login-flow): Why login responsibility moved from frontend-owned state to backend-owned authorization. +- [로그인 책임 분리 (2) - authorize/callback 흐름 연결하기](https://dev.devy.dev/posts/auth-authorize-callback-flow): Connecting protected pages, backend authorize, callback handling, and token issuance. +- [로그인 책임 분리 (3) - 기존 토큰과 새 백엔드 토큰을 함께 검증하기](https://dev.devy.dev/posts/auth-token-verification-migration): Token verification order and migration handling when old and new tokens coexist. +- [결제 시스템 재설계 (1) - PHP 레거시에서 Java/Spring으로](https://dev.devy.dev/posts/payment-system-migration-php-to-spring): Migrating a legacy PHP payment system to Java/Spring. +- [결제 시스템 재설계 (2) - SQS를 걷어내고 동기 API로](https://dev.devy.dev/posts/payment-system-redesign-sync-api): Simplifying payment flow from SQS-based async processing to synchronous APIs and webhooks. +- [멀티채널 알림 서버 구축기 - php 레거시에서 Java/Spring으로](https://dev.devy.dev/posts/multi-channel-notification-server): Building a unified notification server for KakaoTalk, SMS, email, push, and Slack. +- [API 응답/에러 처리 구조 공통화 - HTTP 상태코드를 제대로 쓰기까지](https://dev.devy.dev/posts/api-response-error-standardization): Replacing always-200 API responses with consistent HTTP status and error handling. +- [Spring MVC에 Facade 패턴 도입기 - @Gateway 어노테이션으로 레이어드 아키텍처 개선](https://dev.devy.dev/posts/spring-facade-pattern-layered-architecture): Introducing a facade layer and custom gateway annotation in a Spring MVC architecture. +- [ECS에서 EKS로 - kustomize + Gateway API 기반 운영 환경 구축기](https://dev.devy.dev/posts/ecs-to-eks-migration): Migrating from ECS to EKS with kustomize, Gateway API, Karpenter, and blue/green deployment. +- [Datadog 걷어내고 LGTM 스택 구축하기 - OTel Sidecar + Grafana/Loki/Tempo/Mimir](https://dev.devy.dev/posts/lgtm-stack-observability): Replacing Datadog with an open-source LGTM observability stack. +- [EKS에 LGTM 스택 구축하기 - Loki, Grafana, Tempo, Mimir 실전 셋업 가이드](https://dev.devy.dev/posts/lgtm-stack-setup-guide): Setting up the LGTM observability stack on EKS. +- [Spring AI 실전 적용기 - 7단계 AI 진단 파이프라인 구축](https://dev.devy.dev/posts/spring-ai-pipeline-real-world): Applying Spring AI to a production multi-step AI diagnostic pipeline. +- [Spring AI 적용 가이드 (1) - 프로젝트 설정부터 첫 번째 AI 호출까지](https://dev.devy.dev/posts/spring-ai-guide-01-setup): Starting a Spring AI project and making the first AI call. +- [Spring AI 적용 가이드 (2) - 멀티 프로바이더 전략](https://dev.devy.dev/posts/spring-ai-guide-02-multi-provider): Designing a multi-provider AI strategy. +- [Spring AI 적용 가이드 (3) - 프롬프트 관리 & Structured Output](https://dev.devy.dev/posts/spring-ai-guide-03-prompt-structured-output): Managing prompts and structured output in Spring AI. +- [JDK 마이그레이션 (1) - JDK 11에서 21로, Spring Boot 3.x 전환기](https://dev.devy.dev/posts/jdk-migration-strategy-11-to-25): Moving from JDK 11 to 21 and Spring Boot 3.x. +- [JDK 마이그레이션 (2) - JDK 21에서 25로, Virtual Threads와 모던 Java](https://dev.devy.dev/posts/jdk-migration-strategy-21-to-25): Moving from JDK 21 to 25 and adopting modern Java features. +- [Platform Thread vs Virtual Thread vs Coroutine - 10,000 태스크 벤치마크](https://dev.devy.dev/posts/sync-virtual-coroutine-benchmark): Comparing platform threads, virtual threads, and coroutines in a 10,000-task benchmark. ## Article Series -- [로그인 책임 분리](https://devy1540.dev/series): 3 posts on backend-owned login flow, authorize/callback handling, and token verification migration. -- [결제 시스템 재설계](https://devy1540.dev/series): 2 posts on payment system migration and redesign from legacy PHP to Java/Spring. -- [서비스 인프라 현대화](https://devy1540.dev/series): 2 posts on EKS, GitOps, Gateway API, and LGTM observability modernization. -- [JDK Migration](https://devy1540.dev/series): 2 posts on Java runtime migration from JDK 11 to 21 and JDK 21 to 25. -- [Spring AI 적용 가이드](https://devy1540.dev/series): 3 posts on Spring AI setup, multi-provider strategy, prompt management, and structured output. -- [React 블로그 만들기](https://devy1540.dev/series): 6 posts on building this blog with React, Vite, search, SEO, analytics, UX, and hydrated SSG. -- [React 마스터하기](https://devy1540.dev/series): 2 posts on React hooks and React + TypeScript practices. +- [로그인 책임 분리](https://dev.devy.dev/series): 3 posts on backend-owned login flow, authorize/callback handling, and token verification migration. +- [결제 시스템 재설계](https://dev.devy.dev/series): 2 posts on payment system migration and redesign from legacy PHP to Java/Spring. +- [서비스 인프라 현대화](https://dev.devy.dev/series): 2 posts on EKS, GitOps, Gateway API, and LGTM observability modernization. +- [JDK Migration](https://dev.devy.dev/series): 2 posts on Java runtime migration from JDK 11 to 21 and JDK 21 to 25. +- [Spring AI 적용 가이드](https://dev.devy.dev/series): 3 posts on Spring AI setup, multi-provider strategy, prompt management, and structured output. +- [React 블로그 만들기](https://dev.devy.dev/series): 6 posts on building this blog with React, Vite, search, SEO, analytics, UX, and hydrated SSG. +- [React 마스터하기](https://dev.devy.dev/series): 2 posts on React hooks and React + TypeScript practices. ## Project Pages -- [AI 진단/피드백 파이프라인 구축](https://devy1540.dev/about/projects/ai-diagnostic-pipeline): Multi-step AI pipeline with Spring AI, Gemini, AWS Bedrock, and OpenAI. -- [결제 시스템 전면 재설계](https://devy1540.dev/about/projects/payment-system): Payment system migration, idempotency, webhooks, and PortOne integration. -- [멀티채널 알림서버 신규 구축](https://devy1540.dev/about/projects/notification-server): Event-driven notification server with SQS, Redis, DynamoDB, and multiple delivery channels. -- [사용자 데이터 기반 개인화 시스템 구축](https://devy1540.dev/about/projects/personalization-system): Segmentation-based coupons, retention flows, and personalized user benefits. -- [온보딩 및 체험레슨 예약 플로우 고도화](https://devy1540.dev/about/projects/onboarding-trial-flow): Trial lesson onboarding, reservation state consistency, and feature-flagged rollout. -- [인증 시스템 리팩토링 및 레거시 전환](https://devy1540.dev/about/projects/auth-refactoring): OAuth/JWT authentication refactoring and legacy migration. -- [개발 프로세스 개선](https://devy1540.dev/about/projects/dev-process): Facade patterns, common API responses, error handling, and metadata-driven domain design. -- [서비스 인프라 현대화 및 보안 체계 구축](https://devy1540.dev/about/projects/infra-modernization): EKS, GitOps, observability, WAF, and secrets modernization. -- [온프레미스형 DPM 모니터링 시스템 리팩토링](https://devy1540.dev/about/projects/dpm-monitoring): Query optimization for high-volume monitoring data. -- [SaaS형 모니터링 서비스 비즈니스 로직 구현](https://devy1540.dev/about/projects/saas-monitoring): Multi-tenant SaaS monitoring service and DataSaker product work. -- [SaaS형 모니터링 서비스 데이터 수집 파이프라인 구축](https://devy1540.dev/about/projects/data-pipeline): Kafka Stream and Apache Druid data collection pipeline. -- [쿠버네티스 모니터링 시스템 개발](https://devy1540.dev/about/projects/k8s-monitoring): Kubernetes monitoring API and CloudMOA product work. +- [AI 진단/피드백 파이프라인 구축](https://dev.devy.dev/about/projects/ai-diagnostic-pipeline): Multi-step AI pipeline with Spring AI, Gemini, AWS Bedrock, and OpenAI. +- [결제 시스템 전면 재설계](https://dev.devy.dev/about/projects/payment-system): Payment system migration, idempotency, webhooks, and PortOne integration. +- [멀티채널 알림서버 신규 구축](https://dev.devy.dev/about/projects/notification-server): Event-driven notification server with SQS, Redis, DynamoDB, and multiple delivery channels. +- [사용자 데이터 기반 개인화 시스템 구축](https://dev.devy.dev/about/projects/personalization-system): Segmentation-based coupons, retention flows, and personalized user benefits. +- [온보딩 및 체험레슨 예약 플로우 고도화](https://dev.devy.dev/about/projects/onboarding-trial-flow): Trial lesson onboarding, reservation state consistency, and feature-flagged rollout. +- [인증 시스템 리팩토링 및 레거시 전환](https://dev.devy.dev/about/projects/auth-refactoring): OAuth/JWT authentication refactoring and legacy migration. +- [개발 프로세스 개선](https://dev.devy.dev/about/projects/dev-process): Facade patterns, common API responses, error handling, and metadata-driven domain design. +- [서비스 인프라 현대화 및 보안 체계 구축](https://dev.devy.dev/about/projects/infra-modernization): EKS, GitOps, observability, WAF, and secrets modernization. +- [온프레미스형 DPM 모니터링 시스템 리팩토링](https://dev.devy.dev/about/projects/dpm-monitoring): Query optimization for high-volume monitoring data. +- [SaaS형 모니터링 서비스 비즈니스 로직 구현](https://dev.devy.dev/about/projects/saas-monitoring): Multi-tenant SaaS monitoring service and DataSaker product work. +- [SaaS형 모니터링 서비스 데이터 수집 파이프라인 구축](https://dev.devy.dev/about/projects/data-pipeline): Kafka Stream and Apache Druid data collection pipeline. +- [쿠버네티스 모니터링 시스템 개발](https://dev.devy.dev/about/projects/k8s-monitoring): Kubernetes monitoring API and CloudMOA product work. ## Feeds And Discovery -- [Korean RSS Feed](https://devy1540.dev/rss.xml): Latest Korean posts. -- [English RSS Feed](https://devy1540.dev/en/rss.xml): Latest English posts. -- [Sitemap](https://devy1540.dev/sitemap.xml): Complete index of public pages and posts with language alternates. -- [Robots.txt](https://devy1540.dev/robots.txt): Crawler access policy. +- [Korean RSS Feed](https://dev.devy.dev/rss.xml): Latest Korean posts. +- [English RSS Feed](https://dev.devy.dev/en/rss.xml): Latest English posts. +- [Sitemap](https://dev.devy.dev/sitemap.xml): Complete index of public pages and posts with language alternates. +- [Robots.txt](https://dev.devy.dev/robots.txt): Crawler access policy. ## Source And Build diff --git a/public/robots.txt b/public/robots.txt index 064afe7..6daa9c5 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,3 +1,3 @@ User-agent: * Allow: / -Sitemap: https://devy1540.dev/sitemap.xml +Sitemap: https://dev.devy.dev/sitemap.xml diff --git a/scripts/prerender.mjs b/scripts/prerender.mjs index 9398cbb..6e480fe 100644 --- a/scripts/prerender.mjs +++ b/scripts/prerender.mjs @@ -7,7 +7,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) const rootDir = path.resolve(__dirname, "..") const distDir = path.resolve(rootDir, "dist") const template = fs.readFileSync(path.resolve(distDir, "index.html"), "utf-8") -const baseUrl = "https://devy1540.dev" +const baseUrl = "https://dev.devy.dev" function escapeAttr(value) { return value diff --git a/scripts/sitemap-lastmod.test.mjs b/scripts/sitemap-lastmod.test.mjs index bd9c0e4..ae5de5b 100644 --- a/scripts/sitemap-lastmod.test.mjs +++ b/scripts/sitemap-lastmod.test.mjs @@ -5,7 +5,7 @@ import test from "node:test" import { fileURLToPath } from "node:url" const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..") -const baseUrl = "https://devy1540.dev" +const baseUrl = "https://dev.devy.dev" const today = new Date().toISOString().slice(0, 10) function frontmatterValue(raw, key) { diff --git a/src/components/ResumePdf.tsx b/src/components/ResumePdf.tsx index e01705f..cdd2325 100644 --- a/src/components/ResumePdf.tsx +++ b/src/components/ResumePdf.tsx @@ -249,7 +249,7 @@ export function ResumePdfDocument() { Blog - https://devy1540.dev + https://dev.devy.dev {PROJECTS.flatMap((p) => p.relatedLinks ?? []).map((link) => ( diff --git a/src/entry-server.tsx b/src/entry-server.tsx index 1b49a3b..0efd522 100644 --- a/src/entry-server.tsx +++ b/src/entry-server.tsx @@ -27,7 +27,7 @@ export interface PrerenderRoute { jsonLd?: Record } -const BASE_URL = "https://devy1540.dev" +const BASE_URL = "https://dev.devy.dev" const OG_IMAGE_URL = `${BASE_URL}/og-image.png?v=20260610` function markdownToText(md: string) { @@ -171,7 +171,7 @@ function localizedStaticRoutes(language: Language, posts: PostMeta[]): Prerender path: path("/privacy/"), language, title: isEnglish ? "Privacy Policy" : "개인정보처리방침", - description: isEnglish ? "Privacy policy for devy1540.dev." : "devy1540.dev의 개인정보처리방침입니다.", + description: isEnglish ? "Privacy policy for dev.devy.dev." : "dev.devy.dev의 개인정보처리방침입니다.", alternates: { ko: "/privacy/", en: "/en/privacy/", diff --git a/src/hooks/useMetaTags.ts b/src/hooks/useMetaTags.ts index 33281b4..8fccbf3 100644 --- a/src/hooks/useMetaTags.ts +++ b/src/hooks/useMetaTags.ts @@ -15,7 +15,7 @@ interface MetaTagsOptions { alternateUrls?: Partial> } -const BASE_URL = "https://devy1540.dev" +const BASE_URL = "https://dev.devy.dev" const OG_IMAGE_URL = `${BASE_URL}/og-image.png?v=20260610` const OG_IMAGE_ALT = "Devy Archive preview image" diff --git a/src/pages/PrivacyPage.tsx b/src/pages/PrivacyPage.tsx index a186d60..f6646d0 100644 --- a/src/pages/PrivacyPage.tsx +++ b/src/pages/PrivacyPage.tsx @@ -44,7 +44,7 @@ function getContent(language: Language, email: string): PrivacyContent { return { effectiveLabel: `Effective date: ${EFFECTIVE_DATE}`, intro: - "This Privacy Policy explains what information is collected and how it is processed when you use the services provided at devy1540.dev (the “Site”).", + "This Privacy Policy explains what information is collected and how it is processed when you use the services provided at dev.devy.dev (the “Site”).", sections: [ { heading: "1. Information we collect", @@ -111,7 +111,7 @@ function getContent(language: Language, email: string): PrivacyContent { return { effectiveLabel: "시행일: 2026년 6월 29일", intro: - "본 개인정보처리방침은 Devy(이하 ‘본 블로그’)가 devy1540.dev에서 제공하는 서비스 이용과 관련하여 수집하는 정보와 그 처리 방침을 안내합니다.", + "본 개인정보처리방침은 Devy(이하 ‘본 블로그’)가 dev.devy.dev에서 제공하는 서비스 이용과 관련하여 수집하는 정보와 그 처리 방침을 안내합니다.", sections: [ { heading: "1. 수집하는 정보", @@ -182,7 +182,7 @@ export function PrivacyPage() { useMetaTags({ title: t.common.privacy, - description: language === "en" ? "Privacy policy for devy1540.dev." : "devy1540.dev의 개인정보처리방침입니다.", + description: language === "en" ? "Privacy policy for dev.devy.dev." : "dev.devy.dev의 개인정보처리방침입니다.", url: localizePath("/privacy", language), }) diff --git a/vite.config.ts b/vite.config.ts index a331270..fd823e2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { defineConfig, type Plugin } from "vite" import react from "@vitejs/plugin-react" import { assertValidPostDates, getPostModifiedDate } from "./src/lib/post-dates" -const BASE_URL = "https://devy1540.dev" +const BASE_URL = "https://dev.devy.dev" const LANGUAGES = ["ko", "en"] as const type ContentLanguage = typeof LANGUAGES[number]