Files
uniare.sori.studio/docs/spec.md
zenn dbf02241e2 v4.0.0: 회원·덱 API, 인증 UI, 프로필 및 레이아웃 통일
Express/SQLite API와 Docker 구성을 추가하고 로그인·덱 저장·공개 덱·관리자·프로필 화면을 구현했다. 결과 화면 저장 UX, 헤더 프로필, 애드센스용 app-shell 레이아웃(1280px) 및 문서를 반영했다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-22 16:59:36 +09:00

9.5 KiB
Raw Blame History

기술 명세

1. 프로젝트 개요

  • 프로젝트명: UADECK V4.0.0 - Union Arena Deck Builder
  • 형태: 정적 HTML/CSS/JavaScript 프론트 + Docker API 백엔드
  • 패키지 의존성 (프론트): tailwindcss, @tailwindcss/cli
  • 패키지 의존성 (API): express, better-sqlite3, bcryptjs, jsonwebtoken, cors
  • 빌드 산출 스타일: style/output.css

2. 화면 구조

/index.html

  • 시리즈 선택 랜딩 페이지다.
  • i18n/translations.<lang>.json을 직접 fetch하여 시리즈명과 소개 문구를 렌더링한다.
  • 사용자가 시리즈를 선택하면 cardList.html?series=<key>&seriesName=<name>&lang=<lang>로 이동한다.

/cardList.html

  • 특정 시리즈의 카드 목록을 보여주고 덱을 편집한다.
  • 쿼리스트링의 series 값을 기준으로 ./datas/${seriesKey}.js를 동적 import 한다.
  • 필터 기능:
  • 검색어
  • 색상(All, Red, Blue, Green, Yellow, Purple)
  • 시리즈 하위 그룹
  • 타입(Basic, AP, Parallel)
  • 트리거(All, Special, Color, Final)
  • 카드 수량 증감, 키 카드 지정, 초기화, 상세 오버레이, 결과 페이지 이동을 담당한다.

/result.html

  • 선택한 카드 목록을 미리보기하고 이미지로 저장한다.
  • 스타일 모드:
  • type1: 키 카드 강조형
  • type2: 클래식 5열형
  • html-to-image CDN을 사용해 덱 이미지를 PNG로 저장한다.

3. 데이터 구조

카드 데이터 파일

  • 위치: datas/*.js
  • 파일 수: 현재 52개
  • 각 파일은 export const cardList = [...] 형태를 사용한다.

카드 객체 스키마

{
    imgSrc: '/ua24/UA24BT_SHY-1-001.png',
    Number: 'UA24BT/SHY-1-001',
    count: 0,
    key: false,
    color: 'Red',
    parallel: false,
    rarity: 'C',
    trigger: null,
}

필드 의미

  • imgSrc: 원본 상대 식별자. 실제 렌더링 시 images/${seriesKey}/${fileName} 형태로 재구성한다.
  • Number: 카드 번호. 동일 카드 판본 묶음과 필터 기준으로 사용한다.
  • count: 현재 덱에 담긴 수량.
  • key: 키 카드 여부.
  • color: 카드 색상 또는 일부 특수 분류 값.
  • parallel: 패러렐 여부.
  • rarity: 희귀도 표기.
  • trigger: null, COLOR, FINAL, SPECIAL 등 트리거 정보.
  • maxCount: 일부 카드만 선택적으로 사용하며 기본값은 4로 동작한다.

4. 이미지 규칙

  • 기본 위치: images/<seriesKey>/
  • 저장 정책: images/**는 Git LFS 대상으로 관리한다.
  • 렌더링 규칙:
  • 카드 목록 화면: images/${seriesKey}/${fileName}
  • 결과 화면: /images/${seriesKey}/${fileName}
  • 폴백 이미지: /images/uapr/comingsoon.png
  • 현재 용량 현황:
  • images/ 약 1.7G
  • 이미지 파일 약 9,370개

5. 다국어

  • 지원 언어: ko, ja, en
  • 번역 파일:
  • i18n/translations.ko.json
  • i18n/translations.ja.json
  • i18n/translations.en.json
  • index.html은 번역 JSON을 직접 읽는다.
  • 공통 텍스트 치환은 i18n/i18n.js의 data-i18n 기반 로직을 사용한다.

6. 상태 저장

  • localStorage.lang: 현재 언어
  • localStorage.selectedCards: 편집 중인 덱 (임시, encodeURIComponent JSON)
  • localStorage.selectedSeries: 현재 시리즈 키
  • localStorage.uadeck_token / uadeck_user: 로그인 세션
  • 덱 공유·영구 저장: API + DB (GET /api/v1/decks/:shareCode)

7. 스타일 및 자산

  • Tailwind 유틸리티 클래스와 페이지별 인라인 스타일을 혼용한다.
  • 공통 스타일 파일:
  • style/output.css
  • style/style.css
  • style/navigation.css

8. 알려진 제약

  • cardList.html과 result.html의 스크립트가 페이지 내부에 크게 포함되어 있어 모듈 분리 전까지는 변경 영향 범위가 넓다.
  • script/navigation.js의 일부 이동 대상 페이지는 현재 저장소에 존재하지 않는다.
  • 이미지가 Git 일반 객체로 계속 누적되면 저장소 히스토리 크기가 지속 증가한다.

9. v4.0.0 계획 — 회원·덱 API·공유

상태: v4.0.0 1차 구현 완료 (2026-06-19)

9.1 아키텍처 개요

  • 프론트: 기존 정적 HTML/JS 유지. 헤더에 프로필·인증 UI 추가.
  • 백엔드: Docker 컨테이너 API 서버 (NAS 배포).
  • 카드 DB: datas/*.js + images/ 정적 유지 (변경 없음).
  • 사용자·덱 데이터: API + SQLite(또는 PostgreSQL) DB.
  • 외부 연동(옆 프로젝트): GET /api/v1/decks/:shareCode 단일 계약.

9.2 덱 공유 방식 (확정)

기존 ?cards=<JSON> URL 방식은 폐기한다. 공유는 공유 코드 + API만 사용한다.

종류 share_type 코드 생성 URL 예시 설명
개인 덱 user nanoid 8자 (저장마다 고유) /d/x7Kp9m2Q 같은 카드 구성이라도 저장자마다 URL이 다름
메타 덱·프리셋 preset 내용 해시 8자 (동일 구성 = 동일 URL) /d/a7f3b2c1 관리자 등록 공식 템플릿, 중복 저장 없음

브라우저 진입:

  • /d/:shareCode → cardList.html?d=:shareCode 리다이렉트 또는 동일 페이지에서 API 로드
  • cardList.html은 ?d= 파라미터가 있으면 API에서 덱 복원

9.3 DB 저장 vs API 응답

DB에 저장하는 최소 덱 본문 (cards_json):

[
  { "number": "UA36BT/MCR-1-052", "count": 4, "key": true },
  { "number": "EX14BT/MCR-2-011", "count": 2, "key": false }
]

API 응답 시 서버가 datas/<series>.js를 lookup하여 풀 카드 정보를 합성한다.

{
  "v": 1,
  "shareCode": "x7Kp9m2Q",
  "shareType": "user",
  "series": "ua36",
  "seriesName": "마크로스",
  "name": "블루 aggro",
  "totalCards": 50,
  "cards": [
    {
      "number": "UA36BT/MCR-1-052",
      "count": 4,
      "key": true,
      "imgSrc": "/ua36/UA36BT_MCR-1-052.png",
      "color": "Blue",
      "rarity": "SR",
      "trigger": null,
      "parallel": false
    }
  ],
  "author": {
    "id": 12,
    "displayName": "닉네임",
    "avatarUrl": "/uploads/avatars/12.png"
  },
  "createdAt": "2026-06-19T12:00:00Z",
  "updatedAt": "2026-06-19T14:30:00Z",
  "viewCount": 42,
  "isPublic": true
}

비회원 임시 공유: author는 null, expiresAt 필드로 만료 관리.

9.4 DB 스키마 (초안)

users

컬럼 타입 설명
id INTEGER PK
email TEXT UNIQUE 로그인 ID
username TEXT UNIQUE 표시용 닉네임
password_hash TEXT bcrypt
display_name TEXT 프로필 이름
avatar_url TEXT 프로필 썸네일
default_deck_public INTEGER 덱 저장 기본 공개 여부 (1=공개, 0=비공개)
skip_deck_public_prompt INTEGER 저장 시 공개 확인 생략 (1=생략)
role TEXT user | admin
is_active INTEGER 0=비활성, 1=활성
created_at TEXT 가입일
updated_at TEXT

decks

컬럼 타입 설명
id INTEGER PK
share_code TEXT UNIQUE URL에 쓰이는 8자 코드
share_type TEXT user | preset
content_hash TEXT preset 타입용. user 타입은 null 가능
user_id INTEGER FK null=비회원 임시 공유
series TEXT 예: ua36
name TEXT 덱 이름
cards_json TEXT [{number,count,key}] JSON
is_public INTEGER 0=비공개, 1=공개
view_count INTEGER 조회수
expires_at TEXT null=만료 없음
created_at TEXT 생성일
updated_at TEXT 최종 수정일

덱 1건 용량 추정: 카드 50장 × 약 60바이트 ≈ 3KB. 수만 건이어도 DB 부담은 경미하다.

9.5 API 엔드포인트 (초안)

인증

Method Path 설명
POST /api/v1/auth/register 회원가입
POST /api/v1/auth/login 로그인 → JWT
GET /api/v1/auth/me 내 정보
PUT /api/v1/auth/me 프로필 수정 (이메일, 사용자명, 아바타, defaultDeckPublic, skipDeckPublicPrompt)
POST /api/v1/auth/me/password 비밀번호 변경
GET /api/v1/auth/avatar/:userId 프로필 이미지 (PNG)

덱

Method Path 설명
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 비밀번호 초기화
POST /api/v1/admin/decks/preset 메타 덱(프리셋) 등록

9.6 프론트 변경 (예정)

  • script/auth-header.js: 헤더 프로필 드롭다운 (로그인/회원가입, 내 덱 관리)
  • login.html, signup.html, deckHistory.html, admin.html 신규
  • cardList.html: ?cards= 제거, ?d= API 로드로 전환
  • localStorage.selectedCards: 편집 중 임시 저장만 (공유와 분리)

9.7 배포

  • docker-compose.yml: API만 (기존 웹서버 사용 시)
  • docker-compose.prod.yml: Nginx + API 풀스택 (NAS 권장)
  • docs/deploy.md: NAS 배포 상세 가이드
  • docs/api-integration.md: 옆 프로젝트 연동 가이드
  • integrations/uadeck-deck-client.js: 연동용 JS 클라이언트
  • nginx/default.conf: /api/, /d/ 라우팅