diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..1a753fb --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,573 @@ +# Architecture Overview + +Project Notes is a web-based Markdown note-taking application built with a hybrid architecture combining Go backend, HTMX for interactions, and modern JavaScript for UI enhancements. + +## Design Philosophy + +**HTML Over The Wire**: The server renders HTML, not JSON. HTMX enables dynamic interactions without building a full SPA. + +**Progressive Enhancement**: Core functionality works with basic HTTP. JavaScript enhances the experience (CodeMirror editor, drag-and-drop, search modal). + +**Simplicity First**: Avoid framework complexity. Use the right tool for each job: +- Go for backend (fast, simple, type-safe) +- HTMX for AJAX (declarative, low JavaScript) +- Vanilla JS for UI (no framework overhead) +- Vite for building (fast, modern) + +## System Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Browser (Client) │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ HTMX │ │ CodeMirror │ │ JavaScript │ │ +│ │ (interactions)│ │ (editor) │ │ (UI logic) │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ │ +│ └──────────────────┴──────────────────┘ │ +│ │ │ +└────────────────────────────┼──────────────────────────────────┘ + │ HTTP (HTML) + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Go HTTP Server │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Handlers │ │ Indexer │ │ Watcher │ │ +│ │ (API) │◄─┤ (search) │◄─┤ (fsnotify) │ │ +│ └──────┬───────┘ └──────────────┘ └──────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ Templates │ │ +│ │ (Go html) │ │ +│ └──────────────┘ │ +│ │ +└────────────────────────────┬────────────────────────────────┘ + │ Filesystem + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Markdown Files (.md) │ +│ YAML Front Matter │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Component Interaction Patterns + +### 1. Page Load (Initial Render) + +``` +User → Browser + │ + ├─ GET / → Go Server + │ │ + │ ├─ Parse index.html template + │ ├─ Inject file tree + │ └─ Return HTML + │ + ├─ Load static/dist/project-notes-frontend.es.js (Vite bundle) + │ │ + │ ├─ Initialize FileTree (file-tree.js) + │ ├─ Initialize Search (search.js) + │ └─ Setup UI handlers (ui.js) + │ + └─ HTMX processes hx-* attributes + │ + └─ Triggers hx-get="/api/tree" (load file tree) + hx-get="/api/home" (load home page) +``` + +### 2. Opening a Note + +``` +User clicks file in tree → HTMX intercepts click (hx-get attribute) + │ + ├─ GET /api/notes/my-note.md → Go Server + │ │ + │ ├─ Read file + │ ├─ Parse front matter + │ ├─ Render editor.html template + │ └─ Return HTML fragment + │ + └─ HTMX swaps into #editor-container + │ + └─ Triggers htmx:afterSwap event + │ + └─ editor.js initializes CodeMirror +``` + +### 3. Drag and Drop File + +``` +User drags file → JavaScript (file-tree.js) + │ + ├─ dragstart: Store source path + ├─ dragover: Validate drop target + └─ drop: Calculate destination + │ + └─ htmx.ajax('POST', '/api/files/move') + │ + ├─ Go Server moves file + ├─ Re-indexes + ├─ Renders new file tree + └─ Returns HTML with hx-swap-oob="innerHTML" #file-tree + │ + └─ HTMX swaps file tree automatically + │ + └─ Triggers htmx:oobAfterSwap event + │ + └─ file-tree.js updates draggable attributes +``` + +### 4. Searching Notes + +``` +User types in search → HTMX (hx-get="/api/search" with debounce) + │ + ├─ Go Server + │ │ + │ ├─ Query indexer + │ ├─ Rank results + │ ├─ Render search-results.html + │ └─ Return HTML + │ + └─ HTMX swaps into #search-results +``` + +Alternative: Search Modal (Ctrl/Cmd+K) + +``` +User presses Ctrl+K → search.js opens modal + │ + └─ User types → Debounced fetch to /api/search + │ + ├─ Renders results in modal + └─ Keyboard navigation (JS) +``` + +### 5. Auto-Save in Editor + +``` +User types in editor → CodeMirror EditorView.updateListener + │ + ├─ Debounce 150ms → Update preview (JavaScript) + │ + └─ Debounce 2s → Trigger save + │ + ├─ Sync content to hidden textarea + └─ form.requestSubmit() + │ + └─ HTMX intercepts (hx-post="/api/notes/...") + │ + ├─ Go Server saves file + ├─ Updates front matter (last_modified) + ├─ Re-indexes + └─ Returns HTML with oob swap for file tree + │ + └─ HTMX updates file tree automatically +``` + +## Frontend Architecture + +### Build Process (Vite) + +``` +frontend/src/ +├── main.js → Entry point +├── editor.js → CodeMirror 6 + Slash Commands +├── file-tree.js → Drag & drop + HTMX coordination +├── search.js → Search modal (Ctrl/Cmd+K) +└── ui.js → Sidebar toggle + + ↓ (Vite build) + +static/dist/ +├── project-notes-frontend.es.js (1.0 MB - ES modules) +└── project-notes-frontend.umd.js (679 KB - UMD) + + ↓ (Loaded by browser) + +Executed in browser → Initializes components +``` + +### Module Responsibilities + +**main.js** +- Entry point +- Imports all modules +- No logic, just imports + +**editor.js** +- MarkdownEditor class (CodeMirror 6) +- SlashCommands class (command palette) +- View mode management (split/editor-only/preview-only) +- Preview rendering (marked.js + DOMPurify) +- Scroll synchronization +- Auto-save logic +- HTMX event listeners for editor initialization + +**file-tree.js** +- FileTree class (drag & drop) +- Event delegation for clicks (folder expand/collapse) +- Drag & drop event handlers +- htmx.ajax() for move operations +- Folder creation modal +- HTMX event listeners (htmx:oobAfterSwap) for updates + +**search.js** +- Search modal (Ctrl/Cmd+K) +- Keyboard navigation +- Debounced search +- Result highlighting +- Uses HTMX search API + +**ui.js** +- Sidebar toggle (mobile/desktop) +- Simple utility functions + +## HTMX Integration Patterns + +### Pattern 1: Declarative Links (Preferred) + +Use HTMX attributes directly in HTML for static interactions: + +```html + + 📄 my-note.md + +``` + +**When to use**: Static content, links, forms with fixed targets. + +### Pattern 2: JavaScript-Initiated Requests + +Use `htmx.ajax()` for dynamic interactions initiated by JavaScript: + +```javascript +htmx.ajax('POST', '/api/files/move', { + values: { source: 'old/path.md', destination: 'new/path.md' }, + swap: 'none' // Server uses hx-swap-oob +}); +``` + +**When to use**: Drag & drop, programmatic actions, complex validations. + +### Pattern 3: Out-of-Band Swaps (OOB) + +Server includes additional HTML fragments to update multiple parts of the page: + +```html + +