상점 플랫폼 앱 화면
ui/ 폴더로 만드는 앱 화면, 세션과 HTTP 핸들러 호출, 상점 플랫폼과의 연결(알림·이동)
매니페스트에 ui.adminPage를 적으면 상점 플랫폼 **앱 › {앱}**에 앱 화면이 생깁니다. 화면은 ui/ 폴더의 정적 파일(HTML·JS·CSS)이고
sayren이 앱 주소 https://{handle}.apps.sayren.app에서 서빙합니다. 상점 플랫폼은 이 주소를 격리된 프레임으로 엽니다.
ui/
index.html 매니페스트 ui.adminPage.entry
main.js @sayren/app/ui로 세션을 받고 HTTP 핸들러를 부른다ui/는 정적 파일 그대로 올라갑니다. sayren이 빌드하지 않습니다. ui/index.html이 진입이고 그 안에서
<script type="module" src="./main.js">처럼 코드를 가져옵니다. TypeScript·React·Vue를 쓰려면 자기 도구(Vite 등)로 ui/에 산출물을
만든 뒤 deploy합니다. 정적 파일은 합계 25MB·2,000개까지입니다.
브리지 스크립트는 deploy가 ui/_sayren/ui.js로 함께 올립니다(앱 폴더의 @sayren/app에서). 빌드 도구 없이 쓸 때는 이 경로에서
가져오고, 번들러를 쓸 때는 @sayren/app/ui를 import합니다.
세션과 핸들러 호출
앱 화면은 상점 플랫폼이 넘겨주는 세션으로만 앱의 HTTP 핸들러를 부를 수 있습니다. 세션은 「이 사람이 이 상점의 이 설치에서 화면을 열었다」는
증명이고 5분마다 갱신됩니다. @sayren/app/ui가 세션을 받고 요청에 싣습니다.
import { createAppBridge } from "./_sayren/ui.js"; // 번들러를 쓰면 "@sayren/app/ui"
const app = createAppBridge();
await app.ready(); // 상점 플랫폼에서 세션을 받을 때까지
const res = await app.fetch("/summary"); // → 앱 코드의 "GET /summary"
const { recent } = await res.json();
document.querySelector("#list").textContent = recent.map((o) => o.orderNo).join(", ");
await app.fetch("/notes", { method: "POST", body: JSON.stringify({ text: "안녕" }) });| 메서드 | 하는 일 |
|---|---|
ready() | 세션을 받을 때까지 기다립니다. 직접 연 창(프레임 밖)에서는 거부됩니다 |
fetch(path, init?) | 앱의 HTTP 핸들러를 부릅니다. path는 핸들러 키의 경로 부분입니다. 세션 헤더와 content-type: application/json(본문이 문자열일 때)을 넣습니다 |
session | { storeId, installationId, user: { userId, role } } |
toast(message, { tone? }) | 상점 플랫폼의 알림을 띄웁니다. tone은 success · error · info |
navigate(path) | 상점 플랫폼 안 경로로 이동합니다(예: /orders/ord_01J…). 상점 플랫폼 밖 주소는 거부됩니다 |
resize(height?) | 프레임 높이를 내용에 맞춥니다. 생략하면 문서 높이입니다 |
세션 헤더 이름과 형식은 바뀔 수 있으므로 직접 만들지 말고 app.fetch를 쓰십시오.
핸들러에서 사람 확인
앱 화면에서 온 요청은 핸들러의 ctx.user에 사람 id와 역할이 들어 있습니다. 핸들러는 설치 토큰으로 실행되므로 관리 API 권한은 설치 동의 범위이고
사람의 역할로 좁혀지지 않습니다. 소유자만 할 작업은 ctx.user.role === "OWNER"로 직접 막으십시오.
제한
- 화면은 상점 플랫폼 프레임 안에서만 동작합니다. 주소를 직접 열면 안내 페이지가 보입니다.
- 프레임은 상점 플랫폼 창을 다른 주소로 이동시킬 수 없고, 팝업은 열 수 있습니다.
- 앱 주소는 앱마다 다른 하위 도메인이라 다른 앱·상점 플랫폼의 쿠키·저장소에 닿지 않습니다. 브라우저 저장소(
localStorage)는 설치가 아니라 사람의 브라우저 단위이므로 상점 데이터를 두지 마십시오. - 지금은 상점의 소유자·관리자만 앱 화면을 엽니다.
- 앱 화면에서 로그인 폼을 그리지 마십시오(셀러 계정 정보를 받지 않습니다).
로컬에서 보기
npx sayren app dev가 http://localhost:4020/에 화면을 띄웁니다. 로컬에서는 상점 플랫폼 프레임이 없으므로 --store의 상점과 내 계정으로
세션을 흉내 냅니다. toast·navigate는 콘솔에 찍힙니다.