| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- Dooray
- jQuery 4.0
- ChatGPT
- GTM
- SEO
- swagger
- 생산성
- 리포지토리 인텔리전스
- Github Copilot
- 패스키
- The Singularity is Here
- 미래
- Visual Studio 2026
- geo
- 벡터 인덱싱
- 프롬프트 엔지니어링
- Passkey
- GPT
- AI
- ASP.NET
- github
- GA4
- YouTrack
- 보안
- #IT트렌드
- jira
- Gemini
- 가상시나리오
- 프론트엔드
- Today
- Total
Beyond Frontend
.NET 8 Web Application Architecture 본문

.NET 8 클린 아키텍처 기반 쇼핑몰 애플리케이션 아키텍처 설계서
본 문서는 .NET 8 기반의 차세대 쇼핑몰 애플리케이션 개발을 위한 아키텍처 설계 및 개발 표준을 정의합니다.
본 설계는 복잡한 비즈니스 로직(주문, 결제, 배송 등)을 체계적으로 관리하고, 장기적인 관점에서 애플리케이션의 성능, 확장성, 유지보수성을 극대화하기 위해 클린 아키텍처(Clean Architecture)를 핵심 설계 사상으로 채택합니다. 이 구조는 비즈니스 규칙을 기술적 구현(UI, 데이터베이스, 외부 서비스 등)으로부터 철저히 분리하여 테스트 용이성을 높이고 팀원 간의 효율적인 분업을 가능하게 합니다.
특히, 도메인(Domain) 계층을 외부 의존성 없이 순수 비즈니스 로직의 집합으로 격리함으로써, 향후 '주문'이나 '결제' 같은 핵심 도메인을 코드 변경 없이 그대로 별도의 마이크로서비스로 승격시킬 수 있는 전략적 발판을 마련합니다.
1. 솔루션 아키텍처 설계 (Solution Architecture Design)
본 아키텍처의 청사진은 '관심사의 분리(Separation of Concerns)' 원칙에 따라 명확하게 정의된 계층 구조를 제시합니다. 이 구조는 비즈니스 로직의 핵심인 도메인(Domain)을 외부 기술 변화로부터 보호하고, 각 계층이 명확한 역할과 책임을 갖도록 설계되었습니다. 이를 통해 개발팀은 기술적 복잡성에 얽매이지 않고 비즈니스 가치 구현에 집중할 수 있으며, 코드의 품질과 팀의 생산성을 전략적으로 향상시킬 수 있습니다.
1.1. 전체 솔루션 구조 (Overall Solution Structure)
ShoppingMall.sln 솔루션은 아래와 같이 소스 코드(src)와 테스트 코드(tests)를 명확히 분리하며, 각 프로젝트는 클린 아키텍처의 계층별 역할을 수행합니다.
ShoppingMall.sln
│
├── 📂 src (애플리케이션 소스 코드)
│ ├── 📦 ShoppingMall.Domain
│ ├── 📦 ShoppingMall.Application
│ ├── 📦 ShoppingMall.Infrastructure
│ └── 🌐 ShoppingMall.Web
│
└── 📂 tests (단위 및 통합 테스트 프로젝트)
└── 🧪 ShoppingMall.Tests
1.2. 계층별 역할과 책임 (Roles and Responsibilities of Each Layer)
각 프로젝트(계층)는 다음과 같은 명확한 역할과 책임을 가지며, 이는 프로젝트의 경계를 정의하고 의존성을 관리하는 기준이 됩니다.
| 계층 (Project) | 핵심 역할 및 책임 | 주요 구성 요소 |
| ShoppingMall.Domain | 핵심 비즈니스 규칙 정의<br/>- 애플리케이션의 가장 중심부.<br/>- 외부 기술에 대한 의존성이 전혀 없는 순수한 비즈니스 모델. | - Entities: DB 테이블과 매핑되는 핵심 객체 (Product, Order)<br/>- Enums: 고정된 상태 값 (OrderStatus)<br/>- Interfaces: 데이터 영속성을 위한 Repository 인터페이스 정의 |
| ShoppingMall.Application | 응용 프로그램 비즈니스 로직 구현<br/>- 도메인 객체를 사용하여 실제 사용자 시나리오를 처리.<br/>- UI나 DB 등 외부 요소와 직접 상호작용하지 않음. | - Services: 실제 비즈니스 로직 구현체 (OrderService)<br/>- DTOs: 계층 간 데이터 전송 객체<br/>- Mappings: Entity와 DTO 간 변환 로직 (AutoMapper)<br/>- Validators: 입력 데이터 유효성 검사 (FluentValidation) |
| ShoppingMall.Infrastructure | 외부 기술 및 서비스 연동<br/>- 데이터베이스, 외부 API, 파일 시스템 등 외부 시스템과의 상호작용을 담당.<br/>- Domain 계층의 인터페이스를 구현. | - Data: EF Core DbContext 설정<br/>- Repositories: Domain 인터페이스의 실제 구현체<br/>- Services: 외부 서비스 연동 (EmailService, PaymentService)<br/>- Utils: 파일 업로드, 암호화 등 인프라 관련 유틸리티 |
| ShoppingMall.Web | 사용자 인터페이스 및 요청 처리<br/>- 사용자 요청의 진입점.<br/>- Application 계층의 서비스를 호출하고 결과를 사용자에게 반환. | - Controllers: HTTP 요청 처리<br/>- Middleware: 공통 관심사 처리 (에러 핸들링, 로깅)<br/>- ViewModels: View에 특화된 데이터 모델<br/>- Program.cs: 의존성 주입(DI) 및 미들웨어 파이프라인 구성 |
이처럼 명확하게 계층을 분리함으로써 각 팀원은 자신의 역할에 집중할 수 있으며, 특정 계층의 수정이 다른 계층에 미치는 영향을 최소화하여 전체 시스템의 결합도를 낮추고 유지보수성을 극대화합니다.
2. 핵심 개발 원칙 및 표준 (Core Development Principles & Standards)
성공적인 아키텍처는 설계뿐만 아니라, 이를 구현하는 과정에서 일관된 원칙과 표준을 준수할 때 완성됩니다. 본 섹션에서는 모든 팀원이 반드시 준수해야 할 핵심 개발 원칙을 정의합니다. 장기적으로 시스템의 붕괴를 막고 예측 가능한 유지보수를 가능하게 하는 최소한의 안전장치입니다. 이 원칙들은 선택이 아닌 필수 사항입니다.
2.1. 의존성 규칙 (The Dependency Rule)
클린 아키텍처의 가장 중요한 원칙은 의존성의 방향이 항상 외부에서 내부로 향해야 한다는 것입니다. 우리 프로젝트에서는 이 규칙을 다음과 같이 적용합니다.
Web → Application → Domain
- 허용되는 의존성: Web 프로젝트는 Application을, Application 프로젝트는 Domain을 참조할 수 있습니다. Infrastructure 역시 Application과 Domain을 참조하여 인터페이스를 구현합니다.
- 절대 금지: 가장 내부 계층인 Domain은 다른 어떤 계층(Application, Infrastructure, Web 등)에도 의존해서는 안 됩니다. Domain은 순수한 비즈니스 로직만을 담고 있어야 하며, 특정 기술이나 프레임워크에 종속되어서는 안 됩니다.
이 규칙을 위반할 경우, 핵심 비즈니스 로직이 외부 기술(예: 특정 DB나 UI 프레임워크)에 종속되어 향후 기술 교체나 시스템 확장이 매우 어려워지는 심각한 문제가 발생할 수 있습니다.

2.2. DTO(Data Transfer Object) 사용 의무화
데이터베이스 Entity 객체(예: Product, Order)를 Controller 계층이나 View로 직접 전달하는 행위를 절대 금지합니다. 모든 데이터 전달은 DTO(Data Transfer Object) 또는 ViewModel을 통해 이루어져야 합니다.
이는 다음 두 가지 핵심적인 이유 때문입니다.
- 보안 취약점 방지: Entity를 직접 외부에 노출하면, 공격자가 예상치 못한 필드 값을 전송하여 데이터를 오염시키는 '대량 할당(Mass Assignment)' 취약점에 노출될 수 있습니다. DTO를 사용하면 외부에 노출할 필드만 명시적으로 선택할 수 있어 안전합니다. 예를 들어, User Entity에 IsAdmin이라는 속성이 있을 때, 회원 정보 수정 API에 Entity를 직접 바인딩하면 공격자가 {"IsAdmin": true} 값을 포함한 요청을 보내 스스로를 관리자로 승격시킬 수 있습니다. DTO는 이러한 공격을 원천적으로 차단합니다.
- 계층 간 결합도 감소: Entity는 데이터베이스 스키마와 밀접하게 연관되어 있습니다. 만약 UI 변경 요구사항 때문에 Entity를 수정하게 되면, 데이터베이스와 비즈니스 로직 전반에 예기치 않은 영향을 줄 수 있습니다. DTO는 각 계층의 필요에 맞는 데이터 구조를 제공하여 이러한 강한 결합을 방지합니다.
2.3. 의존성 주입(DI) 생명주기 가이드
Program.cs에서 서비스를 등록할 때, 각 서비스의 특성에 맞는 정확한 생명주기를 선택하는 것은 리소스 누수, 데이터 오염, 예기치 못한 버그를 유발하는 핵심 원인이므로 아래 가이드를 반드시 숙지하고 적용해야 합니다.
| 생명주기 | 설명 | 주요 사용 사례 |
| AddScoped | 각 HTTP 요청 사이클 내에서 단일 인스턴스를 보장합니다. | DbContext, 대부분의 비즈니스 서비스 및 Repository |
| AddSingleton | 애플리케이션 시작 시 한 번 생성되어 전체 수명 동안 공유됩니다. | 캐싱 서비스, 애플리케이션 설정 관리자 |
| AddTransient | 주입이 요청될 때마다 새로운 인스턴스를 생성합니다. | 가볍고 상태가 없는 유틸리티성 서비스 |
using ShoppingMall.Web.Middleware;
// using ShoppingMall.Infrastructure; // 인프라스트럭처 등록용 (추후 구현)
// using ShoppingMall.Application; // 애플리케이션 서비스 등록용 (추후 구현)
var builder = WebApplication.CreateBuilder(args);
// =========================================================
// 1. 서비스 등록 (DI Container)
// =========================================================
// [IIS 설정] 윈도우 인증 등을 사용하지 않는다면 기본값 유지.
// In-Process 호스팅 시 IIS 옵션 설정이 필요할 수 있습니다.
builder.Services.Configure<IISServerOptions>(options =>
{
options.AutomaticAuthentication = false;
});
// [MVC & API 설정]
builder.Services.AddControllersWithViews()
.AddJsonOptions(options =>
{
// JSON 속성 이름을 카멜케이스(camelCase)로 유지
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
// [레이어별 의존성 주입 (Dependency Injection)]
// 예: builder.Services.AddApplicationServices();
// 예: builder.Services.AddInfrastructureServices(builder.Configuration);
// [세션 사용 시 (장바구니 등)]
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
var app = builder.Build();
// =========================================================
// 2. HTTP 요청 파이프라인 구성 (Middleware Order) - 순서 중요!
// =========================================================
// [1] 에러 핸들링 (가장 먼저 위치해야 모든 에러를 잡음)
app.UseMiddleware<GlobalExceptionMiddleware>();
// [2] Https 리다이렉션 (운영 환경에서 필수)
if (!app.Environment.IsDevelopment())
{
app.UseHsts(); // HSTS 보안 헤더
}
app.UseHttpsRedirection();
// [3] 정적 파일 서빙 (wwwroot 안의 CSS, JS, Image)
app.UseStaticFiles();
// [4] 라우팅
app.UseRouting();
// [5] 세션 (라우팅과 인증 사이)
app.UseSession();
// [6] 인증 및 인가 (Authentication -> Authorization 순서 필수)
// app.UseAuthentication(); // 로그인 구현 시 주석 해제
app.UseAuthorization();
// [7] 엔드포인트 매핑
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// [8] 앱 실행
app.Run();
위 코드의 주석 부분(AddApplicationServices)처럼, Program.cs가 너무 길어지지 않도록 각 레이어(App, Infra)별로 DependencyInjection.cs라는 확장 메서드 클래스를 만들어 깔끔하게 관리하는 것이 좋습니다.
GlobalExceptionMiddleware는 파이프라인의 가장 앞쪽(app.Run() 직후가 아닌 app.Build() 직후)에 배치해야, 뒤따르는 모든 단계(인증, 컨트롤러 로직 등)에서 발생하는 에러를 놓치지 않고 잡을 수 있습니다.
2.4. 공통 기능 구현 가이드
프로젝트 전반에서 사용되는 공통 기능은 그 성격에 따라 미들웨어 또는 유틸리티로 구분하여 명확한 위치에 구현합니다.
- 미들웨어 (Middleware)
- 역할: 전역 예외 처리, 요청 로깅, 보안 헤더 추가 등 모든 HTTP 요청 파이프라인에 걸쳐 적용되어야 하는 공통 관심사를 처리합니다.
- 위치: 복잡한 로직은 ShoppingMall.Web/Middleware 폴더에 별도의 클래스로 구현합니다.
- 등록: Program.cs의 미들웨어 파이프라인 설정 부분에 app.UseMiddleware<>()를 사용하여 등록합니다.
- 유틸리티 (Utils)
- 역할: 파일 업로드, 암호화, 이미지 리사이징 등 특정 비즈니스 로직에 종속되지 않고 인프라와 관련된 재사용 가능한 기능입니다.
- 위치: ShoppingMall.Infrastructure/Utils 폴더에 배치합니다.
- 사용법: static 클래스보다는 DI 컨테이너에 서비스로 등록하여 주입받아 사용하는 것을 원칙으로 합니다. 이는 단위 테스트 시 모의(Mock) 객체 주입을 가능하게 하여 테스트 가능한 코드를 보장하는 핵심 원칙이며, 시스템 전반의 의존성 관리를 명확하게 합니다.
이러한 개발 표준을 일관되게 적용함으로써 코드의 품질을 높이고, 다음 단계인 실제 배포 및 운영 환경에서의 안정성을 확보할 수 있는 견고한 기반을 마련하게 됩니다.
3. 배포 및 운영 가이드 (Deployment & Operations Guide)
애플리케이션의 라이프사이클은 코드 작성으로 끝나지 않습니다. 안정적인 배포와 효율적인 운영은 프로젝트 성공의 핵심 요소입니다. 본 섹션에서는 개발 환경부터 실제 운영 환경에 이르기까지 일관된 배포 파이프라인을 수립하고, IIS(Internet Information Services) 환경에서의 표준 구성 및 운영 전략을 제시하여 잠재적 위험을 최소화하고 서비스 안정성을 확보하는 방안을 다룹니다.
3.1. 환경별 배포 파이프라인
팀 전체가 배포 프로세스에 대한 공통된 이해를 갖도록, 각 환경의 목적과 역할을 다음과 같이 명확히 정의합니다.
| 단계 | 환경 (Environment) | 목적 | DB 연결 | 배포 주체/방식 |
| 1 | Local (로컬) | 개별 기능 개발 및 단위 테스트 | 로컬 DB (Docker or LocalDB) | 개발자 (F5 Debugging) |
| 2 | Dev (개발 서버) | 팀원 간 통합 테스트, QA 진행 | 개발 공용 DB | CI 도구 (자동 배포) |
| 3 | Staging (선택) | 운영 환경과 동일한 스펙에서 최종 리허설 | 운영 DB (혹은 복제본) | 운영자 (승인 후 배포) |
| 4 | Production (운영) | 실제 사용자 서비스 | 운영 DB | 운영자 (배포 전략 준수) |
3.2. 운영 서버 IIS 구성 표준
운영 서버에서 .NET 8 애플리케이션의 성능과 안정성을 보장하기 위한 핵심 IIS 구성 체크리스트입니다.
- .NET 8 Hosting Bundle 설치
- .NET 애플리케이션이 IIS 내에서 실행되기 위한 필수 구성 요소입니다. IIS가 리버스 프록시(Reverse Proxy) 역할을 하고 실제 처리는 Kestrel 내장 웹서버가 담당하도록 연결하는 **ASP.NET Core Module (ANCM)**을 포함하므로 반드시 설치해야 합니다.
- 호스팅 모델 설정: In-Process
- 설정: In-Process 호스팅 모델을 기본이자 강력한 권장 사항으로 합니다. 이 모델은 IIS 작업자 프로세스(w3wp.exe) 내에서 .NET 런타임을 직접 실행합니다.
- 효과: 외부 프로세스와의 통신 오버헤드가 없어 Out-of-Process 모델 대비 월등한 성능(2~3배 높은 처리량)을 제공합니다. 특별한 사유가 없다면 반드시 이 모델을 사용해야 합니다.
- 응용 프로그램 풀(App Pool) 설정
- .NET CLR 버전: 반드시 **'관리 코드 없음(No Managed Code)'**으로 설정해야 합니다. .NET 8은 자체 런타임을 사용하며 IIS의 CLR에 의존하지 않기 때문입니다. 이 설정 오류는 가장 흔한 배포 실패 원인 중 하나입니다.
- 재생(Recycling) 주기: 기본값(29시간)은 예측 불가능한 시간에 서비스 재시작을 유발할 수 있습니다. 서비스 중단 영향을 최소화하기 위해, 사용량이 가장 적은 특정 시간(예: 새벽 4시)으로 고정하여 주기적인 재시작을 유도하는 것이 안정적입니다.
- ID (Identity): 보안 강화를 위해 응용 프로그램 풀의 ID는 권한이 최소화된 기본값 'ApplicationPoolIdentity'를 사용해야 합니다. 'LocalSystem'과 같이 과도한 권한을 가진 계정을 사용하는 것은 심각한 보안 위협을 초래하므로 절대 금지합니다.
- 로그 설정
- 초기 배포 또는 부팅 오류 문제 해결을 위해 web.config 파일에서 stdoutLogEnabled 속성을 true로 활성화할 수 있습니다.
- 단, 운영 환경에서는 이 로그가 디스크 공간을 빠르게 소모시킬 수 있으므로, 문제 해결 후에는 반드시 false로 비활성화해야 합니다. 장기적인 로깅 전략으로는 Serilog와 같은 서드파티 로깅 라이브러리를 도입하여 파일, 데이터베이스 등 체계적인 저장소로 로그를 수집하는 것을 강력히 권장합니다.
이러한 서버단 설정은 섹션 1과 2에서 정의한 견고한 아키텍처와 결합될 때 비로소 그 효과를 발휘합니다. 잘 분리된 애플리케이션만이 이러한 최적화된 환경에서 예측 가능하게 동작할 수 있습니다.
3.3. 무중단 배포 및 서버 폴더 구조
서비스 중단을 최소화하고 안정적인 롤백을 지원하기 위한 운영 전략입니다.
- Blue/Green 무중단 배포 단순히 운영 폴더에 파일을 덮어쓰는 방식은 배포 도중 파일 잠금 문제나 불완전한 파일 복사로 인한 오류를 유발할 수 있으며, 결정적으로 IIS가 파일 변경을 감지하고 애플리케이션을 재시작하는 과정에서 필연적으로 짧은 서비스 중단이 발생합니다. Blue/Green 배포는 이러한 문제를 원천적으로 차단하는 전략입니다.
- 준비: 현재 서비스 중인 경로(C:\ShoppingMall_Server\Builds\v1.0.1)를 가리키고 있는지 확인합니다.
- 배포: 새 버전(v1.0.2)의 빌드 결과물을 C:\ShoppingMall_Server\Builds\v1.0.2 경로에 배포합니다.
- 전환 (Swap): IIS 관리자에서 웹 사이트의 '실제 경로'를 C:\ShoppingMall_Server\Builds\v1.0.2로 즉시 변경하고 저장합니다. 이 순간 트래픽이 새 버전으로 전환됩니다.
- 검증: 애플리케이션이 정상 동작하는지 핵심 기능을 테스트하고 모니터링합니다.
- 롤백 또는 확정: 문제가 발생하면 즉시 '실제 경로'를 이전 버전(v1.0.1)으로 되돌립니다. 배포가 성공적이라면 이전 버전 폴더를 유지하여 다음 배포를 위한 백업으로 사용합니다.
- 서버 폴더 구조 운영 서버의 폴더를 다음과 같이 표준화하여 관리 효율성을 높이고 배포 실수를 방지합니다.
- 가장 중요한 원칙: 사용자가 업로드하는 파일(이미지, 첨부파일 등)이 저장되는 Uploads 폴더는 배포가 이루어지는 Builds 폴더와 반드시 물리적으로 분리해야 합니다. 만약 업로드 폴더가 배포 폴더 내에 위치하면, 새 버전을 배포할 때마다 기존 사용자 파일이 모두 삭제되는 치명적인 사고가 발생할 수 있습니다. 따라서 Uploads 폴더는 IIS의 가상 디렉터리(Virtual Directory) 기능을 사용하여 웹사이트에 연결하는 것을 원칙으로 합니다.
이러한 가이드라인을 철저히 준수함으로써, 우리는 개발부터 배포, 운영에 이르는 전 과정에서 안정적이고 예측 가능한 시스템 환경을 구축할 수 있습니다.

4. 최종 요약 및 체크리스트
본 아키텍처 설계서에서 제시된 핵심 원칙과 지침들을 종합하여, 프로젝트 리더와 개발팀이 지속적으로 참고하고 준수해야 할 최종 체크리스트를 제공합니다.
- 아키텍처 원칙:
- [ ] 의존성 규칙(Web → Application → Domain)을 항상 준수하는가?
- [ ] Entity를 Controller/View에 직접 노출하지 않고 DTO를 사용하는가?
- 서버 구성 및 배포:
- [ ] 서버에 .NET 8 Hosting Bundle이 설치되었는가?
- [ ] App Pool의 .NET CLR 버전이 '관리 코드 없음'으로 설정되었는가?
- [ ] 호스팅 모델이 성능이 우수한 'In-Process'로 설정되었는가?
- [ ] 사용자 업로드 폴더가 배포 루트 폴더와 물리적으로 분리되었는가?
- 모니터링:
- [ ] /health와 같은 상태 확인(Health Check) 엔드포인트를 구현하여 모니터링에 활용하는가?
'Frontend Essentials' 카테고리의 다른 글
| Asynchronous Log Aggregation (1) | 2025.12.16 |
|---|---|
| Kestrel: ASP.NET Core (0) | 2025.12.16 |
| AI 시대, 웹사이트의 운명을 바꿀 'llms.txt'란 무엇인가 (1) | 2025.12.15 |
| Visual Studio 2022를 위한 GitHub Copilot 고급 활용 가이드 (1) | 2025.12.15 |
| GitHub Copilot 활용 (0) | 2025.12.15 |
