17 KiB
17 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로 제공한다. - 프런트 앱 셸은
좌측 내비게이션 / 중앙 워크스페이스 / 우측 컨텍스트 패널3단 구조로 재정의되었고, preview 모드에서는 이 셸을 숨기고 콘텐츠만 렌더링한다. - 좌측 패널은
248px, 우측 패널은320px기준 폭을 사용하며, 우측 패널은 상단 토글 버튼으로 접고 펼칠 수 있다. - 이 3단 셸 구조는 홈, 게임 허브, 에디터, 관리자 등 일반 페이지 전반의 공통 뼈대로 유지하고, 페이지별 차이는 중앙/우측에 어떤 콘텐츠를 넣는지만 달라지도록 관리한다.
- 비로그인 상태의 로그인 유도는 좌측 하단 버튼으로만 노출하고, 좌측 상단 사용자 카드 영역에는 별도 게스트 안내 카드를 렌더링하지 않는다.
- 공통 셸의 좌측 내비, 우측 패널, 빠른 점프 버튼은 간단한 선형 SVG 아이콘과 두꺼운 카드형 버튼 문법을 공유한다.
데이터 저장 구조
- 메인 데이터베이스: MariaDB
tier_cursor(기본값) - 세션 파일:
backend/.sessions/*.json - 업로드 파일:
- 게임 이미지:
backend/uploads/games/ - 아바타:
backend/uploads/avatars/ - 커스텀 아이템:
backend/uploads/custom/ - 시드 이미지:
backend/uploads/seeds/
- 게임 이미지:
화면 구조
- 좌측 패널
- 사용자 요약, 전체 공개 티어표 검색 입력, 주요 라우트 내비게이션, 최근 즐겨찾기 티어표 바로가기, 관리자 진입 버튼을 배치한다.
Settings는 별도 메뉴 항목으로만 진입하며, 사용자 카드 자체는 정보 표시 용도로만 사용한다.Favorites영역은 최근 즐겨찾기 티어표 최대 10개를 바로 보여주고, 하단즐겨찾기 더 보기링크로 전체 즐겨찾기 화면에 연결한다.
- 중앙 워크스페이스
- 현재 라우트의 핵심 콘텐츠를 렌더링하는 영역이며, 홈/목록 계열 화면은 카드형 대시보드 레이아웃을 우선 적용한다.
- 홈, 게임 허브, 내 티어표, 즐겨찾기 화면은 같은 카드 문법(상단 16:9 썸네일, 제목, 작성자/보조 메타, 하단 상태 영역)을 공유하도록 정리한다.
- 목록 계열 화면의 상단 도구 영역은 통계 카드와 액션 버튼을 공통 높이/반경으로 맞춰, 같은 라이브러리 대시보드로 읽히도록 정리한다.
- 우측 패널
- 현재 화면 문맥에 맞는 설명, 빠른 액션, 계정 상태 같은 보조 정보를 배치한다.
- 에디터/관리자 세부 옵션은 후속 단계에서 이 패널로 점진 이관한다.
- 공통 토글 버튼으로 패널을 접으면 중앙 워크스페이스가 남는 공간을 확장 사용한다.
- 홈 화면 기준 우측 패널은 임시 정보 카드 여러 개보다 핵심 CTA 하나만 남겨, 시안처럼 단순한 보조 레일 역할을 우선 유지한다.
- 티어표 편집 화면
- 공통 우측 패널 대신 전용 로컬 편집 패널을 사용한다.
- 공통
workspaceBody카드 컨테이너를 벗기고, 중앙 보드 영역은 메인 컬럼에, 우측320px편집 패널은 공통 셸의 세 번째 컬럼 aside에 배치한다. - 공통 상단 토글 버튼은 Teleport로 이동한 로컬 편집 패널의 접힘/펼침 상태와도 연결되어, 우측 패널을 숨기면 중앙 보드 영역이 확장된다.
- 제목, 설명, 대표 썸네일, 공개 여부, 저장/삭제/요청 액션을 우측 로컬 패널에 배치한다.
- 보드 바로 옆에는 드래그용 아이템 풀을 별도 패널로 두고, 커스텀 아이템 이름 정리 목록은 우측 편집 패널 내부에서 관리한다.
- 관리자 화면
- 공통 우측 패널 대신 전용 로컬 운영 패널을 사용한다.
- 공통
workspaceBody카드 컨테이너를 벗기고, 중앙 관리 목록은 메인 컬럼에, 우측 운영 패널은 공통 셸의 세 번째 컬럼 aside에 배치한다. - 우측 로컬 패널에는
게임/아이템/티어표/회원 관리탭, 검색, 필터, 새로고침, 빠른 작업 제어를 배치하고, 중앙 영역에는 실제 관리 대상 목록과 상세만 렌더링한다. - 상단 헤더에는 현재 탭 기준 요약 통계 카드를 배치해 운영 상태를 먼저 읽고, 각 관리 카드는 공통 대시보드 카드 문법(두꺼운 반경, 얕은 레이어 배경, 강조된 액션 버튼)을 공유한다.
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: string- 사용자가 직접 지정하지 않으면 저장 시 티어표 대표 아이템 이미지로 자동 채운다.
description: stringisPublic: booleangroups:{ id, name, itemIds[] }[]pool:{ id, src, label, origin }[]createdAt: numberupdatedAt: number
favoriteTierListsuserId: stringtierListId: stringcreatedAt: 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/publicgameId없이q만 전달하면 전체 공개 티어표 검색에 사용한다.
GET /api/tierlists/meGET /api/tierlists/favorites/meGET /api/tierlists/:idPOST /api/tierlists/:id/template-requestPOST /api/tierlists/:id/favoriteDELETE /api/tierlists/:id/favoriteDELETE /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/tierlistsGET /api/admin/template-requestsPOST /api/admin/template-requests/:requestId/approvePOST /api/admin/template-requests/:requestId/rejectPOST /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)를 표시하며, 미사용 항목만 필터링해 개별/일괄 삭제할 수 있다. - 관리자 화면에는 별도
티어표 관리탭이 있으며, 내부에서템플릿 요청 관리 / 전체 티어표 관리를 분리해 볼 수 있고, 확인용 완성본은 탐색 UI 없는 preview 전용 모달로 연다. 티어표 관리탭의 추가 아이템은 작은 그리드 카드로 표시하고, 클릭 시기존 템플릿에 추가 / 새 템플릿 만들기모달을 통해 목적지를 선택한다.티어표 관리탭에서는 티어표 안의 커스텀 아이템을 개별 또는 일괄로 기존 게임 템플릿에 복제할 수 있다.freeform티어표는 관리자 화면에서 새 게임 ID/이름을 입력해 새로운 게임 템플릿으로 복제 생성할 수 있다.- 관리자 티어표 관리 상단에는 사용자가 보낸 템플릿 등록/업데이트 요청 목록이 별도로 표시되며, 여기서 승인/반려를 바로 처리할 수 있다.
- 관리자 템플릿 요청 목록에서
반려 후 숨김을 누르면 해당 요청은 pending 목록에서 즉시 제외된다. - 관리자 화면에서는 회원 이메일/닉네임/권한 수정, 비밀번호 초기화, 계정 삭제가 가능하다.
- 회원 관리 카드에는 아바타, 작성 티어표 수, 최근 활동 시각을 함께 표시한다.
티어표 접근 메모
new작성 경로는 로그인한 사용자만 진입할 수 있다.- 비로그인 사용자는 공개된 티어표를 열람만 할 수 있고, 편집 UI와 저장 동작은 비활성화된다.
- 비공개 티어표라도 관리자는 편집 화면에서 완성본을 열람할 수 있다.
- 공개 티어표는 목록과 상세 화면에서 즐겨찾기 토글 및 개수를 함께 표시한다.
- 카드형 목록에서는 즐겨찾기 수/상태만 표시하고, 실제 토글은 상세 화면에서 처리한다.
- 공개 티어표 목록은 현재 게임 기준으로 제목/작성자 검색을 지원한다.
내 즐겨찾기화면에서는 즐겨찾기한 순, 최신 업데이트순, 인기순 정렬을 제공한다.- 커스텀 이미지 추가는 다중 파일 선택과 드래그 앤 드롭을 모두 지원한다.
- 사용자가 직접 추가한 커스텀 아이템 이름은 편집 화면 우측 목록에서 정리할 수 있고, 저장 시 원본 커스텀 아이템 라벨과 함께 동기화된다.
- 티어 행은 기본 5단으로 시작하지만, 사용자가 직접 추가하거나 제거할 수 있다.
- 티어 행에 넣은 아이템은 작은 제거 버튼으로 다시 우측 아이템 풀로 되돌릴 수 있다.
- 신규 티어표의 공개 여부 기본값은
ON이며, 기존 티어표는 편집 화면과내 티어표목록에서 직접 삭제할 수 있다. - 제목이 비어 있는 상태로 저장하면 내부 제목은 현재 게임명을 기본값으로 사용한다.
- 제목 입력이 비어 있는 동안에는 무분별한 도배 방지를 위한 관리자 임의 삭제 가능성 안내 문구를 표시한다.
freeform티어표는 커스텀 아이템이 준비된 상태에서템플릿 등록 요청을 보낼 수 있다.템플릿 등록 요청전에는 체크리스트 모달로제목 직접 입력여부를 확인하고, 관리자가 식별하기 쉬운 게임 이름을 입력하도록 안내한다.- 신규 티어표를 막 저장한 직후에도, 템플릿 요청은 새로 발급된 실제 티어표 ID를 기준으로 이어서 처리한다.
- 기존 게임 티어표는 커스텀 아이템이 포함되어 있으면
템플릿 업데이트 요청을 보낼 수 있다. - 티어표는 편집 화면에서 16:9 썸네일 이미지를 별도로 선택해 저장할 수 있고, 목록 카드에서는 그 이미지를 상단 대표 썸네일로 사용한다.
- 티어표에 썸네일을 직접 지정하지 않으면 저장 시 대표 아이템 이미지 하나를 기본 썸네일로 자동 선택한다.
- 편집 화면 상단 헤더는 좌측 제목/설명, 우측 썸네일 카드 구조를 사용하며 모바일에서는 한 열로 접힌다.
- 티어표 편집 화면의 우측 패널은 공통
rightRail의localRightRailRoot에 직접 section들을 쌓는 구조이며, 별도 외곽 래퍼 카드 없이 공통 오른쪽 컬럼 문법을 그대로 따른다. - 공통 앱 셸은 좌측/중앙/우측 컬럼마다 높이
56px의 상단 헤더 블록을 유지하며, 중앙 헤더에는 고정 사이트 타이틀Tier Maker by zenn을 표시한다. - 티어표 편집기의 아이콘 기본 크기는
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은 제거되었다.