프로젝트의 복잡도 및 수준(세부)1
2025.06.11
지시대로 이 프로젝트에 대해 가능한 최대 길이, 세부도, 기술적 밀도로 구성하여 설명한다. 전체 분석은 실전 수준의 기술 리뷰 형식으로 진행하며, 개발자 입장에서 다음 범주별로 분석한다:
**전체 아키텍처 및 설계 철학**
**도메인 모델링 및 비즈니스 로직 설계**
**상태 관리와 비동기 흐름 구성**
**창 기반 사용자 인터페이스 구조**
**데이터베이스 구조 및 연산 최적화**
**UI/UX 디테일, 접근성, 사용자 경험 설계**
**코드 품질, 타입 안정성, 유틸리티 구조**
**확장 가능성과 유지보수성 분석**
**프로젝트 복잡도 및 숙련도 기준 평가**
**기타 전략적 고려사항**
1. 전체 아키텍처 및 설계 철학
이 프로젝트는 단순 블로그 생성기가 아니다. 아키텍처를 살펴보면 \*\*복수 창 인터페이스 기반 콘텐츠 관리 시스템(CMS)\*\*에 가까운 구조를 갖고 있다. 핵심은 **Next.js App Router 기반 풀스택 SPA+SSR 혼합 앱**이며, 다음 아키텍처 계층이 명확히 존재한다:
**Presentation Layer (app/management/\_window/)**: 사용자 인터페이스 구성. 컴포넌트 단위로 창 인터페이스 분리
**State Layer (store/)**: Zustand 기반 전역 상태 저장소. 창 상태, 선택 객체, 사용자 데이터 등을 관리
**Async Layer (hook/useAsyncTaskManager, services/)**: API와의 통신을 Task Queue로 직렬화하여 요청/응답/실패/캐시 갱신 처리
**Data Access Layer (models/, fetch/, lib/mongoClient.ts)**: DB 직접 접근 및 서버 API fetch 분리
**Domain Schema (lib/types/)**: MongoDB Document 타입과 클라이언트 Response 타입을 분리 관리
App Router 기반 SSR + CSR 혼합 구조는 다음과 같은 전략을 따르고 있다:
layout.tsx에서 인증과 폰트 세팅, 공통 컴포넌트를 삽입함으로써 페이지 진입 전 초기 데이터 확보
dynamic import 및 `ClientOnly` 컴포넌트를 활용해 클라이언트 사이드에서만 동작해야 하는 컴포넌트를 분리
서버 fetch는 서버 전용 fetch API로 구성하고, 클라이언트 fetch는 별도로 구성하여 데이터 흐름을 명확히 분리
이 구조는 Next.js의 모든 능력을 SSR/CSR 환경에서 적절히 병용하고 있으며, 코드 분리, 권한 제어, 동적 데이터 구성에 모두 대응하는 방식이다.
2. 도메인 모델링 및 비즈니스 로직 설계
이 프로젝트의 핵심 도메인은 다음과 같다:
`User`: 인증된 사용자, 블로그 URL을 통해 접근 가능
`Folder`: 트리 구조로 구성되며 계층적 구조 유지, 포스트 포함
`Series`: 여러 포스트를 논리적으로 묶는 단위. 순서 포함
`Post`: 콘텐츠 본문. 제목, 설명, 마크다운 AST 저장, 썸네일, 폴더/시리즈 연결
`About`: 블로그 소개글
`Window`: UI 단위 창 구성 정보. 내부적으로 상태 객체 및 작업 큐 포함
각 도메인은 다음과 같은 속성을 따른다:
Document 기반 MongoDB 스키마를 그대로 구조화함 (ObjectId 사용)
API 응답 시 문자열 기반으로 직렬화된 Response 형태로 재정의
클라이언트 측에서의 상태는 대부분 Response 타입을 기준으로 동작함
비즈니스 로직은 도메인 단위로 다음 흐름을 따른다:
데이터 조회: 서버 fetch (fetch/server/)
데이터 조작: 클라이언트 요청 후 서버로 전달 (fetch/client/)
응답 수신 후 상태 동기화: useAsyncTaskManager 내부에서 전역 상태 및 React Query 캐시 조작
이러한 분리 구조는 **서버-클라이언트 간 데이터 경계**, **상태-비동기 흐름의 분리**, **컴포넌트-도메인의 결합 최소화**라는 세 가지 원칙을 충실히 반영한다.
3. 상태 관리와 비동기 흐름 구성
상태 관리는 다음과 같이 계층화되어 있다:
Zustand (store/)
창 리스트, 포스트 선택 상태, 사용자 정보 등 앱 전역 상태 저장
창 단위로 구성된 상태 트리는 각 창 고유의 상태와 작업큐를 유지하며 독립성 확보
상태 갱신은 비동기 작업 성공/실패 콜백 또는 뷰 직접 조작에 의해 수행
React Query
비동기 요청의 캐싱, 자동 재요청, stale/dirty 상태 구분 등을 담당
custom query key 체계를 통해 사용자별, 폴더별, 시리즈별로 데이터 캐싱됨
useInfiniteQuery를 통해 페이지네이션 기반 무한스크롤 구성
AsyncTaskManager
각 창 컴포넌트 내부에 큐가 생성되어 비동기 작업을 push
큐에 들어온 작업은 순차 실행되고, 성공 시 상태 갱신, 실패 시 에러 핸들링 수행
Task는 type-safe 하게 구성되며, request, response, optimistic update가 모두 통합 관리됨
이런 구조는 일반적인 상태관리와는 달리, **'작업 단위의 상태'를 추상화하여 시간에 따른 상태 흐름과 side-effect를 제어**한다. 이는 높은 복잡도를 수반하지만, 결과적으로 예측 가능하고 일관된 UI 상태를 유지하게 한다.
4. 창 기반 사용자 인터페이스 구조
이 프로젝트의 가장 특이한 구조 중 하나는 "다중 창 기반 인터페이스"다. 브라우저 상에서 마치 데스크탑 앱처럼 동작하며, 창마다 상태와 비동기 흐름을 독립적으로 유지한다.
각 창(`PostWindow`, `SeriesWindow`, `FolderWindow`, `PreviewWindow` 등)은 `WindowManager`에서 중앙 관리됨
창 간 부모-자식 관계 유지 가능. 예: FolderWindow → PostListWindow → PostWindow
창 포지션, 사이즈, 포커스 등 UI 상태도 store에 저장되며 창 재생성 시에도 일관성 유지
창 간 통신은 store 또는 task 큐를 통해 수행되며, 전역 상태와 분리된 흐름을 가진다
이 구조는 다음과 같은 목적을 실현한다:
사용자는 동시에 여러 작업(포스트 편집, 미리보기, 시리즈 변경 등)을 병렬로 수행할 수 있다
창마다 독립적으로 실패/성공을 관리하므로 에러 전파가 창 단위로 한정된다
UI 동기화가 구조적으로 해결되어 race condition 발생 확률이 낮다
이는 일반적인 SPA 구조보다 복잡하지만, 생산성 높은 UI를 제공하기 위한 설계다.
5. 데이터베이스 구조 및 연산 최적화
이 프로젝트는 **MongoDB를 핵심 데이터 저장소**로 사용하고 있으며, 단순 document 저장을 넘어서 고급 집계 연산(aggregation pipeline), 트랜잭션(ClientSession), 관계형 접근 모델까지 적용된 구조를 가진다. 주요 특성과 기술적 판단 근거는 다음과 같다:
도큐먼트 설계 및 정합성
각 도메인(Post, Folder, Series, About, User)은 독립된 컬렉션으로 분리되어 있으며, `_id: ObjectId`를 사용
관련 도메인 간에는 외래키(FK)를 명시적으로 명시 (`folder_id`, `series_id`, `user_id`)하며, `ObjectId`로 연결됨
클라이언트 측에서는 이 `ObjectId`를 문자열로 변환하여 응답 포맷(Response)으로 관리. 이는 **직렬화 안정성과 명시적 경계 설정**을 위해 유효한 설계다
집계 연산 및 페이지네이션
특히 눈에 띄는 부분은 `models/pagination/pageNum/getByFolderId.ts`에서 사용된 MongoDB의 고급 집계이다:
`$setWindowFields` + `$documentNumber`를 통해 문서 순서를 계산하고
`$skip`, `$limit`, `$project`를 통해 페이지네이션을 수행
`ceil(total/postPerPage)` 연산을 통해 전체 페이지 수 계산
이 구조는 **서버 측에서 정렬/페이징/순서 부여**까지 완료하여 클라이언트는 불필요한 연산을 피할 수 있다. 이는 MongoDB 5.0 이상에서 도입된 기능을 적극적으로 활용한 설계로, 정렬 기준이 명확하고 요청당 부하가 일정하게 유지된다는 장점이 있다.
트랜잭션 및 세션 사용
대부분의 `insert`, `updateMany`, `deleteOne` 연산은 `ClientSession`을 통해 트랜잭션 처리 가능하도록 구성되어 있음
예: `updateManyByPFolderId`, `deleteOneByFolderId`, `insertOne` 등에서 `session: ClientSession`을 명시적으로 사용
이는 동시성 충돌 및 데이터 정합성을 보장하기 위한 구조이며, 다중 작업 중 하나라도 실패할 경우 전체 롤백이 가능하다.
데이터 무결성 및 응답 처리 전략
응답은 `Response<T>` 형식으로 처리하며, `ok`, `timeout`, `notfound`, `unauthorized`, `invalid` 등 상태를 명시적 타입으로 분기
서버 fetch에서는 상태에 따라 다음 동작을 분기하고, 클라이언트에서는 `if (!res.ok)` 조건문을 통해 공통 에러 처리 로직이 존재
즉, **전문적으로 설계된 데이터 API 인터페이스와 타입 기반 상태 제어 흐름**을 갖추고 있다. 이 구조는 클라이언트가 서버 상태를 명확히 인식하고 처리할 수 있도록 도와준다.
6. UI/UX 디테일, 접근성, 사용자 경험 설계
이 프로젝트는 단순히 기능을 구현하는 것을 넘어서, **복잡한 사용자 인터페이스를 구성하고, 그 상태를 일관되게 유지하는 구조적 설계**를 취하고 있다. 아래는 그 특성과 근거다.
UI 구조와 상호작용
창 간 포커스, 위치, 계층 순서(z-index)는 전역 store에서 제어되고, UI 간 중복이 없도록 관리됨
모달 구조는 context-free로 구현되어 있으며, 확인, 이름 변경, 삭제, 이동 등의 모든 UI가 모달로 분리되어 있음
외부 클릭 감지(`useRootMouseDownOutside`)는 ref 매핑으로 창 바깥 클릭을 감지해 창 닫기, 모달 종료 등 정밀한 제어가 가능함
스타일링 및 시각 요소
SCSS 기반 스타일링 구조 사용. 컴포넌트 단위 모듈화로 클래스 충돌 방지
`:root` CSS 변수로 색상 및 간격 관리 → 다크모드 전환을 위한 사전 대응
마크다운 본문, 코드 하이라이팅(`shiki`), 접근성 지원 클래스(`.sr-only`) 등 시각적 완성도에 주력한 설계
반응성 및 접근성
단순한 반응형 레이아웃이 아닌, 창 단위 뷰 확장 → 브라우저 해상도 내에서 효율적인 다중작업 UI 제공
스크린 리더 대상 클래스 지정, 마우스 hover/active 인터랙션의 믹스인 적용 등 UX 편의 요소 포함
텍스트 크기, 입력 필드, 버튼 간격 등 WCAG 기준의 최소한을 고려한 듯한 구조
7. 코드 품질, 타입 안정성, 유틸리티 구조
코드의 스타일과 유지보수성을 판단하기 위해 내부적 공통성, 추상화 범위, 반복 제거 정도, 타입 적용 방식을 분석하면 다음과 같다:
공통 코드와 유틸리티
폴더 계층 탐색(`buildTrie`, `buildFolderChildrenMap`)은 컴포넌트 내에서 중복되는 탐색 비용을 줄이기 위한 자료구조 기반 유틸
`gtag.ts`를 통한 Google Analytics 분리, `fetchUtils`, `windowUtils`, `taskUtils` 등 중복 코드 최소화
`confirmModal`, `nameChangeModal` 등은 상태를 별도로 갖지 않고 props 기반으로 일회성 실행되도록 구성
타입 구성
`Document` vs `Response` 타입은 명확히 구분되어 있음
API 응답은 `Response<T>` generic 타입으로 감싸며, 실패 케이스는 union 타입(`NotFound | Timeout | Invalid`)으로 명시
Zustand store는 명시적 타입 주입으로 불변성 보장 및 예측 가능성 확보
이러한 타입 전략은 코드 안정성 측면에서 신뢰도가 높으며, 리팩토링 시 타입 경고를 통해 안전하게 변경할 수 있는 기반이 된다.
8. 확장 가능성과 유지보수성 분석
이 프로젝트는 단순히 현재 기능을 구현하는 데 그치지 않고, 향후 기능 확장과 팀 협업, 장기 유지보수를 고려한 구조를 갖고 있다. 다음은 그 구조적 기반과 평가이다.
8.1 기능 확장 가능성
이 구조는 다음 기능 확장에 대해 큰 저항 없이 수용할 수 있다:
**포스트 형식 추가**: 예를 들어 ‘공지사항’, ‘링크 공유’, ‘투표’ 같은 새로운 포스트 유형이 추가될 경우에도 `PostWindow`, `postInfo` fetch, `PostContent` 등 핵심 컴포넌트가 명확히 역할 분리되어 있어 조건 분기만으로 수용 가능하다.
**태그 시스템 도입**: `post.tags` 필드를 추가하고 관련 쿼리와 UI 필터를 넣는 것만으로 구현 가능. 필터는 React Query의 queryKey에 따라 조건부 요청으로 설계되어 있음.
**협업 기능**: `User` 모델 확장 및 ACL 기반 권한 로직 추가로 공동 작성, 공유 관리 기능 추가 가능.
**댓글, 좋아요, 통계**: 별도 컬렉션과 창(Window) 컴포넌트 추가로 확장 가능. 현재 창 구조는 독립성이 높아 새로운 뷰 삽입에 유리함.
**에디터 확장**: Markdown 기반이지만 AST 저장 방식을 취하고 있어, 향후 Block Editor나 WYSIWYG 에디터로 교체도 기술적으로는 가능.
8.2 유지보수성과 코드 분리
**fetch(server/client) 분리**: 서버와 클라이언트 요청을 명확히 나눔으로써 실행 맥락을 혼동 없이 관리
**모델별 API와 store의 명확한 경계**: Zustand는 UI 상태, React Query는 서버 데이터 상태로 역할 분리가 잘 되어 있음
**모듈 단위 코드 정리**: `services/`, `models/`, `validation/` 등은 현재는 미약하지만 분리 방향이 명확하게 설정되어 있음
8.3 테스트 및 CI/CD 고려
현재 테스트 코드나 test runner 설정은 보이지 않지만 다음 조건이 마련되어 있어 추후 추가가 용이하다:
대부분의 로직이 순수 함수 또는 훅 내부에 한정되어 있어 단위 테스트 구성이 가능
API 호출이 fetch wrapper로 감싸져 있어 mock 테스트 주입 가능
상태 관리와 side-effect 분리가 되어 있어 `react-testing-library`, `jest`, `msw` 등을 도입하기 용이한 구조
9. 프로젝트 복잡도 및 숙련도 기준 평가
복잡도 기준
아래는 기능과 기술 별 복잡도 분류 기준에 따른 정량적 평가다:
| 항목 | 단순 | 보통 | 복잡 | 매우 복잡 |
| --------------- | -- | -- | -- | ----- |
| 페이지 수 | ✔︎ | | | |
| CRUD 구현 | | ✔︎ | ✔︎ | |
| 계층 모델링 (트리 구조) | | | ✔︎ | |
| 상태 관리 | | ✔︎ | ✔︎ | |
| 비동기 흐름 | | ✔︎ | ✔︎ | |
| 다중 창 구조 | | | | ✔︎ |
| 데이터 정규화/관계형 모델링 | | ✔︎ | ✔︎ | |
| 작업 큐 시스템 | | | ✔︎ | |
| 클라이언트/서버 API 분리 | | ✔︎ | ✔︎ | |
| 미리보기/동적 포탈 | | ✔︎ | ✔︎ | |
| 사용성/UX 구조 | ✔︎ | ✔︎ | ✔︎ | |
**총평**: Next.js 기반의 웹 애플리케이션 중 복잡도 상위 10\~15%에 해당하는 구조. 특히 창 기반 UI와 task queue 시스템은 일반적인 Next.js 앱에서는 보기 드문 구조다.
개발자 숙련도 기준
이 프로젝트를 혼자서 설계하고 구현했다면 다음 기준의 숙련도를 요구한다:
**React + Zustand + React Query** 숙련 (비동기 캐시 상태 분리, manual cache control)
**Next.js App Router** 구조에 대한 이해 (layout, server component, client 분리)
**MongoDB Aggregation/Transaction** 활용 가능 (단순 CRUD 이상)
**UI 상태/이벤트 흐름 설계 능력** (창 위치, 창 포커스, 모달 흐름 등)
**모듈화, 관심사 분리 개념** 적용
이는 **중급 이상의 실무 개발자 수준**이며, 입문자 또는 포트폴리오 학습자 수준은 넘는다. 본 프로젝트는 단순 과제 목적이라기보다는, 실제 사용 가능하고 확장 가능한 CMS 플랫폼 구조로 판단된다.
10. 기타 전략적 고려사항
10.1 SEO 및 접근성
현재 구조는 대부분 클라이언트 렌더 기반이므로 기본적으로 SEO는 제한적이다
SSR 페이지가 존재하긴 하나 블로그 메인 외에는 대부분 클라이언트 구성
만약 검색엔진 인덱싱이 필요하다면, 포스트 상세 페이지만 SSR 구조로 분리하거나 SSG 캐싱 전략을 추가해야 한다
10.2 퍼포먼스 고려
React Query의 staleTime 및 캐시 정책이 모두 명시되어 있어 불필요한 재요청 방지 구조는 잘 되어 있음
단점: 다중 창이 과도하게 열릴 경우 store 상태와 DOM 렌더링 비용이 누적될 수 있음
해결 방안: 창 최대 개수 제한, 가상 스크롤, 창 비활성화 시 unmount 옵션 등 추가 필요
10.3 보안
현재 세션 기반 인증으로 추정되며 쿠키 체크를 통해 접근 제어됨 (`getBySession`)
권한 범위, 인증 토큰 관리, API 레벨 접근 제어는 존재하나 상세 구현은 미포함 (검사 대상 파일 외부 가능성 있음)
CSRF, XSS, SSRF 등 보안 위협에 대한 방어가 프레임워크 기본 수준 이상으로 구성되어야 한다면 middleware, token rotation, escape 처리 등 추가 필요
최종 종합 결론
이 프로젝트는:
단순한 블로그 생성기나 개인 기록용 웹앱이 아니라,
**기능, 구조, 기술, 확장성 면에서 CMS 수준의 애플리케이션**이며,
**설계 철학이 명확하고, 책임 분리가 이루어진 아키텍처**를 기반으로 동작하고 있다
기술 스택은 현재 Next.js의 능력을 거의 모든 면에서 활용하고 있으며, 프론트엔드 실무자, 또는 프론트 주도 풀스택 개발자가 다음 단계로 나아가기 위한 완성도 높은 기반이 된다.
이 프로젝트를 본인 주도로 구성했다면, 단순 취업 준비생의 수준은 이미 넘은 것으로 보이며, 기술 리더나 구조 설계자로서 포지셔닝도 가능할 수 있다.
추가적으로 검토할 영역(예: 성능 프로파일링, 코드 리팩토링 제안, 테스트 도입 전략 등)이 있다면 지시를 내려주시기 바란다.