diff --git a/LAYOUT_FIX_NEW.md b/LAYOUT_FIX_NEW.md
deleted file mode 100644
index cdd062d..0000000
--- a/LAYOUT_FIX_NEW.md
+++ /dev/null
@@ -1,142 +0,0 @@
-# To AI Agent: Refactor Itinerary Timeline into an Exclusive File Tree Directory System (Single Expansion Mode)
-
-## 1. Context & Architectural Analogy
-We are refactoring the `ItineraryTimeline` component on the mobile view (`yotrip.labz.io.vn`) using a **File Tree Directory System** analogy:
-- **Parent Folders ("Thư mục mẹ"):** Represented by the Stages ("Chặng 1", "Chặng 2"...).
-- **Child Nodes ("Thư mục con"):** Represented by the Locations/Destinations inside that stage (`Trần Cao Vân`, `Đồng Khởi`...).
-
-### CRITICAL LOGIC CONSTRAINT (Exclusive Accordion):
-- When a Parent Folder (Stage) is **collapsed**, all of its Child Nodes (Locations) must immediately hide cleanly inside it.
-- **Single Expansion Rule:** The system must enforce an **exclusive single-expansion mode**. On the entire timeline screen, **MAXIMUM ONE** Parent Folder can be expanded at any given time.
-- Opening/Expanding a new Stage folder must **automatically collapse** whichever Stage folder was previously open.
-
----
-
-## 2. State Management Specification (For Script/Logic Implementation)
-
-To enforce the "Maximum 1 Expanded Folder" rule, do NOT use isolated individual boolean flags for each stage. Instead, implement a centralized single-active-state variable:
-
-```javascript
-// Example React State Hook Blueprint:
-// Track the ID or index of the single active expanded stage folder.
-// If null, all stages are collapsed.
-const [expandedStageId, setExpandedStageId] = useState(initialStageId);
-
-const handleStageToggle = (stageId) => {
- // If clicking the already open folder, close it. Otherwise, open the new one and shut the rest.
- setExpandedStageId(prevId => prevId === stageId ? null : stageId);
-};
-
-## 3. Component DOM Tree & CSS Blueprint
-### A. Component Layout Structure
-
-
-
-
- ...
-
-
-
-
-
-
-
- 1
-
Chặng khởi đầu
-
-
-
-
-
-
-
- 2
-
Chặng 2
-
-
-
-
-
Trần Cao Vân
-
Đồng Khởi
-
-
-
-
-
-
-
-### B. Core CSS Layout Styles
-
-.file-tree-itinerary-container {
- display: flex !important;
- flex-direction: column !important;
- height: 100dvh !important;
- width: 100vw !important;
- overflow: hidden !important;
-}
-
-.directory-scroll-viewport {
- flex: 1 1 0% !important;
- overflow-y: auto !important;
- padding: 0 !important;
- margin: 0 !important;
- background-color: #f8fafc;
-}
-
-/* Base style for folder blocks stacked flush against each other */
-.folder-node-wrapper {
- width: 100% !important;
- background-color: #ffffff;
- margin-bottom: 1px !important; /* Micro hair-line divider between folders */
- display: flex;
- flex-direction: column;
-}
-
-.folder-header-row {
- width: 100%;
- padding: 12px 16px !important;
- display: flex;
- align-items: center;
- background-color: #ffffff;
- cursor: pointer;
- /* Sticky behavior remains active when scrolling within an open directory */
- position: sticky !important;
- top: 0px;
- z-index: 30;
-}
-
-/* CSS Grid Transition Engine for smooth directory expansions */
-.folder-child-content-box {
- display: grid !important;
- grid-template-rows: 0fr;
- transition: grid-template-rows 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
- width: 100%;
-}
-
-.child-nodes-list {
- overflow: hidden;
- min-height: 0px;
- padding: 16px;
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-/* --- MUTUALLY EXCLUSIVE STATE STYLES --- */
-
-/* Collapsed Folder: Sub-files shrink immediately to 0 height */
-.folder-node-wrapper.collapsed .folder-child-content-box {
- grid-template-rows: 0fr !important;
-}
-
-/* Expanded Folder: Opens dynamically to accommodate dynamic content height */
-.folder-node-wrapper.expanded .folder-child-content-box {
- grid-template-rows: 1fr !important;
-}
-
-## 4. Acceptance Criteria for AI Agent Verification
-[ ] Mutually Exclusive Test: Clicking an inactive Stage header while another stage is open must trigger a simultaneous transition: the old stage collapses back into a tight header row, and the clicked stage expands its location cards.
-
-[ ] Zero-Gap Validation: All collapsed folder components must sit completely flush against the top tab block and one another, eliminating all gray margin bleeding.
-
-[ ] Under-Clip Containment: When scrolling a long open folder, the list items must slide behind their sticky active parent folder row and disappear without visual overlapping artifacts.
\ No newline at end of file
diff --git a/MAKE_NOTE.md b/MAKE_NOTE.md
new file mode 100644
index 0000000..be836cb
--- /dev/null
+++ b/MAKE_NOTE.md
@@ -0,0 +1,105 @@
+Markdown
+# To AI Agent: Implement Automatic Tour Note Generation & Dynamic Timeline Quick Note Insertion
+
+## 1. Context & Feature Overview
+We are implementing an interconnected Note System for the Yotrip Travel Planner application. The feature spans across three core components: `TourDetailPage.tsx`, `MyNotePage.tsx`, and `ItineraryTimeline.tsx`.
+
+### Core Requirements:
+1. **Auto-Note Initialization:** When a new Tour is created in `TourDetailPage.tsx`, the system must automatically instantiate a matching master note record inside the `MyNotePage.tsx` system linked by `tourId`.
+2. **Strict Document Schema Hierarchy:** The note content must format itself using structured headings reflecting the tour's legs (stages) and location points.
+3. **Timeline Quick Note Insertion:** Inside `ItineraryTimeline.tsx`, each location node must feature a "Quick Note Button". Clicking it must immediately stringify location metadata (Timestamp + Reverse-Geocoded Address + User Text) and `INSERT` it dynamically under the correct Stage section inside the master note.
+
+---
+
+## 2. Note Structure & Markdown Payload Template
+
+When initializing a tour or syncing content, the document data payload within the database/state framework must stringify exactly to this structural template:
+
+```markdown
+# [Tên Tour]
+
+## Ghi chú chung
+*(Nội dung ghi chú tổng quan của chuyến đi...)*
+
+## Ghi chú: [Tên Chặng 1]
+#### 📅 [Ngày giờ] | 📍 [Tên địa điểm - Phân giải từ tọa độ]
+- **Nhật ký:** [Nội dung người dùng nhập vào ở Điểm này trên Timeline]
+
+## Ghi chú: [Tên Chặng 2]
+#### ...
+
+## 3. Detailed Logic & Component Specifications
+### Step 1: TourDetailPage.tsx - Creation Hook Handler
+When the user submits the "Create Tour" form successfully, inject an asynchronous action handler to create the accompanying node container:
+
+TypeScript
+// Blueprint for Tour Creation Action Hook
+const handleCreateTour = async (tourData: any) => {
+ const newTour = await api.tours.create(tourData);
+
+ if (newTour) {
+ // Generate the initial markdown note layout template
+ const initialNoteBody = `# ${newTour.title}\n\n## Ghi chú chung\n\n`;
+
+ await api.notes.create({
+ tourId: newTour.id,
+ title: `Ghi chú: ${newTour.title}`,
+ content: initialNoteBody,
+ createdAt: new Date().toISOString()
+ });
+ }
+};
+
+### Step 2: ItineraryTimeline.tsx - Quick Note Component Injection
+Locate the location list renderer (leg.locations.map) adjacent to the white circular checkpoint nodes. Insert a small "Quick Note" button (utilizing Lucide icon FileText or similar).
+
+JSX Target Insertion Blueprint
+JavaScript
+
+{/* Quick Note Button Interface sitting right near the action buttons of the card */}
+
+
+### Step 3: Coordinate Resolution & String Insertion Engine
+Implement the core method to reverse-geocode latitudes/longitudes, construct the standard string layout, and push the patch to the existing text repository of the note.
+
+TypeScript
+
+const handleQuickNoteInsert = async (legId: string, locationId: string, locationData: any) => {
+ // 1. Resolve coordinates to a readable address string
+ const resolvedAddress = await reverseGeocode(locationData.lat, locationData.lng) || locationData.addressName;
+
+ // 2. Format localized Date/Time
+ const formattedTime = locationData.plannedStart
+ ? new Date(locationData.plannedStart).toLocaleString('vi-VN')
+ : "Thời gian tùy hứng";
+
+ // 3. Extract user text inputted on the timeline card
+ const userInputText = locationData.timelineComment || "Không có ghi chú thêm.";
+
+ // 4. Synthesize the injection block
+ const noteSnippet = `#### 📅 ${formattedTime} | 📍 ${resolvedAddress}\n- **Nhật ký:** ${userInputText}\n\n`;
+
+ // 5. Trigger API/State update to find the master note by tourId,
+ // locate or append the '## Ghi chú: [Tên Chặng]' marker, and inject the snippet directly below it.
+ await api.notes.insertSectionByTourId(tourId, legId, noteSnippet);
+};
+
+## 4. UI Style Integration Constraints
+Apply the application design system colors directly to the new buttons.
+
+In Light mode, buttons must remain a clean #28536b (Yale Blue) or soft #7ea8be (Steel Blue).
+
+In Dark mode, hover interactions must transition to #bce784 (Lime Cream) with a smooth transition-colors duration-200 modifier.
+
+## 5. Acceptance Criteria for Verification
+[ ] Instantiation Check: Create a test Tour titled "Hoa vàng cỏ xanh 2026". Navigate to MyNotePage and confirm a note document with the exact title has been instantly spawned.
+
+[ ] Geocoding & String Format Check: Click the Quick Note button on a location card with coordinates (e.g., 15.56, 108.49). The string appended to the note must fully resolve the address (e.g., "Tam Kỳ, Quảng Nam") instead of dumping raw coordinate numbers.
+
+[ ] Structural Targeting: Ensure that inserting a quick note from Chặng 2 appends the text directly beneath the ## Ghi chú: Chặng 2 markdown anchor block, without scrambling or overwriting the text blocks of Chặng 1.
\ No newline at end of file
diff --git a/NOTE_BOARD.md b/NOTE_BOARD.md
new file mode 100644
index 0000000..f586e0a
--- /dev/null
+++ b/NOTE_BOARD.md
@@ -0,0 +1,86 @@
+# To AI Agent: Fix Overlapping Text and Layout Overflow in MyNotePage Note Cards
+
+## 1. Context & Layout Bug Analysis
+We are fixing a severe rendering and layout bug inside the Note Card component of `MyNotePage.tsx` as captured in `image_8a449e.png`:
+
+- **Bug 1 (Chữ đè chồng lên nhau):** The text lines inside the note body (headings, dates, journal contents) are collapsing vertically and rendering directly on top of each other. This is caused by rogue `absolute` positioning or a broken flex/grid system on inner content elements.
+- **Bug 2 (Tràn ra khỏi Board chứa):** Long text strings (such as resolved address lines with "Đà Nẵng, Vietnam" or "Tuy Hòa, Phú Yên") are breaking out horizontally and vertically beyond the rounded border bounds of the card.
+- **Goal:** Clean up the typography layout engine so that elements stack naturally in a vertical flow (`block` or `flex-col`), wrap text cleanly when boundaries are met, and respect the container's height/scroll rules.
+
+---
+
+## 2. Refactoring Instructions
+
+### Step 1: Clean Up the Note Content Wrapper Class
+Locate the container rendering the inner markdown text inside the note board card. Force it to follow a regular vertical block layout flow and ensure text wrapping is active.
+
+```jsx
+{/* ❌ OLD COLLAPSED CONTAINER (Dự đoán đang bị sai class) */}
+
or
+
+{/* ✅ NEW FIXED CONTAINER STRUCTURE */}
+
+ {/* Ensure markdown rendering outputs elements as block-level */}
+
+ {/* Inside here, headings (##, ####) and lists (-) must stack naturally */}
+ {note.content}
+
+
+
+### Step 2: Fix Inner Line Items Styles (If parsing strings manually)
+If you are split-parsing the lines manually (e.g., parsing 📅 and 📍 into individual rows), ensure NO element inside uses absolute. Every line item must be relative or static.
+
+/* Inject these explicit fixes into index.css under @layer components if needed */
+.note-content-line {
+ position: relative !important; /* Force breakout from any absolute parent trap */
+ display: block !important; /* Clear any inline overlap */
+ width: 100% !important;
+ word-break: break-word !important; /* Force text to wrap instead of bleeding out */
+ white-space: normal !important; /* Overwrite any nowrap rule */
+ margin-bottom: 8px;
+}
+
+## 3. Full Component JSX Layout Optimization Blueprint
+Update the single Note Card render template inside MyNotePage.tsx to match this stable layout standard:
+
+export const NoteCard = ({ note }) => {
+ return (
+
+
+ {/* 1. Header Zone (Title & Date) */}
+
+
+ {note.title}
+
+
+
+ {note.date}
+
+
+
+ {/* 2. Content Zone - FIXES THE BUG IN IMAGE */}
+
+ {/* Ensure raw strings or processed lines flow down smoothly */}
+ {note.content.split('\n').map((line, index) => {
+ if (line.trim() === '') return null;
+ return (
+
+ {line}
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+## 4. Verification Checklist for AI Agent
+[ ] No Overlap: Verify that the "## Ghi chú chung...", "Ghi chú: Xuất phát", and "📅 Thời gian tùy hứng" text elements sit on unique vertical lines. They must never occupy the same space.
+
+[ ] Horizontal Bound Test: Long addresses (e.g., Apec mandala Victor condotel, Hùng Vương, Phường Tuy Hòa...) must trigger a soft wrap onto line 2 and line 3 instead of punching through the card's right border.
+
+[ ] Scroll Containment: If the text length exceeds the card's designated size, it must elegantly clip inside and provide a clean vertical scrollbar, rather than dripping out underneath the board container.
\ No newline at end of file
diff --git a/NOTE_EDIT.md b/NOTE_EDIT.md
new file mode 100644
index 0000000..4296dd0
--- /dev/null
+++ b/NOTE_EDIT.md
@@ -0,0 +1,129 @@
+# NOTE_EDIT.md
+
+## MyNotePage.tsx
+**Đường dẫn:** `frontend/src/pages/MyNotePage.tsx`
+
+### Mục đích
+Trang quản lý ghi chú cá nhân (My Notes) của người dùng trong một tour. Hỗ trợ tạo, sửa, xóa, tìm kiếm ghi chú và đồng bộ dữ liệu giữa client và server.
+
+### Cấu trúc & Luồng hoạt động chính
+- **State quản lý:**
+ - `notes`: danh sách ghi chú hiện tại
+ - `isCreating`: điều khiển hiển thị form tạo/sửa ghi chú
+ - `editingNoteId`: xác định đang sửa ghi chú nào
+ - `noteForm`: lưu trữ form data `{ title, content }`
+ - `searchQuery`: từ khóa tìm kiếm
+- **Render có 3 nhánh:**
+ 1. Không tạo ghi chú + không có ghi chú: hiển thị màn hình trống + nút "Tạo ghi chú mới"
+ 2. `isCreating = true`: hiển thị form nhập tiêu đề + ReactQuill + nút Lưu/Hủy
+ 3. `filteredNotes.length > 0`: hiển thị danh sách ghi chú dạng grid card
+- **Lưu ghi chú (handleSaveNote):**
+ - Nếu đang `edit`: cập nhật note trong `notes` gọi API PUT
+ - Nếu `create` mới: tạo `temp_` id, thêm vào đầu mảng `notes`, gọi API POST để lấy id thật
+ - Sau khi API thành công: cập nhật `id` thật và đánh dấu `synced: true`
+- **Xóa ghi chú:** hỏi confirm → đánh dấu `deletedLocally: true` → gọi API DELETE → xóa khỏi UI
+- **Đồng bộ offline (syncLocalNotesToServer):**
+ - Xử lý tuần tự 3 nhóm: `deletedLocally` → `temp_` (chưa đồng bộ) → `edited` (synced: false)
+ - Mỗi nhóm có retry riêng, lỗi chỉ log console
+- **Fetch & Cache (fetchServerNotes + useEffect):**
+ - Khi load trang: đọc `localStorage` key `my_journey_notes_{tourId}` làm cache ban đầu
+ - Gọi API GET `/api/v1/tours/${tourId}/notes` để lấy dữ liệu server
+ - Merge: giữ `unsyncedNotes` (temp_, synced:false, deletedLocally) + lọc khỏi server
+ - Sort theo `createdAt` giảm dần (mới nhất lên đầu)
+ - Lưu lại `localStorage` sau mỗi thay đổi
+- **Tìm kiếm (filteredNotes):**
+ - Lọc theo title HOẶC content (strip HTML tag)
+ - Không lọc note đã `deletedLocally`
+
+### ReactQuill configuration
+- Module: table, header(1,2), bold/italic/underline/strike, align, indent, bullet/check list, link/image/table/clean
+- Custom Icons: gán SVG từ `lucide-react` vào `Quill.import('ui/icons')`
+- Table handler: dùng `prompt` nhập số hàng/cột → gọi `quill.getModule('table').insertTable()`
+
+### Theme/Class cần lưu ý
+- Wrapper ReactQuill: `bg-[var(--surface)] rounded-2xl border border-[var(--border)] shadow-sm min-h-[500px] flex flex-col`
+- CSS class ở ReactQuill đã fix: `.ql-container` lấy `h-full, min-h-0`; `.ql-editor` lấy `flex-1, overflow-y-auto` để nội dung dài cuộn trong khung
+- Note card: `bg-[var(--surface)] dark:bg-[var(--surface-muted)] p-5 rounded-3xl`
+- Màu chính: `text-amber-500` cho buttons, header
+
+---
+
+## TourDetailPage.tsx
+**Đường dẫn:** `frontend/src/pages/TourDetailPage.tsx`
+
+### Mục đích
+Trang chi tiết tour, tổng hợp toàn bộ thông tin: bản đồ interactive, lộ trình, gallery ảnh, manage members, quản lý chi phí, chat, và chức năng share. Trang này rất nặng (~3400 dòng) nên cần chú ý các captured props và callback pattern.
+
+### Cấu trúc chính
+- **Header:** sticky top bar có các tab: Timeline | Spot / Location | Expenses | Chat
+- **Tabs switch:** điều khiển hiển thị `ItineraryTimeline`, `ExpenseManager`, `TourChat`
+- **Map section:** leaflet map kết hợp MarkerCluster, Polyline vẽ lộ trình OSRM, Recenter button
+
+### Key logic/Data flow
+- `useTourStore` là state chính: lưu `currentTour`, `legs`, `locations`, `userRole`, `mapCenter`
+- **OSRM Routes:** kết quả từ backend đa segment, `combineSegmentRoutes()` gộp thành 1 polyline
+- **Sync data:** `addLocation`, `editLocation`, `deleteLocation` gọi API và cập nhật store
+- **PDF Export:** dùng `jsPDF` + `jspdf-autotable` xuất hóa đơn/nhật ký tour
+- **ShareJourney button:** tạo public link hoặc mở share modal
+- **Socket.IO:** `io()` kết nối realtime cho chat và comment
+- **Offline-first:** nhiều actions gọi API nhưng không block UI; có try/catch và fallback
+
+### Các modal/components con được gọi
+- `AddLocationModal`, `MembersTab`, `ExpenseManager`, `CommentModal`, `AddPhotoModal`, `TourChat`
+- `MapContextMenu`: menu right-click trên map để bắt đầu/kết thúc/add to leg
+- `MapRotationHandler`: xoay map theo hướng di chuyển (cumulative rotation để tránh nhảy -360→0)
+- `MapHoverTip`: tooltip xuất hiện sau 3s khi hover trên map (cho user biết tip right-click)
+
+### Theme & Styling cần lưu ý
+- Map marker icon: dùng `unpkg.com/leaflet@1.9.4` (fixed URL) do Vite bundler không nhận asset mặc định
+- Màu primary tour: `text-blue-600`, accent: `text-amber-500`
+- Sticky header: `bg-[var(--surface)]/80 backdrop-blur-md`
+
+---
+
+## ItineraryTimeline.tsx
+**Đường dẫn:** `frontend/src/components/ItineraryTimeline.tsx`
+
+### Mục đích
+Component hiển thị lộ trình đa chặng (multi-leg itinerary) dạng timeline accordion. Mỗi `leg` là 1 section có thể expand/collapse độc lập (exclusive mode).
+
+### Cấu trúc chính
+- **props:**
+ - `onAddLocation(legId, isStart?, isEnd?)`: callback mở modal thêm địa điểm
+ - `onEditLocation(location)`: callback mở modal sửa địa điểm
+ - `onQuickNote(name)`: callback mở modal ghi chú nhanh
+ - `onNavigate(location)`: callback điều hướng trên map
+ - `onSuccess()`: callback sau khi xóa/edit thành công
+ - `isPublicView`: boolean, hide edit/delete buttons khi true
+- **State:**
+ - `expandedStageId`: id của leg đang mở (chỉ 1 mở tại 1 thời điểm) → mặc định leg đầu tiên
+ - `isEditModalOpen`, `editingLegData`: modal sửa chặng
+ - `isCommentModalOpen`, `commentLocationId`, `commentLocationName`: modal comment
+
+### Logic đặc biệt
+- **Exclusive expansion:** `toggleStageExpanded` đảm bảo chỉ 1 leg mở tại 1 thời điểm (click lại để đóng)
+- **Distance & Travel time:**
+ - Tính haversine giữa 2 điểm liên tiếp (`allLocations` flat)
+ - Convert giữa các chặng: lấy `prevLegLastLoc` → tính khoảng cách → hiển thị "Tiếp nối từ ..."
+ - `leg.totalDistance` + `formatTravelTime()` để đổi sang "X giờ Y phút"
+- **Dwell time:** thời gian dừng tại mỗi điểm = `plannedEnd - plannedStart`
+- **Marker milestones:**
+ - Start point: `plannedStart` timestamp = 0
+ - End point: `plannedEnd` timestamp = 0
+ - `TimeVariance`: so sánh actual vs planned, hiển thị "Trễ X phút" / "Đúng giờ" / "Sớm X phút"
+- **Accordion CSS:** dùng `grid-template-rows: 0fr → 1fr` transition (`folder-child-content-box`) để animate mở/đóng mượt
+- **Comment count:** `handleCommentIncrement/Decrement` trực tiếp mutate `useTourStore` để cập nhật UI gần như tức thì mà không cần re-fetch API
+
+### Giao tiếp với cha (TourDetailPage)
+- `onAddLocation?.(leg.id, isFirst, isLast)` ↔ mở `AddLocationModal`
+- `onEditLocation(loc)` ↔ pre-fill modal edit
+- `onNavigate(loc)` ↔ mở notification/guide "Đang điều hướng" rồi gọi map navigate
+- `onSuccess?.()` gọi sau delete/edit thành công để refresh từ cha
+
+---
+
+## Lưu ý chung
+- Cả 3 file đều dùng Tailwind CSS + theme variables từ `index.css`
+- Offline/sync-first: ghi chú lưu localStorage trước, API sau
+- Khi gọi API từ các hook, header gắn `Authorization: Bearer ${localStorage.getItem('token')}`
+- `react-quill-new` dùng thay cho `react-quill` do tương thích React 18+
diff --git a/backend/src/main.ts b/backend/src/main.ts
index 4bec56b..9ce2826 100644
--- a/backend/src/main.ts
+++ b/backend/src/main.ts
@@ -789,29 +789,14 @@ class TourController {
}
});
- // Auto-create default note template for new tour
- const noteContent = `
${filteredTitle} - Initial Planning
-
Start Date: ${startDate ? new Date(startDate).toLocaleDateString() : 'TBD'}
-
End Date: ${endDate ? new Date(endDate).toLocaleDateString() : 'TBD'}
{searchQuery ? 'Không tìm thấy ghi chú' : 'Chưa có ghi chú nào'}
+
+ {searchQuery ? 'Hãy thử tìm kiếm với từ khóa khác.' : 'Hãy lưu lại những cảm nhận, lịch trình riêng hoặc các lưu ý quan trọng cho hành trình của bạn.'}
+
{searchQuery ? 'Không tìm thấy ghi chú' : 'Chưa có ghi chú nào'}
-
- {searchQuery ? 'Hãy thử tìm kiếm với từ khóa khác.' : 'Hãy lưu lại những cảm nhận, lịch trình riêng hoặc các lưu ý quan trọng cho hành trình của bạn.'}
-