앱 제작

최종 수정: 2026년 7월 3일

직접 만든 웹 앱을 Market App으로 마켓플레이스에 올리려면, 먼저 앱을 빌드해 그 산출물을 준비해야 합니다. 이 과정에는 HTML·JavaScript로 정적 사이트를 빌드하고, 명령줄에서 빌드 산출물을 확인하는 작업이 들어갑니다.

Market App은 마켓플레이스에 올려 다른 Space에 설치하는 앱입니다. 형태는 Web Hosting과 같은 정적 웹 앱입니다. 미리 빌드해 둔 화면 파일 묶음을 올려 두면, 방문자가 들어올 때 그 화면이 그대로 나타납니다.

보통의 웹 앱과 다른 점이 하나 있고, 그 때문에 빌드할 때 지켜야 하는 규칙이 하나 생깁니다. 이 페이지는 그 차이와 규칙, 그리고 올리기 전 검증을 다룹니다.

설치하면 리소스가 설치한 사람의 Space로 복사된다

Market App을 설치하면 앱 화면뿐 아니라, 게시할 때 함께 고른 리소스(Content Type, Content, Media 등)도 설치한 사람의 Space로 복사됩니다. 옷가게 상품 카탈로그 앱을 만들어 올렸다고 생각해 보세요. 누군가 그 앱을 설치하면, 앱 화면과 함께 상품 Content Type과 상품 Content가 그 사람의 Space로 복사되어 들어갑니다.

복사된 리소스는 설치한 Space에서 새 식별자를 받습니다. 콘텐츠를 읽는 데 쓰는 Delivery Access Token도 설치한 Space에 새로 만들어집니다. 그래서 설치된 앱은 제작자의 Space가 아니라, 설치한 사람의 Space에 복사된 자기 사본을 읽습니다. 설치가 끝나면 그 앱은 설치한 Space의 리소스만으로 동작합니다.

왜 접근 정보를 빌드에 박아 두는가

설치된 Market App에는 서버가 없습니다. Web Hosting과 같은 정적 호스팅이라 요청마다 화면을 계산해 주는 서버 런타임이 없고, 콘텐츠는 브라우저가 직접 WEEGLOO 전달 API(CDA, Content Delivery API)를 호출해 가져옵니다. 그래서 빌드 산출물(화면 파일) 안에는 어느 Space에서 무엇을, 어떤 자격값으로 읽을지가 글로 적혀 있어야 합니다.

문제는, 앞에서 본 것처럼 설치하면 리소스가 새 식별자로 복사된다는 점입니다. 빌드 파일에 적힌 값은 제작자 Space의 식별자와 토큰인데, 설치된 곳에서 읽어야 하는 것은 새로 복사된 사본입니다. 옛 값 그대로 두면 앱은 엉뚱한 곳을 가리킵니다.

그래서 WEEGLOO가 설치할 때 이 값들을 대신 바꿔 끼워 줍니다. 게시할 때 빌드 텍스트 안에서 제작자 Space의 식별자·토큰·리소스 식별자가 어디에 적혀 있는지 미리 찾아 두고, 설치할 때 그 자리를 설치한 Space 사본의 새 값으로 교체합니다. 덕분에 설치된 앱은 자동으로 설치한 Space를 가리키게 됩니다.

이 교체는 앱에 함께 담은 리소스에 대해서만 일어납니다. 그러니 화면이 읽어 오는 리소스(Content Type·Delivery Access Token 등)는 게시할 때 빠짐없이 함께 담아야 합니다. 빠뜨리면 그 식별자는 교체되지 않아 설치된 곳에서 엉뚱한 값으로 남습니다. 무엇을 함께 담아야 하는지는 앱 게시의 리소스 선택에서 다룹니다.

이 자동 교체에는 전제가 하나 있습니다. 값이 빌드 텍스트 안에 하나의 온전한 문자열로 그대로 들어 있어야 한다는 것입니다. 게시 단계가 그 문자열을 글자 그대로 찾아 위치를 기록하기 때문입니다. 값을 쪼개거나, 실행 중에 만들어 넣거나, 바깥에서 받아 오게 해 두면 게시 단계가 찾지 못하고, 그러면 설치할 때 교체도 일어나지 않아 설치된 앱이 동작하지 않습니다.

빌드에 박아 두는(그리고 설치할 때 교체되는) 값은 세 가지입니다.

  • 원본 Spacesys.id (spaceId): 어느 Space에서 읽을지.
  • 원본 SpaceDelivery Access Token: 그 Space의 발행된 콘텐츠를 읽을 수 있는 읽기 전용 자격값.
  • 앱이 참조하는 리소스들의 sys.id: 예를 들어 상품을 담은 Content Typesys.id 등, 클라이언트 코드가 가리키는 리소스 식별자.

값을 리터럴로 인라인하기

핵심은 위 세 값이 빌드 산출물 안에 하나의 온전한 문자열 리터럴(intact literal substring)로 나타나야 한다는 것입니다. 빌드된 텍스트 파일(JS·HTML·JSON 등)을 열었을 때, 값이 쪼개지거나 변형되지 않고 그대로 한 덩어리로 보여야 합니다. 그래야 게시 단계가 그 값을 찾아 위치를 기록하고, 설치 단계가 그 자리를 새 값으로 교체할 수 있습니다.

아래는 클라이언트 코드에 둔 설정의 예시입니다. 값은 형식만 보여 주는 예시이고, 실제 자격값으로 바꿔야 합니다.

// weegloo.config.js: 빌드 산출물에 이 값들이 그대로 실린다
export const WEEGLOO = {
  spaceId: "spc_xxxxxxxxxxxxxxxx",                 // 원본 Space의 sys.id
  deliveryAccessToken: "dat_xxxxxxxxxxxxxxxxxxxx",  // 원본 Space의 Delivery Access Token
  productContentTypeId: "ct_xxxxxxxxxxxx",          // 앱이 읽는 Content Type의 sys.id
};

브라우저는 이 값으로 CDA를 직접 호출합니다.

fetch(`https://cda.weegloo.com/v1/spaces/${WEEGLOO.spaceId}/contents`, {
  headers: { Authorization: `Bearer ${WEEGLOO.deliveryAccessToken}` },
});

다음과 같은 방식은 쓰면 안 됩니다. 모두 값이 빌드 산출물에 온전한 리터럴로 남지 않게 만들어, 게시 단계가 값을 찾지 못하게 합니다. 그러면 설치할 때 교체가 일어나지 않아, 설치된 앱이 제 Space의 사본을 읽지 못합니다.

  • 런타임 환경변수 조회. 설치된 앱에는 값을 주입할 서버나 런타임 환경이 없고, 빌드 텍스트에 값이 글자로 남지도 않습니다.

    // 안 됨: 설치된 곳에 이 환경변수가 존재하지 않는다
    deliveryAccessToken: process.env.DELIVERY_ACCESS_TOKEN
  • 런타임 fetch로 가져오기. 값을 어딘가에서 받아 오게 만들면, 빌드 텍스트에 값이 남지 않고 받아 올 곳도 없습니다.

  • 문자열 결합으로 쪼개기. 값이 한 덩어리로 나타나지 않아 게시 단계가 찾지 못합니다.

    // 안 됨: 산출물에 "dat_xxxxxxxxxxxxxxxxxxxx"가 하나의 substring으로 남지 않는다
    deliveryAccessToken: "dat_" + "xxxxxxxxxxxxxxxxxxxx"
  • 플레이스홀더로 두거나 빈칸으로 두기. 값을 채우는 일은 설치할 때 WEEGLOO가 해 줍니다. 그러나 그 교체는 빌드에 박힌 실제 값을 찾아 그 자리를 바꾸는 것이라, 빈칸이나 임시 표시로 두면 찾을 값이 없어 교체 대상이 되지 못합니다. 빌드 산출물을 만드는 시점에 실제 값이 글자 그대로 들어가 있어야 합니다.

값은 반드시 텍스트 파일(JS·HTML·JSON 등)에 두세요. 이미지·폰트 같은 바이너리 파일에 넣으면 안 됩니다. 값을 찾아 교체하는 일은 텍스트 파일에서만 일어납니다.

번들러도 확인 대상입니다. 일부 번들러는 문자열 리터럴을 최적화 과정에서 쪼개거나 변형합니다. 소스 코드만 보고 안심하지 말고, 실제 빌드 산출물을 열어 값이 온전한 리터럴로 남아 있는지 확인하세요(다음 절).

토큰은 최소권한으로 발급한다

빌드에 박는 Delivery Access Token은 브라우저에 그대로 노출됩니다. 설치한 누구든 앱의 빌드 파일에서 이 값을 볼 수 있습니다(설치 후 그 Space에 새로 만들어지는 토큰도 마찬가지로 노출됩니다). 그러므로 이 토큰은 앱이 실제로 읽어야 하는 Content Type 읽을 수 있는 최소권한 SpaceRole로 발급해야 합니다. Administrator 역할로 발급하지 마세요. 관리자 권한 토큰이 브라우저에 노출되면 원본 Space 전체가 위험해집니다.

최소권한 SpaceRole을 만들고 그 역할로 Delivery Access Token을 발급하는 방법은 토큰에서 다룹니다.

게시 전 검증

올리기 전에, 머릿속이 아니라 실제 빌드 산출물에서 값이 제대로 들어갔는지 확인하세요. 빌드된 폴더에서 원본 spaceId, 토큰, 리소스 sys.id를 각각 grep 해, 온전한 리터럴로 나오는지 봅니다.

grep -r "DATxxxxxxxxxxxxxxxx" dist/

찾으려는 값이 빌드 산출물 안에서 한 덩어리로(쪼개지거나 변형되지 않고) 나오면 됩니다. 박아 둔 세 값(spaceId, Delivery Access Token, 참조 리소스 sys.id) 모두에 대해 확인하세요. 하나라도 grep에 잡히지 않으면 게시 단계도 그 값을 찾지 못해, 설치할 때 교체되지 않습니다(번들러가 값을 변형했거나 런타임 조회로 빠진 것입니다). 그럴 때는 앞의 "값을 리터럴로 인라인하기"를 참고해 값이 온전한 리터럴로 남도록 고치세요.

정적 빌드 제약

Market App의 빌드 산출물은 Web Hosting과 같은 정적 제약을 따릅니다.

  • 서버 런타임이 없습니다. 정적 export로 빌드해야 합니다(SSR 없음).
  • 압축을 풀었을 때 파일이 100개 이하여야 합니다.
  • 묶음의 맨 위(루트)에 index.html이 있어야 합니다.
  • WEEGLOO API(CDA 등) 호출은 브라우저에서 직접 합니다.

자세한 정적 제약과 파일 묶음 규칙은 웹사이트 배포에서 다룹니다.

빌드한 화면은 App Bundle에 담깁니다

검증을 마친 빌드 산출물은 게시할 때 App Bundle(앱을 버전별로 묶은 꾸러미)에 담깁니다. 게시 화면에서 함께 고른 리소스도 같은 묶음에 담겨, 설치할 때 설치한 Space로 복사됩니다. 게시하고 버전을 올리는 절차는 앱 게시에서 다룹니다.

앱이 자체 회원을 받는다면

여기까지는 누구나 읽을 수 있는 공개 콘텐츠를 CDA로 읽어 오는 경우입니다. 만약 앱이 자체 회원 가입·로그인을 받는다면, ServiceLogin공식 클라이언트 SDK를 씁니다. 이 경우 브라우저는 CDA가 아니라 ACDA(App Content Delivery API)를 회원의 토큰으로 호출합니다. 설정과 연동 방법은 서비스 회원 로그인에서 다룹니다.

설치된 Market App의 인증 방식은 App Auth가, 설치된 앱에 접근 권한이 있는 사용자는 App Member가 다룹니다.

다음으로 할 일

  • 앱 게시: 만든 앱(App Bundle)을 마켓플레이스에 올리는 콘텐츠 스튜디오 절차를 다룹니다.
  • 웹사이트 배포: 정적 빌드, 파일 100개 제한, index.html 루트 같은 Web Hosting의 기본을 다룹니다.
  • 토큰: 빌드에 인라인할 Delivery Access Token을 최소권한 SpaceRole로 발급하는 방법을 다룹니다.
  • API 레퍼런스: 앱 화면이 콘텐츠를 불러올 때 호출하는 CDA(전달 API), 자체 회원을 받는 앱이라면 ACDA의 요청 형식 같은 기술 명세를 다룹니다.