어드민만 Next.js가 아니라 Vite + React SPA로 만들고, 라우팅은 TanStack Router 파일 기반으로 잡았다
대안블로그·포트폴리오와 같이 Next.js App Router로 통일하거나, 어드민을 블로그 앱 안의 /admin 경로로 흡수하는 안근거어드민은 전부 로그인 뒤 화면이라 SSR·RSC·SEO에서 얻는 게 없고, 오히려 서버 컴포넌트 경계가 편집 폼의 클라이언트 상태를 쪼개는 비용만 남는다. 빌드도 세 앱 중 어드민만 정적 산출물이라 Vite 쪽이 훨씬 빠르다. 라우팅은 TanStack Query와 같은 계열이라 로더·캐시 연동이 자연스러웠다.비용세 앱 중 하나만 번들러·라우터·렌더링 모델이 달라, 공용 패키지가 Next와 Vite 양쪽 빌드에서 모두 동작해야 한다는 제약이 생겼다(packages/ui·packages/shared가 두 환경을 다 만족해야 한다). 앱 간 코드 이동도 그대로는 안 되고 라우팅·데이터 패칭을 다시 써야 한다.
어드민에서 Mantine을 전부 걷어내고 shadcn/Radix 기반 packages/ui 공용 컴포넌트로 통일했다 (커밋 b624987, 이어서 블로그의 중복 shadcn 컴포넌트도 00087bc에서 공용 패키지로 흡수)
대안어드민은 Mantine을 유지하고 공용 패키지는 타입·API 클라이언트만 공유하는 안근거어드민(Mantine)과 블로그(shadcn)가 서로 다른 컴포넌트 체계를 쓰면 같은 폼·다이얼로그·테이블을 두 번 만들게 되고, 디자인 토큰도 두 벌이 된다. shadcn은 컴포넌트 소스를 저장소가 소유하는 방식이라 공용 패키지로 끌어올리기가 쉬웠다.비용Mantine이 기본 제공하던 것들(날짜 입력, 폼 상태, 알림 등)을 직접 조립하게 되어 초기 작업량이 늘었고, 이전 작업 자체가 어드민 화면 전반을 건드리는 큰 diff라 그 시점에 다른 기능 작업을 병행할 수 없었다.
세션 만료를 요청 실패 시점에 처리하지 않고, 남은 시간을 초 단위로 세는 useSessionTimer 훅을 두어 만료 5분 전부터 경고와 연장 버튼을 노출했다
대안401 응답을 받으면 그때 로그아웃시키거나, 사용자 조작이 있을 때마다 조용히 세션을 연장하는 안근거어드민의 주 작업이 '긴 글을 Monaco 에디터에서 편집하는 것'이라, 저장 버튼을 누르는 순간 401이 나면 작성 중이던 본문을 잃는다. 남은 시간을 보여주고 만료 전에 연장을 제안하면 사용자가 저장 타이밍을 스스로 정할 수 있다.비용만료 시각을 클라이언트가 들고 세므로 탭이 오래 백그라운드에 있거나 기기 시계가 어긋나면 표시가 실제와 벌어질 수 있다. 표시가 정확해도 서버가 세션을 먼저 끊으면 소용없어서, 401 처리 경로를 없앤 게 아니라 그 위에 얹은 안전장치라는 점은 그대로 남는다.