Architecture Deployment API

Payment Flows

Full Stripe Checkout Flow

sequenceDiagram
  participant App as Mobile App
  participant API as REST API
  participant DB as PostgreSQL
  participant Stripe
  participant Outbox as EfOutboxWriter
  participant Dispatcher as OutboxDispatcherService
  participant Bus as InMemoryEventBus
  participant Hub as BouquetHub (SignalR)

  App->>API: POST /api/v1/orders {deliveryAddress}
  API->>DB: Create Order (status=PendingPayment)
  API->>DB: Reserve bouquets (status=Reserved, reservedUntil=now+15min)
  API->>Stripe: StripeService.CreatePaymentIntentAsync(amount, currency)
  Stripe-->>API: {paymentIntentId, clientSecret}
  API->>DB: Order.StripePaymentIntentId = paymentIntentId
  API-->>App: 201 {orderId, clientSecret}

  App->>Stripe: confirmCardPayment(clientSecret)
  Stripe-->>App: Payment result

  alt Payment succeeded
    Stripe->>API: POST /api/stripe/webhook (payment_intent.succeeded)
    API->>API: Verify webhook signature (Stripe-Signature header)
    API->>DB: Order status → Confirmed, bouquets → Sold
    API->>Outbox: EfOutboxWriter.Write(OrderPaidEvent)
    API->>DB: SaveChangesAsync (order + outbox in one transaction)
    Dispatcher->>DB: Poll OutboxMessages (every 5s)
    Dispatcher->>Bus: InMemoryEventBus.PublishAsync(OrderPaidEvent)
    Bus->>Hub: BouquetHub.SendAsync("OrderStatusChanged", orderId, status)
    Hub-->>App: Real-time notification
  else Payment declined
    Stripe->>API: POST /api/stripe/webhook (payment_intent.payment_failed)
    API->>DB: Order status → PaymentFailed
    API->>DB: Release bouquet reservations (status → Available)
    API-->>App: Real-time: payment-failed
  end

  note over DB,Stripe: Reservation auto-expires after 15min via OrderReservationExpiryService

⚠️ Known gap (EP-04): When Stripe:SecretKey is not configured, StubStripeService is active — it returns synthetic payment intent IDs and no real charge occurs. Full Stripe integration requires configuration of Stripe:SecretKey and Stripe:WebhookSecret in production. End-to-end payment testing against the live Stripe sandbox is pending EP-04.

Order Cancellation

sequenceDiagram
  participant App as Mobile App
  participant API as REST API
  participant DB as PostgreSQL
  participant Stripe

  App->>API: POST /api/v1/orders/{id}/cancel
  API->>DB: Verify order status is PendingPayment or Confirmed (not Delivered)
  API->>DB: Order status → Cancelled
  API->>DB: Release bouquet reservations (status → Available)
  alt Has Stripe payment intent
    API->>Stripe: CancelPaymentIntent or Refund
  end
  API-->>App: 200 OK