# Quick Note Modal Design ## Background Current writing flow is centered on article creation. The user needs a faster way to jot down temporary or reusable notes without opening the full post creation flow. The quick note should be accessible near the top "Write Article" button and support a lightweight editing experience with media upload. ## Goals - Add a `Quick Note` entry to the left side of the top `Write Article` button. - Open a draggable modal that defaults to near-fullscreen and can switch to true fullscreen. - Provide a lightweight editor with upload support. - Store one unique quick note per authenticated user. - Use manual save only. - Protect unsaved changes when closing the modal or leaving the page. ## Non-goals - No auto-save in this iteration. - No multi-note list, categorization, or version history. - No public sharing capability. - No cross-user collaboration. ## User Experience ### Entry and Open - A `Quick Note` button appears to the left of `Write Article`. - Clicking `Quick Note` opens the modal and loads the current user's note from backend. - If no note exists, editor opens with empty content. ### Modal Behavior - Default state is near-fullscreen (small viewport margins). - Modal is draggable by title bar when not in fullscreen. - Top-right button toggles `Fullscreen` and `Exit Fullscreen`. - Fullscreen mode disables dragging. - Exiting fullscreen restores draggable mode and previous near-fullscreen frame behavior. ### Editor Behavior - Use a lightweight markdown editor configuration to reduce startup and UI complexity. - Keep upload capability aligned with existing article editor upload flow. - Editing updates local draft only until user clicks `Save`. ### Save and Unsaved Protection - Save button triggers manual persistence. - Unsaved state (`isDirty`) is determined by comparing `draftContent` against `savedContent`. - On modal close attempt with unsaved content, show confirmation dialog: - Confirm: close and discard unsaved changes in current session. - Cancel: keep modal open. - On page leave/refresh/navigation with unsaved content while modal is open, trigger browser `beforeunload` confirmation. - After successful save, dirty state is cleared. ## Architecture and Components ### Frontend - Add `Quick Note` trigger in the top action area where `Write Article` is rendered. - Add `QuickNoteModal.vue`: - Modal shell, header controls, drag behavior, fullscreen toggle, close interception. - Unsaved-close confirmation handling. - Register/unregister `beforeunload` guard while open. - Add `QuickNoteEditor.vue`: - Lightweight editor wrapper. - Minimal toolbar and markdown input area. - Upload hook integration by reusing existing editor upload bridge/uploader path. - State model inside modal: - `savedContent: string` - `draftContent: string` - `isDirty: boolean` (derived) - `isSaving: boolean` - `isLoading: boolean` ### Backend - Introduce persistent user-unique quick note record. - Data model (`quick_notes` or project-consistent naming): - `id` - `user_id` (unique index) - `content` (text) - `created_at` - `updated_at` - Add API endpoints: - `GET /api/me/quick-note` - Returns current user's note content. - Returns empty content if no record exists. - `PUT /api/me/quick-note` - Accepts `content`. - Performs upsert by `user_id`. - Returns saved content and timestamps. ## Data and Validation Rules - Endpoint access requires authenticated `me` context. - Content must be string. - Enforce max content length (proposed: 200,000 chars) to prevent abuse and oversized payloads. - Normalize line endings server-side to keep storage consistent. ## Error Handling - Load failure: show inline load error with retry option. - Save failure: keep `draftContent` untouched, preserve dirty state, and show save error toast/message. - Concurrent upsert conflicts (rare): service layer retries update path once after conflict. ## Testing Strategy ### Frontend Unit Tests - `QuickNoteModal` open/close, fullscreen toggle, drag enable/disable switching. - Dirty-state derived behavior for save success/failure. - Close interception when dirty. - `beforeunload` guard registration lifecycle and dirty-condition trigger. - `QuickNoteEditor` upload insertion path and save event behavior. ### Backend Unit Tests - `GET /api/me/quick-note` with existing note. - `GET /api/me/quick-note` with no existing note. - `PUT /api/me/quick-note` create path and update path. - Validation rejection for non-string or oversized payload. - Auth rejection for unauthenticated access. ### Manual Acceptance - Quick Note button opens modal in near-fullscreen. - Fullscreen/exit button works as expected. - Draggable behavior works only outside fullscreen. - Unsaved close prompt appears on close attempts. - Browser leave prompt appears on refresh/navigate with unsaved changes. - Save persists content; reopening shows latest saved state. - Upload works in quick note editor and follows existing media behavior. ## Rollout and Compatibility - Feature can ship without affecting existing article editor behavior. - No migration impact on posts data. - New quick note storage is isolated to authenticated user scope. ## Open Decisions (Resolved) - Uniqueness scope: per authenticated user. - Save strategy: manual only. - Unsaved reminders: modal close + page leave. - Default view: near-fullscreen. - Fullscreen trigger: top-right toggle button. - Editor approach: lightweight editor with upload retained.