@@ -0,0 +1,98 @@
+package store.controller;
+
+import java.util.List;
+import store.constant.OrderStatus;
+import store.dto.OrderNotice;
+import store.dto.PurchaseInfo;
+import store.dto.Receipt;
+import store.service.StoreService;
+import store.view.InputView;
+import store.view.OutputView;
+
+public class StoreController {
+    private final InputView inputView;
+    private final OutputView outputView;
+    private final StoreService storeService;
+
+    public StoreController(InputView inputView, OutputView outputView, StoreService storeService) {
+        this.inputView = inputView;
+        this.outputView = outputView;
+        this.storeService = storeService;
+    }
+
+    public void run() {
+        do {
+            runStore();
+        } while (wantMorePurchase());
+    }
+
+    private void runStore() {
+        outputView.printWelcomeMessage();
+        outputView.printProductInventory(storeService.getProducts());
+        enterOrderInfo();
+        checkOrders();
+        outputView.printReceipt(calculateOrders());
+    }
+
+    private void enterOrderInfo() {
+        try {
+            storeService.resetOrders();
+            List<PurchaseInfo> purchases = inputView.readPurchases();
+            storeService.applyPurchaseInfo(purchases);
+        } catch (IllegalArgumentException e) {
+            outputView.printErrorMessage(e.getMessage());
+            enterOrderInfo();
+        }
+    }
+
+    private void checkOrders() {
+        while (storeService.hasNextOrder()) {
+            OrderNotice orderNotice = storeService.checkOrder();
+            OrderStatus orderStatus = orderNotice.orderStatus();
+
+            proceedOrder(orderNotice, orderStatus);
+        }
+    }
+
+    private void proceedOrder(OrderNotice orderNotice, OrderStatus orderStatus) {
+        if (orderStatus != OrderStatus.NOT_APPLICABLE) {
+            try {
+                askAndApplyUserDecision(orderNotice, orderStatus);
+            } catch (IllegalArgumentException e) {
+                outputView.printErrorMessage(e.getMessage());
+                askAndApplyUserDecision(orderNotice, orderStatus);
+            }
+        }
+    }
+
+    private void askAndApplyUserDecision(OrderNotice orderNotice, OrderStatus orderStatus) {
+        if (orderStatus == OrderStatus.PROMOTION_AVAILABLE_ADDITIONAL_PRODUCT) {
+            if (inputView.askAddFreeProduct(orderNotice)) {
+                storeService.modifyOrder(orderNotice.quantity());
+            }
+        }
+        if (orderStatus == OrderStatus.PROMOTION_STOCK_INSUFFICIENT) {
+            if (!inputView.askPurchaseWithoutPromotion(orderNotice)) {
+                storeService.modifyOrder(-orderNotice.quantity());
+            }
+        }
+    }
+
+    private Receipt calculateOrders() {
+        try {
+            return storeService.calculateOrders(inputView.askForMembershipDiscount());
+        } catch (IllegalArgumentException e) {
+            outputView.printErrorMessage(e.getMessage());
+            return calculateOrders();
+        }
+    }
+
+    private boolean wantMorePurchase() {
+        try {
+            return inputView.askForAdditionalPurchase();
+        } catch (IllegalArgumentException e) {
+            outputView.printErrorMessage(e.getMessage());
+            return wantMorePurchase();
+        }
+    }
+}

리뷰: 컨트롤러의 역할이 잘 맞는 것 같습니다. 저희가 사용했던 스프링처럼 각 요청에 따른 처리가 필요하다 생각해 Controller-Service-Repository의 경우 Controller에서의 역할이 순수 유효성검사만 있으며 책임이 너무 적다는 생각을 했는데 흐름을 관리하고 IO와 비즈니스 로직 사이에서 조율하는 역할이 너무 좋은 것 같습니다.