refactor: portfolio → personal 리네이밍 + Blog/Todo 통합

- portfolio/ 디렉토리를 personal/로 리네이밍
- lotto-backend의 Blog/Todo 라우트·CRUD를 personal 서비스로 이전
- lotto-backend에서 Blog/Todo 코드 제거 (DB 테이블 스키마는 유지)
- nginx: /api/todos, /api/blog/ 라우팅을 personal로 추가
- docker-compose: portfolio → personal 서비스 변��
- deploy 스크립트: portfolio → personal 반영

데이터 마이그레이션은 배포 후 NAS에서 별도 수행 필요:
1. cp data/portfolio/portfolio.db data/personal/personal.db
2. sqlite3 data/lotto.db ".dump todos" | sqlite3 data/personal/personal.db
3. sqlite3 data/lotto.db ".dump blog_posts" | sqlite3 data/personal/personal.db

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-27 16:32:55 +09:00
parent 6004bcf66d
commit e3d5eaf6f3
15 changed files with 516 additions and 263 deletions

118
personal/app/models.py Normal file
View File

@@ -0,0 +1,118 @@
from typing import Optional, List
from pydantic import BaseModel
class ProfileUpdate(BaseModel):
name: Optional[str] = None
name_en: Optional[str] = None
role: Optional[str] = None
role_en: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
github_url: Optional[str] = None
blog_url: Optional[str] = None
photo_url: Optional[str] = None
bio: Optional[str] = None
class CareerCreate(BaseModel):
category: str = "company"
organization: str = ""
role: str = ""
description: str = ""
start_date: str = ""
end_date: str = ""
sort_order: int = 0
class CareerUpdate(BaseModel):
category: Optional[str] = None
organization: Optional[str] = None
role: Optional[str] = None
description: Optional[str] = None
start_date: Optional[str] = None
end_date: Optional[str] = None
sort_order: Optional[int] = None
class ProjectCreate(BaseModel):
category: str = "personal"
title: str = ""
description: str = ""
tech_stack: List[str] = []
role: str = ""
start_date: str = ""
end_date: str = ""
url: str = ""
image_url: str = ""
sort_order: int = 0
class ProjectUpdate(BaseModel):
category: Optional[str] = None
title: Optional[str] = None
description: Optional[str] = None
tech_stack: Optional[List[str]] = None
role: Optional[str] = None
start_date: Optional[str] = None
end_date: Optional[str] = None
url: Optional[str] = None
image_url: Optional[str] = None
sort_order: Optional[int] = None
class SkillCreate(BaseModel):
category: str = "language"
name: str = ""
level: int = 3
sort_order: int = 0
class SkillUpdate(BaseModel):
category: Optional[str] = None
name: Optional[str] = None
level: Optional[int] = None
sort_order: Optional[int] = None
class IntroCreate(BaseModel):
title: str = ""
content: str = ""
is_main: int = 0
class IntroUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
class AuthRequest(BaseModel):
password: str
class TodoCreate(BaseModel):
title: str
description: Optional[str] = None
status: str = "todo"
class TodoUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
status: Optional[str] = None
class BlogPostCreate(BaseModel):
title: str
body: str = ""
excerpt: str = ""
tags: List[str] = []
date: str = ""
class BlogPostUpdate(BaseModel):
title: Optional[str] = None
body: Optional[str] = None
excerpt: Optional[str] = None
tags: Optional[List[str]] = None
date: Optional[str] = None