A memo & schedule management web app powered by Naver OAuth login.
Organize your todos and memos intuitively through drag-and-drop and a unified calendar view.
🇰🇷 한국어 설명 보기 (Click to expand)
네이버 로그인 기반의 메모 & 일정 관리 웹앱
드래그 앤 드롭과 통합 캘린더 뷰로 Todo와 메모를 직관적으로 관리하세요.
NaviyNote는 일정 관리와 메모 작성을 하나로 통합한 웹 서비스입니다.
네이버 로그인을 기반으로 사용자의 Todo와 메모를 연동하고 시각적으로 관리할 수 있도록 도와줍니다.
- Todo & 메모 간 1:1 연동
- 드래그 앤 드롭을 활용한 직관적인 일정 및 메모 상태 관리
- 네이버 캘린더 연동 (일정 등록)
- 통계 & 친구 기능 (3차 배포 예정)
"쉽게 적고, 일정에 연결하자"
메모와 일정은 서로 가깝지만 대부분 따로 관리됩니다.
NaviyNote는 두 기능을 하나로 연결해 효율적인 개인 기록 관리를 돕습니다.
- 서비스 소개 및 데모 영상
- 네이버 로그인 버튼 및 네비게이션 헤더
- 최근 수정 메모 10개 (전체보기 버튼 포함)
- 오늘 기준 ±5일 Todo (전체보기 버튼 포함)
- 중요 Todo 6개
- 통계 및 친구 요약 (임시 데이터 기반)
- CRUD 완전 지원
- FullCalendar 기반 캘린더 뷰
- 날짜 없는 Todo를 캘린더로 드래그하여 일정화 가능
- 캘린더 내 일정 날짜 이동 가능
- 인터셉트 라우팅 기반 상세 모달
- 네이버 캘린더에 일정 등록 가능
- CRUD 완전 지원
- 중요/비중요 × 활성/비활성의 4분할 드래그 앤 드롭 그리드
- 인터셉트 라우팅 기반 상세 모달
- Todo 연동 플래그 (
connect) 지원
- YearMonthPicker로 연도·월을 선택해 연결할 Todo 범위 필터링 (2025–2027)
- 연동 시 기존 연결 자동 해제 (Supabase 수준 무결성 보장)
- Memo → Todo, Todo → Memo 양방향 연결
- Sonner 토스트 알림 — 로컬 에러 상태 제거, 전역
<Toaster>로 통합 - useScrollLock 훅 — 모달 열림/닫힘 시 body 스크롤 잠금 자동 관리
- 삭제 확인 오버레이 — 실수 삭제 방지를 위한 인라인 확인 UI
- 전역 Error 페이지 (
error.tsx) — 재시도 및 홈 이동 버튼 포함
- 시맨틱 색상 토큰 (primary, secondary, accent, surface, danger)
- 레거시 토큰 병행 유지 (navy, navy2, navy3, lightnavy, red)
- 커스텀 타이포그래피 스케일 (ui-caption ~ ui-mega)
- 커스텀 레이아웃 토큰 (width, height, minHeight, maxWidth)
fadeInScale애니메이션 토큰- NanumGothic 웹폰트 (Regular / Bold / ExtraBold)
- 반응형 레이아웃 (sm 브레이크포인트: 768px)
- 3차 배포 예정 (준비 중)
| 카테고리 | 내용 | 사용 기술 |
|---|---|---|
| 프론트엔드 | UI/UX 개발 | Next.js 15, TypeScript, Tailwind CSS |
| 상태 관리 | 전역 상태 | Zustand |
| 인증 | 네이버 OAuth 로그인 | NextAuth.js |
| 데이터베이스 | 메모 & Todo 저장 | Supabase |
| 캘린더 | 일정 UI | FullCalendar |
| 드래그 앤 드롭 | 메모 상태 변경 & 일정 등록 | react-dnd |
| 토스트 알림 | 사용자 피드백 | Sonner |
| 차트 | 통계 시각화 (준비 중) | Chart.js |
| 배포 | 호스팅 | Vercel |
| 코드 품질 | 컨벤션 및 정적 분석 | ESLint, Prettier, Husky |
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
NEXTAUTH_SECRET=
NEXTAUTH_URL=
NAVER_CLIENT_ID=
NAVER_CLIENT_SECRET=
NEXT_PUBLIC_GOOGLE_ANALYTICS= # 선택npm install
npm run dev프로젝트 수행 결과(데모)는 페이지 최하단의 데모 영상 보기 섹션에서 확인하실 수 있습니다.
NaviyNote is a personal productivity web service that unifies memo writing and schedule management into a single, cohesive experience. Authenticated via Naver OAuth, users can create, categorize, and link their memos and todos — then push events directly to Naver Calendar.
Key design goals:
- "Write it quick, link it to a schedule." Memos and todos live side-by-side and connect with a single action.
- A drag-and-drop interface that makes state changes feel effortless.
- A polished, consistent design system built on semantic Tailwind tokens.
- Production-grade UX: global error recovery, accessible toast feedback, and scroll-safe modals.
- Product introduction with a feature overview and demo video
- Naver Sign-In button and top navigation header
- Greeting banner and personalized summary
- Recent memos — the 10 most recently created or updated memos, with a "View All" button
- Upcoming todos — todos within ±5 days of today, with a "View All" button
- Important todos — up to 6 pinned high-priority todos
- Statistics and friend summary widgets (placeholder data; full release in v3)
- Full CRUD support
- FullCalendar view — monthly grid with interactive event placement
- Drag date-less todos onto the calendar to assign a date
- Drag existing calendar events to reschedule them
- Detail view via intercepting route modal (no full-page reload)
- Add to Naver Calendar — push any todo directly to the user's Naver Calendar account
- Full CRUD support
- 4-zone drag-and-drop grid categorized by two boolean flags:
active(active / inactive)important(important / not important)
- Drag a memo card between zones to instantly update its flags
- Detail view via intercepting route modal
connectflag marks a memo as linkable to a todo
- YearMonthPicker — select a year (2025–2027) and month to filter the available todos before linking
- Each memo can be linked to at most one todo, and vice versa
- When a new link is created, the previous link is automatically nullified — enforced at both the application layer and the Supabase schema level
- Linking works in both directions: Memo → Todo and Todo → Memo
All user-facing feedback (errors, successes, warnings) is delivered through Sonner, mounted once via <Toaster richColors position="top-center" /> in the root layout. Local error state variables have been removed from individual components in favor of toast.error() / toast.success() calls.
A custom useScrollLock hook (src/hooks/useScrollLock.ts) manages document.body.style.overflow for every modal:
- Sets
overflow: hiddenon mount to prevent background scroll while a modal is open. - Restores
overflow: ''on unmount, including after the modal is closed via a delete action — fixing a previous scroll-lock regression.
Destructive delete actions in memo and todo modals now render an inline confirmation overlay before executing, preventing accidental data loss.
A root-level src/app/error.tsx catches unhandled runtime errors anywhere in the app and renders a branded recovery screen with:
- A Retry button (
reset()) to re-render the failed subtree without a full reload. - A Go Home button that navigates back to
/.
- Placeholder pages; full feature set planned for v3
| Category | Purpose | Technology |
|---|---|---|
| Frontend | UI & routing | Next.js 15 (App Router), TypeScript |
| Styling | Design system | Tailwind CSS 3 |
| State management | Client-side global state | Zustand 5 |
| Authentication | Naver OAuth sign-in | NextAuth.js 4 |
| Database | Memo & todo persistence | Supabase (PostgreSQL) |
| Calendar UI | Schedule display & interaction | FullCalendar 6 |
| Drag and drop | Memo zone changes, calendar placement | react-dnd 16 |
| Toast feedback | User notifications & error reporting | Sonner |
| Charts | Stats visualization (future) | Chart.js 4 |
| Deployment | Hosting & CI | Vercel |
| Code quality | Linting, formatting, git hooks | ESLint, Prettier, Husky, lint-staged |
naviynote/
├── src/
│ ├── app/
│ │ ├── layout.tsx # Root layout — fonts, session, <Toaster>
│ │ ├── error.tsx # Global error boundary (reset + home)
│ │ ├── not-found.tsx # 404 page
│ │ ├── (pages)/
│ │ │ ├── (landing)/page.tsx # Landing / home
│ │ │ ├── main/page.tsx # Dashboard
│ │ │ ├── memo/
│ │ │ │ ├── page.tsx
│ │ │ │ ├── memoItem/[memoId]/page.tsx
│ │ │ │ └── @memoModal/(.)memoItem/[memoId]/page.tsx # Intercepting route
│ │ │ ├── todo/
│ │ │ │ ├── page.tsx
│ │ │ │ ├── todoItem/[todoId]/page.tsx
│ │ │ │ └── @todoModal/(.)todoItem/[todoId]/page.tsx # Intercepting route
│ │ │ ├── stats/page.tsx
│ │ │ └── friend/page.tsx
│ │ └── api/
│ │ ├── auth/[...nextauth]/ # NextAuth handler + SessionWrapper
│ │ └── naver/add-schedule/ # Naver Calendar proxy endpoint
│ ├── hooks/
│ │ └── useScrollLock.ts # Body scroll lock/unlock for modals
│ └── store/
│ ├── memoStore.ts # Zustand memo store
│ └── todoStore.ts # Zustand todo store
├── components/
│ ├── Header/ # Global header & nav
│ ├── Main/ # Dashboard widgets
│ ├── Memo/ # Memo list, modal, drop zones
│ │ ├── memosServer.tsx # Server actions (Supabase CRUD)
│ │ └── YearMonthPicker.tsx # Date range selector for memo-todo linking
│ ├── ToDo/ # Todo list, modal, calendar
│ │ └── todosServer.tsx # Server actions (Supabase CRUD)
│ ├── Button.tsx
│ ├── Loading.tsx
│ └── Footer.tsx
└── lib/
├── supabase.ts # Supabase client
└── GoogleAnalytics.tsx
- Server fetch functions (
memosServer.tsx,todosServer.tsx) query Supabase directly on the server. - Client components call these on mount (gated by
useSession), then populate the Zustand stores (useMemoStore,useTodoStore). - CRUD mutations update both Supabase and the store optimistically, so the UI reflects changes instantly.
- User feedback is delivered via
toast.error()/toast.success()(Sonner) rather than local state variables, keeping component logic lean.
Both memo and todo detail pages use Next.js parallel + intercepting routes:
@memoModal/(.)memoItem/[memoId]— intercepts navigation to/memo/memoItem/:idand renders a modal overlay instead of a full page load.@todoModal/(.)todoItem/[todoId]— same pattern for todos.
Every modal uses useScrollLock to lock the background page scroll on open and reliably restore it on close — including after a successful delete.
Each memo holds a todo_id foreign key; each todo holds a memo_id foreign key. When addMemo or updateMemo creates a new link, the server action first nullifies the old memo's todo_id, ensuring neither side ends up pointing to two records simultaneously.
src/app/error.tsx is a Next.js App Router error boundary that wraps the entire page tree. It catches unhandled exceptions and renders a recovery UI without crashing the shell (header, footer remain intact). The reset function re-mounts the failed segment; the home button provides a full escape hatch.
NaviyNote ships with a custom Tailwind design system defined in tailwind.config.ts.
Both semantic aliases and the original raw brand names are registered so existing code continues to work alongside new semantic usage.
| Semantic token | Raw alias | Hex | Usage |
|---|---|---|---|
primary |
navy |
#003366 |
Brand color, headings, active nav |
secondary |
navy2 |
#4169E1 |
Buttons, interactive elements, form focus rings |
accent |
navy3 |
#6495ED |
Modal highlights, secondary accents |
surface |
lightnavy |
#99CCFF |
Card chip backgrounds, zone labels |
danger |
red |
#FF6347 |
Important flag, destructive actions |
| Class | Size / Line-height | Use case |
|---|---|---|
text-ui-caption |
1rem / 1.5rem | Footer, fine print |
text-ui-sm |
1.5rem / 2rem | Labels, badges |
text-ui-md |
2rem / 2.5rem | Section headings, nav links |
text-ui-lg |
2.3rem / 3rem | Feature body text |
text-ui-xl |
3.2rem / 4rem | Hero headings |
text-ui-mega |
10rem / 1 | Loading spinner display |
| Class | Keyframes | Use case |
|---|---|---|
animate-fade-in-scale |
opacity 0→1, scale 0.95→1 over 0.15s |
Modal entrance |
Custom width / height / minHeight / maxWidth values cover recurring layout measurements so magic numbers are eliminated from component code.
| Category | Key examples |
|---|---|
width |
content (100rem), calendar (50rem), form-sm/md/lg/xl/2xl, logo-* |
height |
header (8.6rem), calendar (50rem), landing, not-found, page-loading |
minHeight |
zone (16rem — memo drop zones), memo-panel (59rem) |
maxWidth |
content (100rem) |
NanumGothic is loaded from public/fonts/ via next/font/local and exposed as CSS variables:
--font-nanumgothic-regular(400)--font-nanumgothic-bold(700)--font-nanumgothic-extrabold(800)
sm: 768px— switches from stacked mobile layout to side-by-side desktop layout- Fine-grained overrides use Tailwind's arbitrary-value syntax (e.g.,
max-[400px]:text-xs)
NaviyNote uses NextAuth.js with a custom Naver OAuth provider.
Scopes requested: calendar — required for the Naver Calendar integration.
Session flow:
- User clicks "Sign in with Naver" → redirected to Naver OAuth.
- On success, NextAuth stores the Naver
access_tokenin the JWT. - The
sessioncallback exposesaccessTokento client components. SessionWrapperwraps the app withSessionProviderto makeuseSession()available everywhere.- After sign-in, users are redirected to
/main.
Naver Calendar proxy (/api/naver/add-schedule): forwards todo payloads (iCal format) to https://openapi.naver.com/calendar/createSchedule.json using the stored access token.
- Node.js ≥ 18
- A Supabase project with
memosandtodostables - A Naver Developer app with OAuth credentials and Calendar scope enabled
Create .env.local in the project root:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
NEXTAUTH_SECRET=a_random_secret_string
NEXTAUTH_URL=http://localhost:3000
NAVER_CLIENT_ID=your_naver_oauth_client_id
NAVER_CLIENT_SECRET=your_naver_oauth_client_secret
NEXT_PUBLIC_GOOGLE_ANALYTICS= # optionalnpm install
npm run dev # Development server at http://localhost:3000
npm run build # Production build
npm run lint # ESLint check (next lint)Pre-commit hooks run automatically via Husky + lint-staged: ESLint --fix on .ts/.tsx files, Prettier on .md/.json files.