v4.0.0: 회원·덱 API, 인증 UI, 프로필 및 레이아웃 통일
Express/SQLite API와 Docker 구성을 추가하고 로그인·덱 저장·공개 덱·관리자·프로필 화면을 구현했다. 결과 화면 저장 UX, 헤더 프로필, 애드센스용 app-shell 레이아웃(1280px) 및 문서를 반영했다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
174
docs/api-integration.md
Normal file
174
docs/api-integration.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# 옆 프로젝트 API 연동 가이드
|
||||
|
||||
UADECK v4부터 덱 데이터는 **공유 코드 + REST API**로 제공합니다.
|
||||
URL 쿼리(`?cards=`) 방식은 사용하지 않습니다.
|
||||
|
||||
## 공식 엔드포인트
|
||||
|
||||
```http
|
||||
GET https://uniare.sori.studio/api/v1/decks/:shareCode
|
||||
```
|
||||
|
||||
### 응답 예시
|
||||
|
||||
```json
|
||||
{
|
||||
"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": 1,
|
||||
"displayName": "닉네임",
|
||||
"avatarUrl": null
|
||||
},
|
||||
"createdAt": "2026-06-19T12:00:00Z",
|
||||
"updatedAt": "2026-06-19T12:00:00Z",
|
||||
"viewCount": 42,
|
||||
"isPublic": true
|
||||
}
|
||||
```
|
||||
|
||||
## shareCode 얻는 방법
|
||||
|
||||
| 방법 | 예시 |
|
||||
|---|---|
|
||||
| UADECK 공유 버튼 | `https://uniare.sori.studio/d/x7Kp9m2Q` |
|
||||
| URL 파라미터 | `cardList.html?d=x7Kp9m2Q` |
|
||||
| 코드만 | `x7Kp9m2Q` |
|
||||
|
||||
## 클라이언트 라이브러리
|
||||
|
||||
프로젝트에 포함된 파일:
|
||||
|
||||
```
|
||||
integrations/uadeck-deck-client.js
|
||||
```
|
||||
|
||||
### 브라우저
|
||||
|
||||
```html
|
||||
<script src="https://uniare.sori.studio/integrations/uadeck-deck-client.js"></script>
|
||||
<script>
|
||||
const client = new UaDeckDeckClient({
|
||||
baseUrl: 'https://uniare.sori.studio/api/v1',
|
||||
imageBase: 'https://uniare.sori.studio',
|
||||
});
|
||||
|
||||
// 공유 링크에서 덱 로드
|
||||
const deck = await client.fetchFromUrl('https://uniare.sori.studio/d/x7Kp9m2Q');
|
||||
|
||||
deck.cards.forEach((card) => {
|
||||
console.log(card.number, card.count, card.imageUrl);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Node.js / ESM
|
||||
|
||||
```javascript
|
||||
import { UaDeckDeckClient } from './integrations/uadeck-deck-client.js';
|
||||
|
||||
const client = new UaDeckDeckClient({
|
||||
baseUrl: 'https://uniare.sori.studio/api/v1',
|
||||
});
|
||||
|
||||
const deck = await client.fetchDeck('x7Kp9m2Q');
|
||||
```
|
||||
|
||||
### fetch 직접 사용
|
||||
|
||||
```javascript
|
||||
const res = await fetch('https://uniare.sori.studio/api/v1/decks/x7Kp9m2Q');
|
||||
const deck = await res.json();
|
||||
|
||||
if (!res.ok) throw new Error(deck.error);
|
||||
```
|
||||
|
||||
## 이미지 URL 규칙
|
||||
|
||||
API의 `imgSrc`는 상대 경로입니다. 전체 URL:
|
||||
|
||||
```
|
||||
https://uniare.sori.studio/images{imgSrc}
|
||||
```
|
||||
|
||||
예: `imgSrc: "/ua36/UA36BT_MCR-1-052.png"`
|
||||
→ `https://uniare.sori.studio/images/ua36/UA36BT_MCR-1-052.png`
|
||||
|
||||
`UaDeckDeckClient`는 `card.imageUrl`에 자동 변환합니다.
|
||||
|
||||
## CORS
|
||||
|
||||
다른 도메인에서 브라우저 `fetch`를 쓰려면 UADECK 서버 `.env`의 `CORS_ORIGINS`에 해당 origin을 추가하세요.
|
||||
|
||||
```
|
||||
CORS_ORIGINS=https://your-app.sori.studio,https://uniare.sori.studio
|
||||
```
|
||||
|
||||
서버 간 호출(Node, Python 등)은 CORS가 필요 없습니다.
|
||||
|
||||
## 마이그레이션 (기존 ?cards= 코드)
|
||||
|
||||
**Before (폐기):**
|
||||
|
||||
```javascript
|
||||
const params = new URLSearchParams(location.search);
|
||||
const cards = JSON.parse(decodeURIComponent(params.get('cards')));
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```javascript
|
||||
const code = UaDeckDeckClient.parseShareCode(location.href)
|
||||
|| new URLSearchParams(location.search).get('d');
|
||||
|
||||
const client = new UaDeckDeckClient({ baseUrl: '/api/v1' });
|
||||
const deck = await client.fetchDeck(code);
|
||||
const cards = deck.cards;
|
||||
```
|
||||
|
||||
## 프리셋(메타 덱) 목록
|
||||
|
||||
```http
|
||||
GET /api/v1/decks/presets
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": [
|
||||
{
|
||||
"share_code": "a7f3b2c1",
|
||||
"series": "ua36",
|
||||
"series_name": "마크로스",
|
||||
"name": "공식 블루 템플릿",
|
||||
"view_count": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
프리셋도 동일하게 `GET /decks/:shareCode`로 상세 조회합니다.
|
||||
|
||||
## 에러 코드
|
||||
|
||||
| HTTP | 의미 |
|
||||
|---|---|
|
||||
| 404 | shareCode 없음 |
|
||||
| 403 | 비공개 덱 |
|
||||
| 410 | 만료된 임시 공유 (비회원 30일) |
|
||||
Reference in New Issue
Block a user