Bixby Developer Center

Guides
References

트랜잭션 워크플로우

Bixby에서 이루어지는 트랜잭션(transaction)의 핵심 요소는 외부적인 또다른 동작(예: 주문에 다른 제품 추가하기, 주문 취소하기, 주문 마무리하기)을 갖는 action입니다.

트랜잭션 워크플로우는 다음과 같은 세 단계로 이루어질 수 있습니다.

  1. 사용자가 상품을 추가, 제거 및 업데이트하여 장바구니를 준비하는 등의 작업을 수행할 수 있는 트랜잭션(Transaction) 단계
  2. 사용자가 트랜잭션을 확인하고 Bixby가 주문을 제출하거나 예약을 확인하는 등 트랜잭션을 완료하는 커밋(Commit) 단계
  3. 주문이 커밋된 후 사용자가 주문과 인터랙션하는 등의 작업을 수행할 수 있는 활동(Activity) 단계. 예를 들어 사용자는 주문 상태를 확인하거나 식사 예약을 취소할 수 있습니다.

트랜잭션에 이 세 단계가 반드시 있어야 하는 것은 아닙니다. 트랜잭션(transaction) 단계와 커밋(commit) 단계만 있는 트랜잭션의 예는 간단한 원스텝 트랜잭션 샘플 캡슐에서 확인할 수 있습니다.

캡슐의 일부로 트랜잭션을 포함하려면 적절한 action typeaction에 태깅하고 관련 concept에 적절한 concept feature를 포함시켜야 합니다. 또한 트랜잭션의 다양한 상태(state)를 처리하기 위해 해당 *-support 파일을 캡슐에 추가해야 합니다.

간단한 셔츠 주문 캡슐을 사용하여 트랜잭션의 각 단계와 트랜잭션을 구현하는 방법을 살펴보겠습니다. GitHub에서 전체 캡슐을 다운로드하시면 모든 파일을 볼 수 있습니다. 또한 기본 장바구니 트랜잭션 샘플 캡슐에서 셔츠 캡슐에 대한 자세한 설명을 확인할 수 있습니다.

다음 그림에서는 셔츠 주문 캡슐의 트랜잭션 워크플로우를 구성하는 action을 보여줍니다.

shirt order diagram

(확대 이미지를 보려면 이미지 선택)

이 예에서 사용자는 트랜잭션 단계를 초기화하는 CreateOrder를 통해 트랜잭션을 시작합니다. 그런 다음 사용자는 트랜잭션 상태를 업데이트하는 UpdateOrder를 통해 사이즈를 변경할 수 있습니다. 이 트랜잭션 객체는 트랜잭션이 완료될 때까지 계속 사용할 수 있습니다. 사용자는 Commit type인 CommitOrder 또는 CancelTransaction type인 CancelOrder를 통해 주문을 커밋하거나 취소해야 합니다. 마지막으로, 활동(Activity) 단계에서 사용자는 CheckStatus를 통해 셔츠 주문의 상태를 확인할 수 있습니다.

Action Type

Action을 모델링할 때는 위 다이어그램에 나온 것처럼 action type을 반드시 포함시켜야 합니다. Bixby에는 외부적으로 홀드(hold)되는 트랜잭션 상태가 있을 때 사용 가능한 특수한 action type이 있습니다. Bixby는 상태를 내부적으로 홀드하지 않으므로 별도의 UX를 사용하여 사용자에게 외부 상태를 처리하는 방법을 알려야 합니다.

action type은 커밋 전, 중간 및 후를 기준으로 그룹화됩니다.

커밋 전 action type

Commit 전에 이루어지는 모든 action type으로, 보통 이러한 타입은 transaction 단계에서 이루어집니다. transaction action type을 사용하는 모델의 경우, 해당 transaction-support 모델이 *.transaction.bxb 파일에 정의되어 있어야 합니다. transaction-support 정보는 상태 표시줄을 표시하고 사용자가 커밋 전에 트랜잭션을 종료하는 상황을 처리하는 데 주로 사용됩니다. 자세한 내용은 트랜잭션 및 활동 상태를 참조하세요.

BeginTransaction

트랜잭션 시작을 나타내는 action type인 BeginTransaction을 사용해 트랜잭션을 시작해 보겠습니다.

아래 셔츠 캡슐에서는 셔츠 item을 사용하여 주문 프로세스를 시작합니다.

action (CreateOrder) {
type (BeginTransaction)
collect {
input (initialItems) {
type (InitialItems)
min (Required)
max (One)
default-init {
intent: goal: CreateItems
}
}
}
output (Order)
}

View on GitHub

UpdateTransaction

트랜잭션 플로우가 시작된 후에 트랜잭션을 수정하려면 UpdateTransaction action type을 사용합니다.

아래 예에서 볼 수 있듯이, 사용자가 셔츠 사이즈를 변경하려는 경우에 이 action이 트리거됩니다.

action (UpdateOrder) {
type (UpdateTransaction)
collect {
//the order that is updated
input (order) {
type (Order)
min (Required)
}
input-group (updates){
requires (OneOrMoreOf)
collect {
input (addedItems) {
type (AddedItems)
min (Optional)
max (One)
}
input (changedItems) {
type (ChangedItems)
min (Optional)
max (One)
}
input (removedItems) {
type (RemovedItems)
min (Optional)
max (One)
}
}
}
}
//returns the updated order
output (Order) {
throws {

error(NoItems) {
on-catch {
halt {
dialog {
template-macro (NoItemsInCart)
}
}
}
}
}
}
}

View on GitHub

CancelTransaction

사용자가 트랜잭션을 완료하기 전에 셔츠 주문을 다시 고려하고 결국 취소할 경우에는 CancelTransaction을 사용하여 트랜잭션의 종료를 표시할 수 있습니다.

action (CancelOrder) {
type (CancelTransaction)
collect {
input (order) {
type (Order)
min (Optional)
validate {
if (!exists(order)) {
halt {
dialog {
template ("Okay.")
}
}
}
}
}
}
output (Receipt)
}

View on GitHub

커밋 action type

커밋 action type은 Commit 하나만 있습니다.

Commit

사용자가 마음에 드는 셔츠를 선택하고 주문을 완료할 경우 Commit을 사용하여 트랜잭션의 성공적인 완료를 표시할 수 있습니다. 이 action type은 트랜잭션 value를 받고 대개 receipt를 반환합니다.

action (CommitOrder) {
type (Commit)
collect {
input (order) {
type (Order)
min (Required)
}
}

confirm {
by (core.Confirmation)
}

output (Receipt)
}

View on GitHub

커밋 후 Action Type

커밋 후, 일반적으로 활동(activity) 단계에서 이루어지는 모든 action type을 말합니다.

활동(activity)이란 커밋 후 이루어지는 사용자와의 모든 인터랙션과 이벤트를 말합니다. Commit 후 추적할 concept을 정의할 때는 반드시 activity를 생성해야 합니다. 셔츠 예제에서는 사용자가 셔츠 주문을 추적하려고 할 때가 이에 해당합니다. 모든 활동 concept은 해당 activity-support 모델이 *.activity.bxb 파일에 반드시 정의되어 있어야 합니다. 이 파일은 활동의 현재 상태에 따라 정보를 표시하며, 반드시 정의된 활동 상태를 기준으로 정의되는 것은 아닙니다. 자세한 내용은 트랜잭션 및 활동 상태를 참조하세요.

RefreshActivity

트랜잭션이 완료된 후에 외부 시스템을 확인하여 activity value를 계속해서 새로 고칠 수 있습니다. 셔츠 주문 예제에는 사용자가 기존 셔츠 주문을 확인할 수 있는 옵션이 제공됩니다. 새로 고침에 대한 자세한 내용은 콘텐트 새로 고치기를 참조하세요.

action (CheckStatus) {
type (RefreshActivity)
collect {
input (receipt) {
type (Receipt)
min (Required)
default-init {
intent {
goal: FindLastReceipt
}
}
}
}
output (Receipt)
}

View on GitHub

CancelActivity

마지막으로, 트랜잭션이 완료된 후에 사용자가 트랜잭션을 취소하기로 결정할 경우 CancelActivity를 사용할 수 있습니다. 트랜잭션이 취소되면 캡슐은 activity value 추적을 중단합니다.

action (CancelCommittedOrder) {

type (CancelActivity)

confirm {
by (core.Confirmation)
}

collect {
input(receipt){
type(Receipt)
min (Optional)

default-init {
intent {
goal: FindLastReceipt
}
}

validate {
if (!exists(receipt)) {
halt {
dialog {
template("Not sure what to cancel. I didn't find any recent shirt orders.")
}
}
}
if (exists(receipt) && receipt.orderState != 'Ordered') {
halt {
dialog{
template("This order is already #{value (receipt.orderState)}!")
}
}
}
}
}
}

output(Receipt)
}

View on GitHub

Concept Feature

structurestructure-enum concept의 경우, 해당 transaction 또는 activity feature를 사용하여 태깅해야 합니다.

셔츠 주문 예제에서, 주문을 나타내는 다음 구조체에는 이 concept을 진행 중인 트랜잭션의 일부로 추적해야 함을 나타내는 features 키(key)가 포함되어 있습니다.

structure (Order) {
property (items) {
type (Item)
min (Optional)
max (Many)
}
property (orderNumber) {
type (OrderNumber)
min (Required)
}
property (totalPrice) {
type (Price)
min (Required)
}
property (holdTime) {
type (HoldTime)
min (Required)
}
features {
transaction
}
}

View on GitHub

한편, 셔츠 주문 예제에서는 receipt가 생성되는데 이것은 트랜잭션이 완료된 후 사용되기 때문에 activity로 태깅해야 합니다.

structure (Receipt) {
property (order) {
type (Order)
min (Required)
max (Many)
}
property (orderState) {
type (OrderState)
min (Required)
}
property(statusRefreshTime) {
type(time.DateTime)
visibility(Private)
min (Required)
}
features {activity}
}

View on GitHub

트랜잭션 및 활동 상태

Feature에 대해 concept을 태깅하여 concept에 상태(state) 정보가 있음을 나타낼 때는 해당 concept 상태에서 어떤 일이 일어나는지도 함께 정의해야 합니다.

트랜잭션 파일(*.transaction.bxb) 내에서는 진행 중인 트랜잭션에 대한 transaction-support를 정의할 수 있고, 활동 파일(*.activity.bxb) 내에서는 완료된 트랜잭션에 대한 activity-support를 정의할 수 있습니다.

예를 들어, 아래와 같은 셔츠 주문 예제에는 셔츠를 주문하는 Order라는 구조체(structure) concept이 있는데, 여기에는 transaction-support 파일을 사용하여 일부 처리 가능한 트랜잭션이 포함되어 있습니다.

transaction-support {
match {
Order (this)
}
confirm-on-abandon {
message ("Are you sure you want to quit your order?")
on-retain {
goal {
CommitOrder
}
}
}
}

이 트랜잭션에서 transaction-support는 사용자가 트랜잭션을 중단하고 새 트랜잭션을 시작할지 여부를 확인할 수 있도록 합니다. 또한 이 transaction-support는 concept이 진행 중인 트랜잭션 플로우의 일부임을 나타냅니다.

transaction-support에 대응되는 activity-support는 concept이 완료된 트랜잭션 플로우의 일부임을 나타냅니다.

activity-support {
match {
Receipt (this)
}
time (statusRefreshTime)
states {
if (orderState == 'Ordered') {
state (Scheduled) {
expires(statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
} else-if (orderState == 'Shipped') {
state (Relevant) {
expires(statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
} else { //orderState == 'Delivered' || orderState == 'Cancelled'
state (Recent) {
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
}
}
}

View on GitHub

Receipt 구조체를 보시면 activity-support에 주문 후(post-order) 상태인 "Ordered", "Shipped", "Delivered"에 대한 제어 플로우가 있음을 알 수 있습니다. 또한 Scheduled, Relevant, Recent 상태도 확인할 수 있습니다. 이 상태들은 각각 활동이 예정됨, 진행 중, 완료됨을 나타내며 Bixby에서 사용되는 특정한 value입니다. 사용자가 RefreshActivity를 사용하여 셔츠 주문의 최신 상황을 확인하고자 할 경우에, 이러한 상태가 사용자에게 다양한 외부 상태를 알려주게 됩니다.

제어 플로우에 대한 특정한 주문 상태를 정의할 필요는 없습니다. 그 대신, expression language를 사용할 수 있습니다. 예를 들어, 예약 시간이 미래인지, 현재인지 아니면 과거인지를 확인하고 이를 해당 state에 매치할 수 있습니다.

transaction, activity 및 관련 concept state에 대한 자세한 내용은 참조 문서에서 확인할 수 있습니다.

선택 프롬프트(Selection Prompt)

둘 이상의 함수를 사용하여 외부 효과를 갖는 action을 구현하는 경우, 실행을 진행하기 위해서는 함수 하나를 반드시 선택해야 합니다. Bixby는 프롬프트를 통해 사용자가 트랜잭션에 사용할 구현 방식을 선택하도록 합니다. 사용자의 선택이 이루어지면 선택된 함수를 사용하여 실행이 계속될 수 있습니다. 사용자를 대신하여 Bixby가 자동으로 선택하도록 만드는 방법은 선택 규칙(selection rule)을 참조하세요.

더 자세한 내용은 선택 프롬프트(Selection Prompt) 항목에서 찾을 수 있습니다.

Activity Card로 업데이트 제공하기

셔츠 샘플 캡슐 워크스루에 간략히 나와 있듯이, 트랜잭션 워크플로우에는 transaction, commit, activity라는 세 단계가 있습니다. activity 단계에서 관련 Activity Card를 활용하여 receipt에 업데이트된 사용자의 예정된 이벤트(예: 참석하기로 예정된 모임, 예약한 호텔, 주문한 상품)에 대한 최신 정보를 제공할 수 있습니다. 기본적으로 "receipt" 상태로 나타나는 모든 트랜잭션이 Activity로 간주됩니다.

activity 인터페이스(dialoglayout 포함)에서는 기본적으로 다음 두 작업 중 하나를 수행할 수 있습니다.

  • 사용자의 마지막 receipt 상태가 오래된 경우 업데이트된 정보를 제공합니다. 예를 들어, 사용자가 승차 공유를 요청했다면 차량의 현재 위치와 예상 도착 시간을 정기적으로 업데이트 받고자 할 수 있습니다.
  • 이전에는 제공되지 않았거나 해당 사항이 없던 추가 관련 정보를 제공합니다. 예를 들어, 사용자가 출발 4시간 전에 항공편 상태를 확인한다면 해당 항공편이 예정대로 정시에 출발할 것인지를 알고 싶어 하는 것입니다. 항공편 출발 시각이 가까워지면 사용자는 activity를 새로 고쳐 항공편 출발 시각과 게이트 번호를 확인할 수 있습니다.

Activity Card가 표시되는 위치는 다음과 같습니다.

  • 예정된 activity가 있는 경우 Bixby Main 페이지에 표시됩니다.
  • 캡슐 페이지에 있는 Manage 탭의 Reservations and Purchases 섹션에 표시됩니다. 모든 과거 트랜잭션이 여기에 저장됩니다.

Activity Card에 표시되는 내용

Activity Card의 summary-view는 주 슬롯, 보조 슬롯 그리고 Activity Card dialog로 구성되며, Bixby Main 페이지와 캡슐 Manage 탭의 최근 기록 아래에 표시됩니다. 카드 내 다양한 슬롯의 내용은 summary-viewmessage, titledetails 키(key)로 결정됩니다. 타임스탬프 슬롯은 required time 키(key)로 결정됩니다. 또한 image-url을 사용하여 Activity Card에 이미지를 추가할 수도 있습니다.

Bixby Main page layout of an Activity Card

Activity Card의 인터페이스는 내용을 포함한 키(key)와 Bixby Main 페이지에서 Activity Card의 위치에 따라 달라집니다. 다음 목록은 activity에 대한 Summary View에서 각 슬롯에 표시되는 정보와 슬롯이 해당 정보를 가져오는 키(key)를 보여줍니다.

  • 목록에서 처음으로 보이는 카드의 경우 message 내용이 Bixby Dialog로 표시되고, 주 슬롯에 title이, 보조 슬롯에는 details가 표시됩니다.

Bixby Main page layout of an Activity Card

  • 첫 번째 카드 아래에 오는 모든 카드는 message 키(key)에 내용이 있는지 여부에 따라 다음과 같이 정보가 표시됩니다.
    • message가 지정된 경우: 주 슬롯에 message가, 보조 슬롯에 titledetails가 표시됩니다.
    • message가 지정되지 않은 경우: 주 슬롯에 title이, 보조 슬롯에 details가 표시됩니다.
      Note

      Bixby Main 페이지에서 message 위치가 달라질 수 있기 때문에 message 내용은 완전한 문장으로 이루어져야 합니다. 예:

      • 좋은 예: "오후 3시에 치과 진료 예약이 있습니다" - Bixby dialog: 안녕하세요 홍길동님, 오후 3시에 치과 진료 예약이 있습니다.
      • 나쁜 예: "오후 3시 치과" - Bixby dialog: 안녕하세요 홍길동님, 오후 3시 치과 진료.

다음과 같은 몇 가지 경우에는 Bixby Main 페이지에 detail-view가 표시됩니다.

  • 트랜잭션 맨 마지막에 Receipt를 표시하는 경우
  • 사용자가 자세한 정보를 위해 Activity Card를 클릭하는 경우
  • 사용자가 트랜잭션 기록에서 과거 트랜잭션을 클릭하는 경우

Activity Card 생성하기

Activity Card는 기본적으로 사용자가 해당 Activity의 수명주기를 따르기 위한 가이드로 사용됩니다. Activity Card는 commit 단계가 끝나고 activity 단계가 시작될 때 대개 receipt 형태로 표시됩니다. 또한 사용자에게 추가 정보를 제공할 수 있도록 Bixby Main 페이지에 표시될 수도 있습니다.

*.activity.bxb 파일에 summary-viewdetails-view 키(key)로 생성되는 layout과 dialog를 정의하여 Activity Card를 생성할 수 있습니다. Details View 내에서는 어떤 layout도 사용 가능하긴 하나, 가급적이면 Card를 사용하는 것이 좋습니다.

또한 Activity의 states(scheduled, relevant, recent)를 고려하여 어떤 정보를 표시할지 그리고 언제 Activity Card에 특정 정보를 표시할 것인지를 결정해야 합니다.

Note

Activity가 recent 상태인 경우 Activity Card가 표시되지 않습니다. 사용자는 캡슐 페이지의 Manage 탭에 표시되는 트랜잭션 기록에서 과거 Activity를 확인할 수 있습니다.

Activity에 대해 생성하는 구조체(예: Receipt 모델) 내에서 $id를 반드시 설정해야 합니다. 이 $id를 통해 사용자의 다양한 Activity를 구별할 수 있습니다. 예를 들어, 사용자가 11월 추수감사절 기간에 호텔을 예약하고 12월 크리스마스 기간에 호텔을 별도로 예약했다고 할 경우에, 이 두 가지 예약을 구별하기 위해서는 호텔 예약 결과로 나타나는 Receipt 모델에 고유한 Activity ID가 각각 표시되도록 해야 합니다.

각 Activity Card마다 고유한 $id가 부여된다는 점을 유의해주세요. 사용자의 디바이스에는 고유한 각 Activity마다 Activity Card 1개가 표시됩니다.

Note

activity concept에 사용하는 id는 내부 시스템과 일관되게 유지하는 것이 좋습니다. 이렇게 하면 Activity를 추적하기 쉽고 디버깅할 때도 도움이 됩니다.

캡슐을 업데이트할 때는 두 가지 직렬화(serialization) 문제를 고려해야 합니다.

  • Activity 모델을 변경하는 경우 Bixby 시스템에서 이전 모델과 호환 가능해야 합니다. 새로운 optional property를 추가하는 것은 문제 없지만, property를 삭제하거나 새 required property를 추가할 경우에는 이전 activity에 영향을 미쳐 Bixby가 이전 receipt를 읽지 못하게 될 수 있습니다.
  • 기존 receipt의 Details View는 해당 receipt의 모델이 새 모델 변경 사항과 호환 가능한 경우에만 처리 및 렌더링될 수 있습니다.

Activity Card를 표시하는 시점

*.activity.bxb 파일에 정의된 expires 키(key)를 통해 Activity Card를 표시하는 시점을 결정하고 activityrefresh 상태인 동안에 얼마나 자주 새로 고칠 것인지를 결정합니다.

표현식(expression)expires 키(key)에 전달할 수 있기 때문에 일정 간격으로 새로 고치거나 다른 상태에 따라 새로 고치도록 설정할 수 있습니다. 예를 들어, shirt 캡슐은 capsule.properties 파일에서 상수 status_refresh_time을 600초(10분)로 설정합니다. 이때 간격이 짧으면 업데이트를 위해 클라이언트 서버로 전송되는 트래픽이 많아지므로 어떤 표현식(expression)을 설정할 것인가에 주의할 필요가 있습니다. 또한 사용자 경험도 고려해야 합니다. 사용자가 8개월 전에 호텔을 예약했다면 여행 일정이 어느 정도 다가오기 전까지는 이 예약에 대한 알림을 매일 표시할 필요가 없습니다.

추가로 조건(conditional)과 다양한 활동 상태(state)를 통해 표시할 내용을 제어할 수 있습니다. 예를 들어 호텔 예약의 activity는 예약 time 7일 전에 scheduled 상태로 설정하고 예약 time 3일 전에 relevant 상태로 변경해야 합니다. 또 다른 shirt 예제에서, 조건(conditional)은 Order 구조체의 state를 결정하고 다양한 states는 실제로 표시되는 정보를 결정합니다.

  states {
if (orderState == 'Ordered') {
state (Scheduled) {
expires(statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
} else-if (orderState == 'Shipped') {
state (Relevant) {
expires(statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
} else { //orderState == 'Delivered' || orderState == 'Cancelled'
state (Recent) {
summary-view {
message {
template ("#{value(orderState)} #{value(order)}")
}
title {
template ("#{value(order)}")
}
details {
template ("#{value(orderState)}")
}
}
detail-view {
render {
layout-match (this) {
mode (Details)
}
}
}
}
}
}

View on GitHub

Note

Activity Card는 사용자가 현재 Bixby를 실행하고 있는 상황에서만 새로 고쳐집니다. 사용자가 Bixby를 종료하면 Bixby Main 페이지를 다시 열 때까지 업데이트를 받지 못합니다. 백그라운드에서는 자동 새로 고침이 이루어지지 않습니다. 다시 말해, *.activity-support.bxb 파일에서 expires 키(key)를 5분으로 설정했다고 해서 5분마다 시스템에 대한 웹 서비스 호출이 이루어지는 것은 아닙니다. Bixby는 각 사용자에 대해 expires 기간(단위: 초) 내에 한 번만 웹 서비스를 호출합니다. 자세한 내용은 콘텐트 새로 고치기를 참조하세요.

다음은 Scheduled 상태인 Activity Card의 예입니다.

Activity Card in Scheduled state

다음은 Relevant 상태인 Activity Card의 예입니다.

Activity Card in Scheduled state