기술 명세
프로젝트 개요
- 서비스명:
UNIARE - Union Arena Deck Builder
- 현재 버전:
v4.0.1
- 프론트: 정적 HTML, CSS, JavaScript
- 백엔드: Express, SQLite(
better-sqlite3)
- 운영: Docker Compose 기반 Nginx + API
- 지원 언어: 한국어, 일본어, 영어
- 표시 브랜드는
UNIARE이며 UaDeckApi, uadeck_token, uadeck.db 등 내부 레거시 식별자는 호환을 위해 유지한다.
화면 기능
| 경로 |
기능 |
/ |
시리즈 선택, 언어 전환, 인증 헤더 |
/cardList.html?series=<key> |
카드 검색·필터, 수량 조절, 키 카드 지정, 덱 편집 |
/cardList.html?d=<shareCode> |
API 공유 덱 불러오기 및 편집 |
/result.html |
덱 미리보기, PNG 다운로드, 덱 저장 |
/login.html |
로그인 |
/signup.html |
회원가입 |
/profile.html |
이메일·사용자명·아바타·비밀번호·덱 공개 기본값 관리 |
/deckHistory.html |
내 덱 검색·필터·이름 변경·공개 설정·삭제·불러오기 |
/preset.html |
공개 사용자 덱 검색·필터·즐겨찾기·불러오기 |
/admin.html |
회원과 덱 관리 |
/d/<shareCode> |
Nginx에서 cardList.html?d=<shareCode>로 연결 |
카드 데이터
- 데이터 위치:
datas/*.js
- 실제 시리즈 데이터:
ua01~ua54 중 현재 존재하는 파일과 uapr.js
- 샘플 데이터:
ua99 sample.js, ua99 sample mini.js
- 모듈 형식:
export const cardList = [...]
Number가 같은 판본은 동일 카드 수량 그룹으로 처리한다.
parallel은 패러렐 판본 구분에 사용한다.
trigger는 null, COLOR, FINAL, SPECIAL 값을 사용한다.
maxCount가 없으면 기본 최대 수량은 4장이다.
이미지
- 카드 이미지:
images/<seriesKey>/<fileName>
- 폴백 이미지:
/images/uapr/comingsoon.png
- 브랜드 자산:
images/assets/
images/**는 Git LFS로 관리한다.
- 아바타와 덱 미리보기는 API 데이터 디렉터리에 저장하며 Git에 포함하지 않는다.
- 덱 저장 미리보기는 1200px 기준 PNG로 정규화한다.
브라우저 상태
| 키 |
용도 |
lang |
선택 언어 |
selectedCards |
편집 중인 덱 |
selectedSeries |
현재 시리즈 |
uadeck_token |
JWT |
uadeck_user |
로그인 사용자 캐시 |
| 덱 즐겨찾기 키 |
공유 코드 기반 로컬 즐겨찾기 |
인증 및 권한
- 비밀번호는 bcrypt 비용 12로 해시한다.
- JWT 기본 만료는 7일이며
JWT_EXPIRES로 변경할 수 있다.
user는 자신의 프로필과 덱만 수정·삭제할 수 있다.
admin은 회원 상태·역할·비밀번호와 전체 덱을 관리할 수 있다.
- 관리자는 자신의 관리자 역할을 해제하거나 자신의 계정을 비활성화할 수 없다.
- 비공개 덱은 소유자와 관리자만 조회할 수 있다.
덱 저장 정책
- 공유 코드는 저장 시 생성되는 8자 코드다.
- 회원 덱은 만료 없이 저장하며 공개 여부를 선택할 수 있다.
- 비회원 덱은 공개 상태로 저장되고 30일 뒤 만료된다.
- DB의
cards_json에는 {number, count, key}만 저장한다.
- API 응답 시
datas/<series>.js에서 이미지·색상·희귀도·트리거 정보를 합성한다.
- 공개 덱 목록은
share_type='user', is_public=1, 미만료 조건을 사용한다.
preset 타입과 관리자 프리셋 API는 레거시 호환용으로 코드에 남아 있으며 현재 공개 덱 화면에서는 사용하지 않는다.
데이터베이스
users
| 컬럼 |
설명 |
id |
기본 키 |
email, username |
고유 로그인·표시 식별자 |
password_hash |
bcrypt 해시 |
display_name |
레거시 표시명, 현재 username과 함께 갱신 |
avatar_url |
아바타 API 경로 |
role |
user 또는 admin |
is_active |
계정 활성 상태 |
default_deck_public |
덱 저장 기본 공개 여부 |
skip_deck_public_prompt |
저장 시 공개 확인 생략 여부 |
created_at, updated_at |
생성·수정 시각 |
decks
| 컬럼 |
설명 |
share_code |
고유 공유 코드 |
share_type |
user 또는 레거시 preset |
content_hash |
레거시 프리셋 중복 판별 |
user_id |
소유 회원, 비회원은 null |
series, series_name |
시리즈 키와 표시명 |
name |
덱 이름 |
cards_json |
최소 카드 구성 JSON |
is_public |
공개 여부 |
view_count |
상세 조회 횟수 |
expires_at |
비회원 공유 만료 시각 |
preview_image |
저장된 미리보기 파일 정보 |
created_at, updated_at |
생성·수정 시각 |
API
공통
| Method |
Path |
권한 |
기능 |
| GET |
/api/v1/health |
공개 |
API 상태와 버전 |
인증
| Method |
Path |
권한 |
기능 |
| POST |
/api/v1/auth/register |
공개 |
회원가입 |
| POST |
/api/v1/auth/login |
공개 |
로그인과 JWT 발급 |
| GET |
/api/v1/auth/me |
회원 |
내 정보 |
| PUT |
/api/v1/auth/me |
회원 |
프로필·덱 저장 설정 변경 |
| POST |
/api/v1/auth/me/password |
회원 |
비밀번호 변경 |
| GET |
/api/v1/auth/avatar/:userId |
공개 |
PNG 아바타 |
덱
| Method |
Path |
권한 |
기능 |
| GET |
/api/v1/decks/presets |
공개 |
공개 사용자 덱 목록 |
| GET |
/api/v1/decks/:shareCode/preview |
공개 |
덱 미리보기 PNG |
| GET |
/api/v1/decks/:shareCode |
조건부 |
공개 덱 또는 소유 덱 상세 |
| GET |
/api/v1/decks |
회원 |
내 덱 목록 |
| POST |
/api/v1/decks |
공개 |
회원 또는 비회원 덱 저장 |
| PUT |
/api/v1/decks/:shareCode |
소유자·관리자 |
덱 수정 |
| DELETE |
/api/v1/decks/:shareCode |
소유자·관리자 |
덱 삭제 |
관리자
| Method |
Path |
기능 |
| GET |
/api/v1/admin/users |
회원 목록·검색 |
| GET |
/api/v1/admin/users/:id |
회원 상세 |
| PUT |
/api/v1/admin/users/:id |
회원 정보·역할·활성 상태 변경 |
| POST |
/api/v1/admin/users/:id/reset-password |
비밀번호 초기화 |
| GET |
/api/v1/admin/decks |
전체 덱 목록 |
| DELETE |
/api/v1/admin/decks/:shareCode |
덱 삭제 |
| POST |
/api/v1/admin/decks/preset |
레거시 프리셋 생성 |
스타일
- 현재는 Tailwind 유틸리티, 공통 CSS, 페이지 전용 CSS, 일부 인라인 스타일을 혼용한다.
- 이번 단계에서는 기존 CSS를 Tailwind로 일괄 전환하지 않는다.
style/output.css는 style/input.css에서 생성하는 빌드 산출물이다.
- 헤더 로고 크기는
style/brand.css만 기준으로 사용한다.
- 기본 글꼴은 Pretendard 계열을 우선 사용한다.
알려진 제약
cardList.html, result.html의 인라인 스크립트가 커서 변경 영향 범위가 넓다.
admin.html은 3개 언어 번역 적용이 완료되지 않았다.
- 즐겨찾기는 브라우저별 로컬 상태라 계정 간 동기화되지 않는다.
- Homepage 전용
GET /api/homepage 엔드포인트는 아직 구현되지 않았다.
- 현재 Compose의 컨테이너명(
uniare-api, uniare-web)과 데이터 볼륨명(uniare-data)은 고정값이며 환경 변수화되지 않았다.