Genesis_GameServer
유니티 게임(Genesis) 서버 + 개인 포트폴리오 사이트.
하나의 ASP.NET Core 프로세스가 두 가지를 함께 서빙합니다.
| 경로 | 내용 |
|---|---|
/myGame/* |
유니티 게임 클라이언트가 쓰는 기존 API (변경 없음) |
/api/portfolio/* |
포트폴리오 REST API |
/ 그 밖의 모든 경로 |
포트폴리오 웹사이트 (정적 SPA) |
1. 처음 실행하기
관리자 비밀번호부터 바꾸세요
GameServer/appsettings.json 의 Portfolio.AdminPassword 가 CHANGE_ME 로 되어 있으면
로그인 자체가 막혀 있습니다(503). 원하는 비밀번호로 바꾸고 서버를 다시 시작하세요.
"Portfolio": {
"AdminPassword": "여기에-원하는-비밀번호",
"SiteTitle": "사이트 이름",
"SiteTagline": "한 줄 소개",
"MaxUploadBytes": 10485760
}
SiteTitle·SiteTagline은 지금 어느 코드도 읽지 않습니다. 화면에 나오는 이름과 문구는GameServer/wwwroot/index.html에 직접 들어 있습니다.
파일에 비밀번호를 두고 싶지 않다면 환경변수가 우선합니다.
# Windows (PowerShell)
$env:Portfolio__AdminPassword = "비밀번호"
# Linux / macOS
export Portfolio__AdminPassword="비밀번호"
실행
dotnet run --project GameServer/GameServer.csproj
브라우저에서 http://localhost:5281 을 열면 포트폴리오가 뜹니다.
우측 상단 관리자 버튼 → 비밀번호 입력 → 글을 쓸 수 있습니다.
이 프로젝트는
net9.0을 대상으로 합니다. .NET 9 런타임이 없고 상위 버전만 있다면DOTNET_ROLL_FORWARD=LatestMajor를 주고 실행하거나, .NET 9 런타임을 설치하세요.
2. 데이터베이스
포트폴리오 테이블은 서버가 시작할 때 자동으로 만들어집니다
(Data/PortfolioSchemaInitializer.cs, CREATE TABLE IF NOT EXISTS).
따로 마이그레이션을 돌릴 필요가 없습니다.
tb_portfolio_category— 카테고리 (처음 한 번게임 / 개발 / 아트 / 기록4개가 시드됩니다)tb_portfolio_post— 게시물tb_portfolio_post_image— 게시물 이미지
수동으로 만들고 싶다면 GameServer/sql/portfolio_schema.sql 을 쓰세요.
DB 연결이 실패해도 게임 서버 부팅은 막지 않습니다(로그만 남기고 넘어갑니다).
3. 화면
| 주소 | 화면 |
|---|---|
#/ |
작업 인덱스 (히어로 + 카테고리 필터 + 번호 매긴 목록) |
#/?cat=game |
카테고리로 걸러진 목록 |
#/post/12 |
게시물 상세 (마크다운 본문 + 이미지 갤러리 + 라이트박스) |
#/about |
소개 |
#/admin |
관리자 로그인 / 대시보드 |
#/admin/new |
새 글 |
#/admin/edit/12 |
글 수정 |
#/admin/categories |
카테고리 관리 |
글쓰기
본문은 마크다운입니다. 왼쪽에 쓰면 오른쪽에 바로 미리보기가 나옵니다.
이미지는 세 가지 방법으로 올립니다.
- 이미지 영역을 클릭해서 파일 고르기
- 파일을 끌어다 놓기
- 클립보드에서 Ctrl+V 로 붙여넣기
올린 이미지마다 세 개의 버튼이 있습니다.
- 대표 — 목록에서 커서를 따라 뜨는 썸네일과 상세 표지로 지정
- 본문삽입 — 커서 위치에
를 끼워 넣기 - 삭제 — 목록에서 빼기 (이번에 올린 파일이면 서버에서도 지웁니다)
저장하지 않고 페이지를 벗어나려 하면 경고가 뜹니다.
화면 구성
목록은 카드 그리드가 아니라 작품집 목차(인덱스) 형태입니다. 번호 → 제목 → 요약 → 카테고리 · 날짜 순으로 한 줄씩 늘어놓고, 행에 마우스를 올리면 행이 살짝 밀려 들어오면서 대표 이미지가 커서 옆에 떠오릅니다 (마우스가 있는 기기에서만. 터치 기기에서는 뜨지 않습니다).
배경 장식은 쓰지 않습니다. 위계는 글자 크기 대비와 얇은 괘선으로 만들고, 색은 카테고리 강조색으로만 들어옵니다. 한글은 산세리프, 숫자·라벨은 모노스페이스입니다.
카테고리 색은 #/admin/categories 에서 바꿀 수 있고, 그 색이 목록·상세·관리자 화면에
그대로 반영됩니다.
샘플 글 지우기
화면이 어떻게 보이는지 확인할 수 있도록 제목이 [샘플] 로 시작하는 글 5건을
자리표시 이미지와 함께 넣어 두었습니다. 직접 쓴 글이 아니니 지우고 시작하세요.
#/admin 에서 로그인한 뒤 각 줄의 삭제 를 누르면 됩니다.
글을 지워도 업로드된 자리표시 이미지 파일은 남으므로, 함께 비우려면
GameServer/wwwroot/uploads/ 아래 폴더를 통째로 지우면 됩니다
(.gitkeep 은 남겨 두세요).
소개 화면 내용 바꾸기
GameServer/wwwroot/js/views/about.js 의 ABOUT_MD 상수 하나만 고치면 됩니다.
빌드가 필요 없고 새로고침하면 바로 반영됩니다.
4. 구조
GameServer/
├─ Controllers/
│ ├─ CharacterController.cs 게임 API (기존)
│ ├─ UserController.cs 게임 API (기존)
│ └─ Portfolio/
│ ├─ PortfolioAuthController.cs 로그인 · 로그아웃 · 상태
│ ├─ PortfolioCategoryController.cs 카테고리 CRUD
│ ├─ PortfolioPostController.cs 게시물 CRUD
│ └─ PortfolioUploadController.cs 이미지 업로드 · 삭제
├─ Models/Portfolio/ 모델 + DTO
├─ Services/PortfolioAdminAuth.cs 관리자 비밀번호 검증
├─ Data/PortfolioSchemaInitializer.cs 테이블 자동 생성 + 시드
├─ sql/portfolio_schema.sql 참고용 DDL
└─ wwwroot/ 포트폴리오 사이트 (빌드 단계 없음)
├─ index.html
├─ css/style.css 디자인 시스템 한 파일
├─ js/
│ ├─ app.js 진입점 · 라우트 표
│ ├─ router.js 해시 라우터
│ ├─ api.js REST 래퍼
│ ├─ ui.js 토스트 · 모달 · 헬퍼
│ ├─ markdown.js 자체 제작 마크다운 렌더러
│ └─ views/ home · post · about · admin
└─ uploads/ 업로드된 이미지 (git 에서 제외됨)
프론트엔드에 빌드 단계가 없습니다. npm 도, 번들러도, 외부 CDN 요청도 없습니다.
배포는 그대로 dotnet publish 하나로 끝납니다.
5. 보안 메모
- 조회는 누구나, 작성 · 수정 · 삭제는 로그인한 관리자만 가능합니다 (쿠키 세션).
- 로그인은 IP별 5분에 8회로 제한됩니다.
- 업로드는 확장자뿐 아니라 매직 바이트까지 검사합니다. 파일명은 서버가 GUID 로 새로 짓습니다.
- 이미지 삭제는 경로를 절대경로로 해석해
uploads폴더 밖이면 거부합니다. - 마크다운은 먼저 escape 한 뒤 HTML 을 조립하므로 본문에 넣은 태그가 실행되지 않습니다.
링크는
http·https·mailto와 사이트 내부 경로만 허용합니다.
아직 남은 것
appsettings.json 에 DB 비밀번호가 평문으로 들어 있고 git 에 커밋돼 있습니다.
이 저장소를 공개할 계획이 있다면 연결 문자열을 환경변수
(ConnectionStrings__DefaultConnection)나 사용자 비밀로 옮기고,
노출된 DB 비밀번호를 교체하는 것을 권합니다.