목차
- 01인증면 구분
- 02Base URL과 환경변수
- 03API Key 발급 흐름
- 04Asset 업로드 요청
- 05업로드 처리 흐름
- 06Asset key 규칙
- 07응답 필드와 재접근 URL
- 08상태 조회와 status 의미
- 09Asset 목록/상세/삭제
- 10헬스체크
- 11에러 처리
1. 인증면 구분
Dashboard API
브라우저 대시보드가 프로젝트, API Key, Asset 목록을 관리할 때 사용합니다. Cognito Hosted UI 로그인 후 받은 JWT를 Bearer token으로 보냅니다.
Authorization: Bearer {cognito_jwt}Developer API
외부 백엔드/서버 애플리케이션이 파일을 업로드하거나 조회할 때 사용합니다. raw API Key는 Dashboard 브라우저 요청에 사용하지 않습니다.
X-OneAsset-Api-Key: {raw_api_key}2. Base URL과 환경변수
프론트는 `NEXT_PUBLIC_API_BASE_URL`을 기준으로 Dashboard API를 호출합니다. Developer API를 호출하는 외부 서버도 같은 백엔드 origin을 사용하되, 인증 헤더만 `X-OneAsset-Api-Key`로 바꿉니다.
| Surface | 환경변수 | 설명 |
|---|---|---|
| Frontend | NEXT_PUBLIC_API_BASE_URL | 대시보드가 호출할 백엔드 origin. 로컬 기본값은 http://localhost:8080. |
| Backend | APP_PORT | Spring Boot 서버 포트. 로컬 Docker 실행 기준 8080. |
| Backend | ONEASSET_DELIVERY_BASE_URL | deliveryUrl 계산에 쓰는 CDN/base URL. 비어 있으면 응답 deliveryUrl은 null. |
3. API Key 발급 흐름
- 01Dashboard에서 Google/Cognito로 로그인합니다.
- 02POST /api/projects로 프로젝트를 생성합니다.
- 03POST /api/projects/{projectId}/api-keys로 API Key를 발급합니다.
- 04응답의 apiKey raw value는 발급 직후 한 번만 복사합니다.
- 05이후 목록에서는 raw key가 아니라 prefix/status만 확인합니다.
4. Asset 업로드 요청
실제 컨트롤러는 `POST /v1/assets`에서 multipart/form-data를 받습니다. `file`은 필수이고, `key`, `fileName`은 선택입니다.
curl -X POST https://api.oneasset.example/v1/assets \ -H "X-OneAsset-Api-Key: oa_live_..." \ -F "file=@hero.png" \ -F "key=products/main/hero.png" \ -F "fileName=hero.png"
| Field | Required | 설명 |
|---|---|---|
| file | Y | 업로드할 원본 파일. multipart part 이름은 file. |
| key | N | 사용자/앱이 다시 조회할 논리 경로. 없으면 서버가 assets/{uuid}.{ext} 형태로 생성. |
| fileName | N | 표시용 원본 파일명. 없으면 multipart original filename 사용. 현재 백엔드 파라미터명은 name이 아니라 fileName. |
Node.js 서버 예시
raw API Key는 브라우저에 노출하지 않고 서버 환경변수로 관리합니다. 아래 예시는 외부 백엔드에서 OneAsset Developer API로 전달하는 형태입니다.
const form = new FormData();
form.append("file", fileBlob, "hero.png");
form.append("key", "products/main/hero.png");
form.append("fileName", "hero.png");
const response = await fetch(`${process.env.ONEASSET_API_URL}/v1/assets`, {
method: "POST",
headers: {
"X-OneAsset-Api-Key": process.env.ONEASSET_API_KEY,
},
body: form,
});
const result = await response.json();
const asset = result.data;
// 실제 이미지 재접근에는 asset.deliveryUrl을 사용합니다.
console.log(asset.deliveryUrl);5. 업로드 처리 흐름
| Step | 무엇을 하나 | 설명 |
|---|---|---|
| 1 | 외부 서버가 raw API Key를 준비합니다. | Dashboard에서 발급 직후 한 번만 보이는 `oa_live_...` 값을 서버 환경변수에 저장합니다. |
| 2 | multipart/form-data로 파일을 보냅니다. | `file`은 필수입니다. `key`는 사용자가 다시 찾을 논리 경로이고, `fileName`은 표시용 이름입니다. |
| 3 | 백엔드는 S3 storageKey를 만듭니다. | `projects/{projectId}/{key}` 형태로 저장합니다. 사용자는 이 값을 직접 만들 필요가 없습니다. |
| 4 | 응답의 deliveryUrl을 저장하거나 노출합니다. | 이미지 재접근, img src, CDN 전달에는 `deliveryUrl`을 씁니다. key/storageKey는 식별과 조회용입니다. |
| 5 | PROCESSING이면 상세 API를 다시 조회합니다. | `GET /v1/assets?key={key}`로 status가 READY가 될 때까지 polling합니다. |
6. Asset key 규칙
허용되는 형태
- `users/123/profile.png`
- `products/iphone/main.png`
- `assets/manual-upload.png`
정규화/거부 규칙
- 앞의 `/`는 제거됩니다.
- `\`는 `/`로 바뀝니다.
- 빈 segment, `.`, `..`는 `COMMON_INVALID_INPUT_400`입니다.
- `key`를 생략하면 서버가 `assets/{uuid}.{ext}` 논리 key를 생성합니다.
7. 응답 필드와 재접근 URL
응답의 `key`는 사용자 논리 경로이고, `storageKey`는 S3 내부 경로입니다. 재접근 URL은 `deliveryUrl`을 사용합니다. 백엔드 환경변수 `ONEASSET_DELIVERY_BASE_URL`이 비어 있으면 `deliveryUrl`은 null입니다.
{
"success": true,
"data": {
"assetId": "f88dcad8-020c-4ed5-bda9-6c078e52a819",
"key": "products/main/hero.png",
"storageKey": "projects/{projectId}/products/main/hero.png",
"originalFileName": "hero.png",
"contentType": "image/png",
"sizeBytes": 125432,
"status": "PROCESSING",
"deliveryUrl": "https://cdn.example.com/projects/{projectId}/products/main/hero.png",
"createdAt": "2026-07-21T17:10:00"
},
"error": null
}| Field | 설명 |
|---|---|
| assetId | Asset UUID. Dashboard 내부 링크와 식별에 사용. |
| key | 사용자가 다루는 논리 경로. 예: users/123/profile.png |
| storageKey | S3 내부 저장 경로. 예: projects/{projectId}/users/123/profile.png |
| originalFileName | 표시용 원본 파일명. 경로가 들어오면 마지막 파일명만 사용. |
| contentType | 업로드 파일 MIME type. |
| sizeBytes | 원본 파일 크기. 0 이하이면 ASSET_INVALID_SIZE_400. |
| status | UPLOADED, PROCESSING, READY, FAILED 중 하나. |
| deliveryUrl | ONEASSET_DELIVERY_BASE_URL이 설정되어 있으면 storageKey를 붙여 계산한 재접근 URL. 설정이 없으면 null. |
| createdAt | Asset metadata 생성 시각. |
어떤 값을 저장해야 하나
- `key`: 이후 상세 조회, 삭제, 트리 렌더링에 사용합니다.
- `deliveryUrl`: 실제 이미지 접근 URL로 사용합니다.
- `storageKey`: 운영/디버깅용 내부 저장 경로로만 취급합니다.
- `deliveryUrl`이 null이면 백엔드 CDN/base URL 설정이 비어 있는 상태입니다. 이 경우 프론트는 URL 복사 버튼을 숨깁니다.
8. 상태 조회와 status 의미
현재 실제 상태 조회는 별도 `/status` path가 아니라`GET /v1/assets?key={key}`입니다. 같은 endpoint가 상세 metadata와 status를 함께 반환합니다.
curl "https://api.oneasset.example/v1/assets?key=products/main/hero.png" \ -H "X-OneAsset-Api-Key: oa_live_..."
| Status | 의미 | 클라이언트 처리 |
|---|---|---|
| UPLOADED | 원본 업로드와 metadata 생성이 완료된 도메인 초기 상태입니다. | 현재 register 흐름에서는 곧바로 PROCESSING으로 전환되어 응답에서 보기 어려울 수 있습니다. |
| PROCESSING | 원본이 저장되고 처리 큐에 등록된 상태입니다. | GET /v1/assets?key={key}를 주기적으로 재조회합니다. UI에서는 처리 중으로 표시합니다. |
| READY | Lambda callback으로 변환본 metadata가 등록되고 Asset이 준비된 상태입니다. | deliveryUrl을 사용할 수 있는 상태로 안내하고 URL 복사 액션을 제공합니다. |
| FAILED | 처리 실패 상태입니다. | 사용자에게 실패를 명확히 보여주고 파일/contentType 확인 후 재업로드를 안내합니다. 현재 확인한 컨트롤러에는 실패 callback API가 아직 노출되어 있지 않습니다. |
polling 예시
업로드 응답이 `PROCESSING`이면 같은 `key`로 상세 API를 재조회합니다. `READY`가 되면 `deliveryUrl`을 화면에 보여주고, `FAILED`면 재업로드 안내를 표시합니다.
async function waitUntilReady(key) {
for (let attempt = 0; attempt < 10; attempt += 1) {
const res = await fetch(
`${process.env.ONEASSET_API_URL}/v1/assets?key=${encodeURIComponent(key)}`,
{ headers: { "X-OneAsset-Api-Key": process.env.ONEASSET_API_KEY } },
);
const { data } = await res.json();
if (data.status === "READY") return data.deliveryUrl;
if (data.status === "FAILED") throw new Error("Asset processing failed.");
await new Promise((resolve) => setTimeout(resolve, 1500));
}
throw new Error("Asset is still processing.");
}9. Asset 목록, 상세, 삭제
목록
API Key가 속한 프로젝트의 active asset 목록을 반환합니다.
GET /v1/assets X-OneAsset-Api-Key: oa_live_...
상세/상태
논리 key로 asset metadata, status, deliveryUrl을 조회합니다.
GET /v1/assets?key=products/main/hero.png X-OneAsset-Api-Key: oa_live_...
삭제
S3 object 삭제 후 DB row는 soft delete 처리됩니다. CloudFront 캐시는 잠시 남을 수 있습니다.
DELETE /v1/assets?key=products/main/hero.png X-OneAsset-Api-Key: oa_live_...
목록 응답으로 트리 만들기
백엔드는 folder/tree 구조를 만들지 않고 flat list를 반환합니다. 프론트는 응답의 `key`를 `/` 기준으로 split해서 Asset Browser tree를 렌더링합니다.
[
{ "key": "users/123/profile.png", "status": "READY" },
{ "key": "users/123/banner.png", "status": "READY" },
{ "key": "products/iphone/main.png", "status": "PROCESSING" }
]
users
123
profile.png
banner.png
products
iphone
main.png10. 헬스체크
백엔드 SecurityConfig 기준 `/actuator/health`는 인증 없이 허용됩니다. 배포/모니터링에서는 이 endpoint로 API 프로세스와 actuator 상태를 확인합니다.
curl https://api.oneasset.example/actuator/health
// typical Spring Boot response
{
"status": "UP"
}11. Dashboard API 엔드포인트
| Method | Path | 설명 |
|---|---|---|
| GET | /api/me | Cognito JWT 사용자 동기화와 현재 사용자 조회 |
| POST | /api/projects | 프로젝트 생성 |
| GET | /api/projects | 내 프로젝트 목록 조회 |
| GET | /api/projects/{projectId} | 프로젝트 상세 조회 |
| POST | /api/projects/{projectId}/api-keys | API Key 발급 |
| GET | /api/projects/{projectId}/api-keys | API Key 목록 조회. raw key는 포함하지 않음 |
| DELETE | /api/projects/{projectId}/api-keys/{apiKeyId} | API Key 폐기 |
| GET | /api/projects/{projectId}/assets | Asset 목록 조회 |
| GET | /api/projects/{projectId}/assets?key={key} | Asset 상세/상태 조회 |
| DELETE | /api/projects/{projectId}/assets?key={key} | Asset 삭제 |
12. Developer API 엔드포인트
| Method | Path | 설명 |
|---|---|---|
| POST | /v1/assets | multipart/form-data로 Asset 업로드 |
| GET | /v1/assets | API Key가 속한 프로젝트의 Asset 목록 조회 |
| GET | /v1/assets?key={key} | 논리 key로 Asset 상세/상태 조회 |
| DELETE | /v1/assets?key={key} | 논리 key로 Asset 삭제 |
13. 에러 처리
OneAsset API는 `success: false`와 `error.code`를 내려줍니다. 프론트는 code/status를 기준으로 inline error, page error, retry, login redirect로 변환합니다.
에러 코드 레퍼런스 보기