sayren Docs

앱 만들기

코드를 올리면 sayren이 실행하는 앱 — 결제 알림 메일 앱을 만들어 상점에 설치하기까지

sayren 앱은 코드를 올리면 sayren이 빌드하고 실행하는 앱입니다. 서버를 따로 두지 않습니다. 주문이 결제되면 앱의 함수가 실행되고, 앱은 설치한 상점의 관리 API를 동의받은 권한 안에서 부릅니다. 어떤 권한을 쓰고 어디로 데이터를 보내는지는 설치할 때 셀러가 확인합니다.

이 가이드는 결제된 주문을 메일로 알리는 앱(order-mail)을 처음부터 만들어 상점에 설치하고 실제 결제로 메일을 받기까지 따라갑니다. 완성된 앱의 전체 코드는 GitHub avarcorp/sayren-apps에 있습니다.

npx sayren login                          # 1. Sayren 계정으로 로그인
npx sayren app init order-mail            # 2. 앱 폴더 만들기 + 앱 등록
cd order-mail && npm install
npx sayren app deploy -m "첫 버전"         # 4. 올리기 → 검사 → 버전 1
npx sayren app secret put RESEND_API_KEY  # 5. 비밀 값
npx sayren app release 1                  # 6. 버전 1을 현재 버전으로

개발자 포털 **developer.sayren.io**에서도 같은 일을 합니다 — 앱 만들기, 버전 release, 비밀 값, 앱 배포 키, 설치·로그 보기, 개발 상점 만들기. 터미널 흐름과 포털 흐름 중 편한 쪽을 쓰십시오.

이 가이드의 앱은 개발 중 앱이라 개발자가 소유자·관리자인 상점과 개발 상점에만 설치할 수 있습니다. 한 상점 전용으로 만들거나 모든 상점에 공개하려면 앱 공개 범위를 보십시오. 이 가이드는 이벤트를 받아 일하는 앱을 만듭니다. 상점 플랫폼 안에 화면을 띄우려면 앱 화면을 더합니다.

준비물

  • Sayren 계정. npx sayren login 또는 developer.sayren.io에서 로그인합니다
  • Node.js 20 이상
  • 테스트할 상점. 없으면 아래 개발 상점을 만듭니다
  • 이 예제는 메일을 Resend로 보냅니다. Resend API 키와 검증한 보내는 도메인이 필요합니다

1. 로그인

npx sayren login

브라우저에서 Sayren 계정으로 로그인합니다. CI처럼 사람이 없는 곳에서는 앱 배포 키를 씁니다.

2. 앱 폴더 만들기

npx sayren app init order-mail
cd order-mail && npm install

order-mail이 앱 handle입니다. 소문자·숫자·하이픈 3~40자이고 전 세계에서 하나뿐이어야 하며 바꿀 수 없습니다. 처음 실행하면 내 계정의 개발자 조직(개인)이 자동으로 만들어지고 앱이 등록됩니다. 포털에서 먼저 만든 앱이면 포털의 「CLI 연결」 안내를 따릅니다.

order-mail/
  manifest.json        앱 매니페스트 — 권한·이벤트·설정·비밀 값 이름
  package.json         @sayren/app 의존성
  src/server.ts        이벤트 함수
  README.md            상점 앱 상세에 보이는 설명
  icon.svg             앱 아이콘(선택, 매니페스트 icon에 적습니다)
  .env.example         로컬 실행의 설정·비밀 값 예시
  .sayren/app.json     등록된 앱 id(커밋하지 않습니다)

3. 매니페스트와 코드

매니페스트

앱이 무엇을 요청하는지 적습니다. 설치 화면에 보이는 내용이 모두 여기서 나옵니다.

manifest.json
{
  "handle": "order-mail",
  "name": "주문 메일 알림",
  "description": "결제된 주문을 메일로 알립니다",
  "icon": "icon.svg",
  "scopes": ["order:r"],
  "network": { "hosts": ["api.resend.com"] },
  "events": ["ORDER.PAID"],
  "settings": {
    "to": { "type": "string", "label": "받는 주소", "description": "결제 알림을 받을 메일 주소", "required": true },
    "from": { "type": "string", "label": "보내는 주소", "description": "Resend에서 검증한 도메인의 주소", "required": true }
  },
  "secrets": ["RESEND_API_KEY"]
}
키이 예제에서뜻
scopesorder:r주문을 읽습니다. 설치할 때 셀러가 동의합니다
network.hostsapi.resend.com앱 코드가 부를 수 있는 외부 호스트. 여기에 없는 곳으로는 요청이 나가지 않습니다
eventsORDER.PAID결제 완료 이벤트를 받습니다. 이벤트마다 필요한 권한이 있습니다(ORDER.*는 order:r)
settingsto·from셀러가 상점마다 채우는 값. 필수 값이 비면 이벤트가 오지 않습니다
secretsRESEND_API_KEY개발자가 앱에 한 번 넣는 비밀 값의 이름

전체 필드는 매니페스트를 참고하십시오.

앱 코드

src/server.ts
import { defineApp } from "@sayren/app";

export default defineApp({
  events: {
    "ORDER.PAID": async (event, ctx) => {
      // event.data는 ORDER.PAID의 모양(orderId 등)으로 좁혀집니다
      const order = await ctx.api.orders.get(event.data.orderId);
      const response = await fetch("https://api.resend.com/emails", {
        method: "POST",
        headers: {
          authorization: `Bearer ${ctx.secrets.RESEND_API_KEY}`,
          "content-type": "application/json",
        },
        body: JSON.stringify({
          from: ctx.settings.from,
          to: [ctx.settings.to],
          subject: `[${ctx.installation.storeName}] 주문 ${order.orderNo} 결제 완료`,
          text: `결제 금액: ${order.payment.totalAmount.toLocaleString("ko-KR")}원`,
        }),
      });
      // 예외를 던지면 실패로 기록되고 뒤에 다시 실행됩니다
      if (!response.ok) throw new Error(`Resend ${response.status}`);
      ctx.log.info("메일 보냄", order.orderNo);
    },
  },
});
  • ctx.api는 설치된 상점의 Store SDK 클라이언트입니다. 토큰을 넣을 필요가 없고 응답은 SDK 타입 그대로입니다. 주문 금액은 order.payment.totalAmount처럼 SDK 필드를 그대로 씁니다. 응답을 직접 만든 타입으로 캐스팅하지 마십시오.
  • ctx.settings는 셀러가 채운 설정, ctx.secrets는 개발자 비밀 값입니다.
  • fetch는 매니페스트 network.hosts와 sayren API에만 나갑니다.

npx tsc --noEmit으로 타입을 확인합니다(init이 tsconfig.json을 만듭니다). sayren은 타입 검사를 하지 않습니다. 상세는 앱 코드를 참고하십시오.

4. 올리기

npx sayren app deploy -m "첫 버전"

CLI가 src/server.ts를 한 파일로 번들하고 아이콘·README와 함께 올립니다. sayren은 의존성 검사 → 매니페스트 검증 → 번들 검사(크기·비밀 값 형식) → 업로드를 하고 버전 1을 만듭니다. 실패하면 단계·오류 코드·로그 꼬리를 보여 줍니다. 올리지 않고 검사만 하려면 npx sayren app verify입니다.

5. 비밀 값 넣기

npx sayren app secret put RESEND_API_KEY      # 값은 표준 입력으로 받습니다

비밀 값은 첫 deploy 뒤에 넣습니다. sayren이 올라간 버전의 매니페스트(secrets)로 이름을 확인하기 때문입니다. 값은 모든 설치의 다음 호출부터 전달되고 어디에도 다시 보이지 않습니다. 자세한 규칙은 설정과 비밀 값에 있습니다.

6. release

npx sayren app release 1

버전은 만들어도 바로 쓰이지 않습니다. 현재 버전으로 정해야 상점에 보이고 설치된 상점에서 실행됩니다. 권한·외부 호스트·이벤트가 늘어난 버전은 기존 설치에 곧바로 적용되지 않고 셀러의 재동의를 기다립니다(버전과 배포).

7. 상점에 설치하기

release한 앱은 내 상점의 상점 플랫폼 앱 › 앱 목록에 카드로 보입니다.

  1. 카드 → 앱 상세(README·Scope·Hook) → [설치]
  2. 설치 화면에서 권한(Scope)·데이터를 보내는 곳·이벤트(Hook)를 확인하고 설정 받는 주소·보내는 주소를 채웁니다
  3. **[설치]**를 누르면 앱 › 설치한 앱 › 주문 메일 알림으로 이동합니다

developer.sayren.io **› {앱} › [내 상점에 설치]**로도 설치할 수 있습니다. 셀러 쪽 화면은 앱 설치와 관리에 있습니다.

8. 확인하기

상점에서 주문을 결제하면(개발 상점은 테스트 결제) ORDER.PAID 함수가 실행되고 메일이 옵니다. 실행 결과는 세 곳에서 봅니다.

npx sayren app logs --tail
  • 개발자: sayren app logs 또는 developer.sayren.io › {앱} › 로그 — 호출별 결과·소요 시간·console.log·ctx.log 출력·예외(7일 보관)
  • 셀러: 상점 플랫폼 앱 › {앱} › 실행 기록 — 이벤트별 성공·실패·재시도·설정 필요. 로그 본문은 보이지 않습니다

메일이 오지 않으면 아래를 차례로 봅니다.

증상확인할 것
실행 기록에 「설정 필요」설치한 앱의 설정에서 필수 값을 채웁니다
로그에 비밀 값 … 없습니다류 예외sayren app secret list로 이름을 확인하고 secret put을 다시 합니다
로그에 OUTBOUND_BLOCKED부른 호스트가 매니페스트 network.hosts에 없습니다
로그에 403 INSUFFICIENT_SCOPE부른 API의 권한이 scopes에 없습니다
실행 기록이 계속 「재시도 대기」앱 코드 예외입니다. 로그에서 원인을 고쳐 새 버전을 release합니다. 24시간 동안 모든 호출이 실패하면 앱이 자동 정지됩니다

9. 고치고 다시 올리기

npx sayren app deploy -m "제목에 금액 추가"     # 버전 2
npx sayren app release 2                          # 모든 설치에 곧바로 적용

실패한 이벤트는 재시도 때 그 시점의 현재 버전으로 실행됩니다. 되돌릴 때는 npx sayren app release 1입니다.

로컬에서 실행하기

올리기 전에 내 컴퓨터에서 이벤트 함수를 돌려 볼 수 있습니다. 설정·비밀 값은 .env에서 읽습니다.

# .env
SAYREN_APP_SETTING_to=ops@example.com
SAYREN_APP_SETTING_from=알림 <noreply@example.com>
SAYREN_APP_SECRET_RESEND_API_KEY=re_…
npx sayren app dev --store store_abc123                    # 로컬 실행(포트 4020)
npx sayren app trigger ORDER.PAID --order ord_01J…         # 다른 터미널 — 실제 주문으로 이벤트 함수 실행

--store는 앱을 설치한 상점(내가 소유자·관리자)이어야 하고 ctx.api가 그 상점의 실제 데이터를 읽습니다.

로컬 실행도 실제 상점의 관리 API를 부릅니다. 쓰기 권한(order:rw 등)이 있으면 실제 데이터가 바뀝니다. 개발 상점에서 테스트하십시오.

개발 상점

실결제 없이 앱을 테스트하는 상점입니다. 테스트 결제만 되고 실결제를 열 수 없습니다. 개발자당 5개까지이고 일반 상점 소유 한도와 따로 셉니다.

npx sayren app dev-store create "알림 앱 테스트"

developer.sayren.io › 개발 상점에서도 만듭니다. 개발 상점은 보통 상점과 같이 상품·주문·결제(테스트)를 다룰 수 있습니다.

앱 배포 키

CI처럼 사람이 로그인하지 않는 곳에서 deploy·release·status·logs·secret을 돌리려면 앱 배포 키를 씁니다. developer.sayren.io › {앱} › 키에서 발행하고(값은 만들 때 한 번만 보입니다) SAYREN_APP_KEY 환경 변수나 --key로 줍니다.

SAYREN_APP_KEY=sak_… npx sayren app deploy -m "$GIT_COMMIT"
SAYREN_APP_KEY=sak_… npx sayren app release 3

키는 발행한 앱의 명령에만 쓰입니다. 앱 만들기·개발 상점·설치는 계정 로그인이 필요합니다. 키가 샜으면 포털에서 폐기하고 새로 발행합니다.

명령 모음

명령하는 일
sayren app init <handle>앱 폴더와 매니페스트·예제 코드 만들기. 앱 등록까지 합니다
sayren app dev [--store <storeId>] [--port 4020]로컬 실행
sayren app trigger <이벤트> [--order <id>] [--data <json>]로컬 실행 중인 앱에 이벤트 보내기
sayren app verify매니페스트·코드 검사만(올리지 않음)
sayren app deploy [-m <메모>]올리기 → 빌드 → 버전 만들기
sayren app release <버전 번호>그 버전을 현재 버전으로
sayren app status앱·현재 버전·설치 수·최근 빌드
sayren app logs [--tail] [--since 1h] [--store <storeId>]실행 로그
sayren app secret put <이름> · list · delete <이름>개발자 비밀 값(값은 표준 입력으로 받습니다)
sayren app dev-store create <이름> · list개발 상점

모든 명령은 앱 폴더(manifest.json이 있는 폴더)에서 실행합니다. 다른 폴더면 --dir을 줍니다. 인증은 --key·SAYREN_APP_KEY(앱 배포 키) → --token·SAYREN_TOKEN → npx sayren login 순서입니다.

다음 단계

이 페이지 목차