PaymentSession
PaymentSession FSM
abstract class PaymentSessionState {
abstract readonly name: PaymentSessionStateName;
abstract on(s: PaymentSessionSnapshot, e: Event, ctx: Ctx): TransitionResult;
protected reject(s: PaymentSessionSnapshot, reason: string): TransitionResult {
return { next: s, state: this, effects: [{ do: 'REJECT', reason }]};
}
}
/** --- Concrete States --- */
class PlanningState extends PaymentSessionState {
readonly name = 'PLANNING' as const;
on(s: PaymentSessionSnapshot, e: Event, ctx: Ctx): TransitionResult {
// * 이 상태객체가 허용할 이벤트 타입들만 거른다.
if (e.type === 'INVITES_SENT') {
const next: PaymentSessionSnapshot = { ...s, state: 'PENDING_PAYMENTS' }
// * Effect는 트랜지션이 일어날때 애그리게이트 밖에서 일어나야 할 사이드 이펙트를 모아둔다.
const effects: Effect[] = [
{ do: 'CREATE_SOFT_HOLD' },
{ do: 'EMIT_OUTBOX', kind: 'PAYMENT_REQUESTED', payload: {sessionId: s.id} },
{ do: 'SCHEDULE_REMINDER', at: s.remindMeAt }
];
// * TransitionResult는 이벤트로 인해 변화한 애그리거트의 상태, 트랜지션 이후의 상태객체, 사이드이펙트를 반환한다. 이벤트를 left-fold하게 될 경우, on 함수들이 연쇄적으로 호출될 것이다.
return { next, state: new PendingPaymentsState(), effects };
}
// * 유효하지 않은 이벤트가 들어올시 FSM은 이를 거절할 수 있다.
return this.reject(s, `Event ${e.type} not allowed in PLANNING`);
}
}
2025-08-14T23:03:46 알림기능에 숨은참조 같은 게 필요해보이는데?
PaymentSession과 관련한 모든 알림은 initiator와 participants에게 발송이 되고 있지만 이 알림을 몰래 훔쳐볼 필요가 있는 유저 (e.g. 그룹레슨에서의 코치)가 있을 것 같기도 하다.
대안: PaymentSessionSnapshot에 CC 라는 이름의 옵셔널 유저ID를 집어넣고, EMIT_OUTBOX
이펙트의 payload.context에 몰래 이걸 끼워넣는거다.
2025-08-20 PayerShare FSM
PayerShare는 엔티티로 봐야 한다. PaymentSession Aggregate에 의해 식별당하고 상태전이를 위임받아야 한다.