9.7 KiB
9.7 KiB
기술 명세
현재 아키텍처
- 프런트엔드: Vue 3 + Vite + Pinia + Vue Router
- 백엔드: Express 5
- 데이터 저장소: MariaDB(MySQL 호환)
- 세션 저장소:
session-file-store기반 파일 세션 - 업로드 저장소: 로컬 파일 시스템(
backend/uploads/) - 운영 배포:
frontend(Nginx 정적 서빙 + /api,/uploads 프록시) + backend + mariadbDocker Compose 구조 - NAS HTTPS 리버스 프록시 운영 시 프런트 Nginx는 백엔드로
X-Forwarded-Proto: https를 전달하고, Express 세션은 프록시 환경에서secure쿠키를 허용하도록 설정한다. - 프런트 파비콘은 운영 정적 파일 차단 영향을 줄이기 위해
index.html의 인라인 데이터 URL로 제공한다.
데이터 저장 구조
- 메인 데이터베이스: MariaDB
tier_cursor(기본값) - 세션 파일:
backend/.sessions/*.json - 업로드 파일:
- 게임 이미지:
backend/uploads/games/ - 아바타:
backend/uploads/avatars/ - 커스텀 아이템:
backend/uploads/custom/ - 시드 이미지:
backend/uploads/seeds/
- 게임 이미지:
DB 스키마
usersid: stringemail: stringnickname: stringpasswordHash: stringisAdmin: booleanavatarSrc: stringcreatedAt: number
gamesid: stringname: stringthumbnailSrc: stringcreatedAt: number- 시스템 전용
freeform레코드는 홈 화면의직접 티어표 만들기저장 대상이며 일반 게임 목록에서는 숨긴다.
gameItemsid: stringgameId: stringsrc: stringlabel: stringcreatedAt: number
customItemsid: stringownerId: stringsrc: stringlabel: stringcreatedAt: number
tierListsid: stringauthorId: stringgameId: stringtitle: stringthumbnailSrc: stringdescription: stringisPublic: booleangroups:{ id, name, itemIds[] }[]pool:{ id, src, label, origin }[]createdAt: numberupdatedAt: number
gameSuggestionsid: stringname: stringcreatedAt: number
주요 API
- 인증
POST /api/auth/signupPOST /api/auth/loginPOST /api/auth/logoutGET /api/auth/meGET /api/auth/metaPOST /api/auth/profile
- 게임
GET /api/gamesGET /api/games/:gameId
- 티어표
GET /api/tierlists/publicGET /api/tierlists/meGET /api/tierlists/:idDELETE /api/tierlists/:idPOST /api/tierlists/thumbnailPOST /api/tierlists/custom-itemsPOST /api/tierlists
- 관리자
POST /api/admin/gamesPOST /api/admin/games/:gameId/thumbnailPOST /api/admin/games/:gameId/images- 여러 이미지를 한 번에 업로드할 수 있고, 별도 라벨이 없으면 파일명 기준으로 기본 아이템 이름을 만든다.
PATCH /api/admin/games/:gameId/items/:itemIdGET /api/admin/tierlistsPOST /api/admin/tierlists/:tierListId/promote-itemsPOST /api/admin/tierlists/:tierListId/create-game-templateGET /api/admin/custom-itemsPOST /api/admin/custom-items/:itemId/promoteDELETE /api/admin/custom-items/:itemIdDELETE /api/admin/custom-itemsGET /api/admin/usersPATCH /api/admin/users/:userIdPATCH /api/admin/users/:userId/passwordDELETE /api/admin/users/:userIdDELETE /api/admin/games/:gameId/items/:itemIdDELETE /api/admin/games/:gameId
관리자 화면 메모
- 썸네일은 16:9 비율 미리보기 후
썸네일 적용버튼으로 실제 반영한다. - 게임 기본 아이템 추가는 드래그 앤 드롭 또는 다중 파일 선택으로 처리하고, 미리보기 카드에서 여러 장을 함께 확인할 수 있다.
- 현재 기본 아이템 목록에서는 등록된 아이템 이름을 직접 수정하고 저장할 수 있다.
- 기본 아이템 이름 저장 버튼은 값이 실제로 바뀐 경우에만 활성화된다.
- 아이템 미리보기는 반응형 환경에서도 최대
192px크기 안에서 표시한다. - 게임 전환 또는 업로드 성공 뒤에는 파일 입력값을 초기화해 같은 파일도 다시 선택할 수 있다.
- 게임 관리 탭에서는 홈 화면 상단에 먼저 노출할 게임을 최대 50개까지 지정하고, 드래그 또는 위/아래 버튼으로 순서를 저장할 수 있다.
- 사용자 업로드 커스텀 아이템은 관리자 화면의 아이템 관리 탭에서 검색, 페이지네이션, 다운로드할 수 있다.
- 사용자 커스텀 아이템은 선택한 게임의 기본 템플릿으로 복제해 가져올 수 있다.
- 커스텀 아이템은 사용 횟수(
usageCount)를 표시하며, 미사용 항목만 필터링해 개별/일괄 삭제할 수 있다. - 관리자 화면에는 별도
티어표 관리탭이 있으며, 최근 티어표 전체를 제목/게임/작성자 기준으로 검색하고 공개 여부를 함께 확인할 수 있다. 티어표 관리탭에서는 티어표 안의 커스텀 아이템을 개별 또는 일괄로 기존 게임 템플릿에 복제할 수 있다.freeform티어표는 관리자 화면에서 새 게임 ID/이름을 입력해 새로운 게임 템플릿으로 복제 생성할 수 있다.- 관리자 화면에서는 회원 이메일/닉네임/권한 수정, 비밀번호 초기화, 계정 삭제가 가능하다.
티어표 접근 메모
new작성 경로는 로그인한 사용자만 진입할 수 있다.- 비로그인 사용자는 공개된 티어표를 열람만 할 수 있고, 편집 UI와 저장 동작은 비활성화된다.
- 비공개 티어표라도 관리자는 편집 화면에서 완성본을 열람할 수 있다.
- 커스텀 이미지 추가는 다중 파일 선택과 드래그 앤 드롭을 모두 지원한다.
- 티어 행은 기본 5단으로 시작하지만, 사용자가 직접 추가하거나 제거할 수 있다.
- 신규 티어표의 공개 여부 기본값은
ON이며, 기존 티어표는 편집 화면과내 티어표목록에서 직접 삭제할 수 있다. - 제목이 비어 있는 상태로 저장하면 내부 제목은 현재 게임명을 기본값으로 사용한다.
- 제목 입력이 비어 있는 동안에는 무분별한 도배 방지를 위한 관리자 임의 삭제 가능성 안내 문구를 표시한다.
- 티어표는 편집 화면에서 16:9 썸네일 이미지를 별도로 선택해 저장할 수 있고, 목록 카드에서는 그 이미지를 상단 대표 썸네일로 사용한다.
- 편집 화면 상단 헤더는 좌측 제목/설명, 우측 썸네일 카드 구조를 사용하며 모바일에서는 한 열로 접힌다.
- 티어표 편집기의 아이콘 기본 크기는
80px이며, 사용자가48 / 60 / 80 / 100 / 120단계로 즉시 조절할 수 있다. - 공개 티어표 목록과
내 티어표목록은 제목 옆에 작성자 아바타와 표시명을 함께 보여준다. - 작성자 아바타 이미지가 없을 경우 목록 썸네일 fallback은 닉네임이 아니라 계정명 기준 첫 글자를 사용한다.
- 티어표 목록 메타 정보는 최종 업데이트 시각만 간략하게 표시한다.
- 저장 성공 시에는 에디터 안에서 반투명 오버레이 기반 확인 모달을 띄우고, PNG export 이미지는 약
960px보드 폭과pixelRatio 1.5, 외곽 여백, 작성자/날짜 하단 메타를 포함해 생성한다. - 홈 게임 목록은 관리자 상단 고정 순서가 있으면 그 순서를 먼저 적용하고, 그 외 게임은 최근 생성순으로 뒤에 이어진다.
커스텀 티어표 만들기는 카드가 아니라 홈 우측 상단 버튼으로 진입한다.
업로드 제한 메모
- 프로필 아바타 업로드는 파일당 최대
3MB다. - 관리자 게임 썸네일/기본 아이템 업로드와 사용자 커스텀 이미지 업로드는 파일당 최대
6MB다. - 현재는 업로드 전에 이미지 리사이즈/압축을 하지 않고 원본 파일을 그대로 저장한다.
운영 환경 변수
- 프런트엔드
VITE_API_ORIGIN: API 및 업로드 파일 절대 기준 주소
- 백엔드
DB_HOST: MariaDB 호스트DB_PORT: MariaDB 포트DB_USER: MariaDB 계정DB_PASSWORD: MariaDB 비밀번호DB_NAME: 데이터베이스명PORT: 서버 포트SESSION_SECRET: 세션 서명 키CORS_ORIGINS: 허용할 프런트 도메인 목록(쉼표 구분)TRUST_PROXY: 프록시 홉 수SESSION_COOKIE_SECURE:true면 HTTPS 전용 쿠키SESSION_COOKIE_SAME_SITE: 기본lax
운영 배포 메모
- 프로덕션 컴포즈 파일은 docker-compose.prod.yml이다.
- 외부 도메인
tmaker.sori.studio는frontend컨테이너의18080포트로 리버스 프록시하고,/api,/uploads,/health는 프런트 Nginx가 내부backend:5179로 전달한다. - 운영 볼륨은 MariaDB 데이터, 업로드 파일, 세션 파일을 각각 분리해 유지한다.
- MariaDB healthcheck는 NAS 첫 기동 지연을 고려해
root기준 ping과 긴start_period/retries를 사용한다.
NAS 배포 메모
- 현재 구조는 MariaDB/MySQL 계열이므로 NAS에 MariaDB를 올리면 phpMyAdmin 또는 Adminer로 직접 데이터 확인이 가능하다.
- 추천 구성:
- MariaDB 컨테이너 또는 NAS 패키지 설치
- phpMyAdmin 또는 Adminer 설치
- 앱은 환경변수로 해당 DB에 연결
로컬 개발 기준
- 기본 로컬 개발도
docker compose로 띄운 MariaDB를 사용한다. - 기본 백엔드 실행 스크립트
backend/package.json의dev,start는 로컬 MariaDB(127.0.0.1:3307) 기준으로 맞춰져 있다. backend/src/db.js는 MariaDB만 대상으로 동작하며, 파일 기반 fallback은 제거되었다.