# Bookhoard Documentation System - Implementation Plan **Version**: 1.0 **Created**: 2026-02-01 **Status**: Ready for implementation --- ## Overview This plan documents the complete implementation of an interactive, searchable, and mobile-responsive documentation system for Bookhoard. ### Current State - ✅ Docs package created (`internal/docs/`) - ✅ Goldmark markdown renderer integrated - ✅ Sidebar navigation working - ✅ Table of contents generator - ✅ Breadcrumb navigation - ✅ 9 documentation files exist - ❌ **Markdown content not rendering as HTML** (blocked) - ❌ **Search backend exists but frontend not connected** - ❌ **API documentation is monolithic (30KB file)** - ❌ **No API explorer** (placeholder only) - ❌ **Mobile layout unoptimized** ### Target State - ✅ Markdown renders correctly as HTML - ✅ Interactive API explorer (mock + live modes) - ✅ Split API docs into individual endpoint files - ✅ Lunr.js client-side search with fuzzy + live + highlighting - ✅ Mobile-responsive sidebar - ✅ Search index auto-generated --- ## Phase 1: Fix Markdown Rendering (30 minutes) **Priority**: CRITICAL (blocks all docs) ### Tasks #### 1.1 Fix rawHTML function in template **File**: `templates/docs.templ` **Current Issue**: ```templ templ rawHTML(content string) { { template.HTML(content) } } ``` **Solution**: Use `@rawHTML` directive instead of function call ```templ
@rawHTML(doc.Content)
``` #### 1.2 Test docs rendering **Action**: ```bash go build ./cmd/server ./bookhoard curl http://localhost:8765/docs/API_REFERENCE.md | grep -A 5 "Bookhoard API" ``` **Expected**: HTML is rendered, not escaped markdown text **Completion Criteria**: Markdown converts to HTML with headings, lists, code blocks properly formatted. --- ## Phase 2: Split API Documentation (2-3 hours) **Priority**: High (improves UX significantly) ### File Structure to Create ``` docs/api/ ├── INDEX.md # Landing page with all endpoints ├── authentication/ │ ├── register.md │ ├── login.md │ ├── refresh_token.md │ └── logout.md ├── users/ │ ├── get_profile.md │ ├── update_profile.md │ ├── update_theme.md │ └── change_password.md ├── libraries/ │ ├── get_visible_libraries.md │ ├── get_library.md │ ├── create_library.md │ ├── add_library_folder.md │ ├── set_library_visibility.md │ └── get_library_stats.md ├── media-items/ │ ├── list_media_items.md │ ├── get_media_item.md │ ├── search_media_items.md │ ├── filter_sort_media_items.md │ ├── update_media_item.md │ └── delete_media_item.md ├── progress/ │ ├── get_progress.md │ ├── update_progress.md │ └── delete_progress.md ├── notes/ │ ├── get_notes.md │ ├── create_note.md │ ├── update_note.md │ └── delete_note.md ├── highlights/ │ ├── get_highlights.md │ ├── create_highlight.md │ ├── update_highlight.md │ └── delete_highlight.md ├── ratings/ │ ├── get_ratings.md │ └── create_rating.md ├── devices/ │ ├── register_device.md │ ├── list_devices.md │ ├── revoke_device.md │ ├── get_devices.md │ └── get_device.md ├── analytics/ │ ├── get_analytics.md │ └── update_analytics.md ├── book-matching/ │ ├── search_books.md │ ├── link_book.md │ └── unlink_book.md ├── collections/ │ ├── INDEX.md # Links to COLLECTIONS_API.md │ ├── list_collections.md │ ├── get_collection.md │ ├── create_collection.md │ ├── update_collection.md │ ├── delete_collection.md │ ├── add_auto_assign_rule.md │ ├── remove_auto_assign_rule.md │ ├── test_rule.md │ ├── bulk_assign.md │ ├── create_shelf_mapping.md │ └── delete_shelf_mapping.md ├── opds/ │ ├── feeds.md │ ├── acquisition.md │ └── publication.md ├── sync/ │ ├── koreader_protocol.md │ └── kobo_protocol.md └── websocket/ └── protocol.md ``` ### Implementation Tasks #### 2.1 Create API Index (INDEX.md) **File**: `docs/api/INDEX.md` **Template**: ```markdown # API Documentation Complete reference for Bookhoard REST API endpoints. ## Quick Links - [Authentication](authentication/) - User registration, login, tokens - [Users](users/) - Profile management - [Libraries](libraries/) - Library management - [Media Items](media-items/) - Book/ebook operations - [Progress](progress/) - Reading progress tracking - [Notes](notes/) - User notes management - [Highlights](highlights/) - Book highlights - [Ratings](ratings/) - Book ratings - [Devices](devices/) - Device registration and sync - [Analytics](analytics/) - Usage statistics - [Book Matching](book-matching/) - Search and link books - [Collections](collections/) - See [COLLECTIONS_API.md](../COLLECTIONS_API.md) - [OPDS](opds/) - Open Publication Distribution - [Sync Protocols](sync/) - KOReader and Kobo sync - [WebSocket](websocket/) - Real-time sync events --- ## Authentication See [Authentication Endpoints](authentication/) ## Users & Profiles See [User Management](users/) ## Libraries See [Library Management](libraries/) ... (continue for all sections) ``` #### 2.2 Extract endpoint sections from API_REFERENCE.md **Process**: 1. Read `docs/API_REFERENCE.md` 2. For each `###` heading (73 total), create dedicated markdown file 3. Extract: - Method (GET/POST/PUT/DELETE) - Endpoint path - Auth requirement - Request body (if applicable) - Response examples - Description **Example** - `docs/api/authentication/register.md`: ```markdown # Register User Create a new user account. **Endpoint**: `POST /api/auth/register` **Auth**: Not required **Content-Type**: `application/json` ## Request Body | Field | Type | Required | Description | |--------|------|-----------|-------------| | email | string | Yes | User's email address | | username | string | Yes | Desired username | | password | string | Yes | Password (min 8 chars) | | first_name | string | No | User's first name | | last_name | string | No | User's last name | ### Example Request ```json { "email": "user@example.com", "username": "john", "password": "SecureP@ss123!", "first_name": "John", "last_name": "Doe" } ``` ## Response (201 Created) ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "d4f5g6h7...", "user": { "id": "uuid-here", "email": "user@example.com", "username": "john", "role": "user", "theme": "tokyo-night", "created_at": "2026-01-31T10:00:00Z" } } ``` ## Error Responses | Code | Description | |------|-------------| | 400 | Invalid email format, weak password, or missing fields | | 409 | Email or username already exists | ## Try It Out ``` #### 2.3 Update navigation in docs/handler.go **File**: `internal/docs/navigation.go` **Current Issue**: Navigation only shows top-level docs, not new API structure **Solution**: Update `BuildNavigation()` to include new API structure --- ## Phase 3: Interactive API Explorer (3-4 hours) **Priority**: High (major UX improvement) ### Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ [ Documentation ] [ Try It Out (Toggle) ] │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ POST /api/auth/login │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Method: [▼ POST] GET PUT DELETE │ │ Auth: [✓ Required] [✗ Optional] │ │ │ │ Request Body: │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ { │ │ │ │ "email": "user@example.com", │ │ │ │ "password": "securepassword" │ │ │ │ } │ │ │ └──────────────────────────────────────────────────────┘ │ │ [Copy JSON] [Copy cURL] │ │ │ │ [ Try It Out ] ← Click to execute │ │ │ │ Response: │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ { │ │ │ │ "token": "eyJ...", │ │ │ │ "refresh_token": "eyJ...", │ │ │ │ "expires_in": 3600 │ │ │ │ } │ │ │ └──────────────────────────────────────────────────────┘ │ │ [Copy JSON] │ └─────────────────────────────────────────────────────────────────────┘ ``` ### Implementation Tasks #### 3.1 Create API Explorer Template Component **File**: `templates/api_explorer.templ` **Template Code**: ```templ package templates import "html/template" // APIExplorer represents the interactive API explorer type APIExplorer struct { Endpoint EndpointInfo IsLoggedIn bool MockData map[string]interface{} CanExecute bool } type EndpointInfo struct { Method string Path string Auth bool ContentType string RequestBody string // JSON example Response string // JSON example Description string } templ APIExplorer(explorer APIExplorer) { if !explorer.IsLoggedIn { // Show mode toggle and mock data

Response (Mock)

{ template.HTML(explorer.Endpoint.Response) }
} else { // Show interactive explorer with real execution
} } ``` #### 3.2 Update docs handler to support both modes **File**: `internal/docs/handler.go` **Add**: ```go type APIEndpointData struct { Method string Path string Auth bool ContentType string RequestBody string Response string Description string } func (h *DocsHandler) GetAPIEndpoint(endpointPath string) (*APIEndpointData, error) { // Map endpoint path to data // This would be populated from the split API files endpoints := h.getAPIEndpoints() for _, ep := range endpoints { if strings.HasSuffix(endpointPath, strings.TrimPrefix(ep.Path, "/api/")) { return &ep, nil } } return nil, fmt.Errorf("endpoint not found: %s", endpointPath) } func (h *DocsHandler) getAPIEndpoints() []APIEndpointData { // This will be populated from the API docs // For now, return static list matching API_REFERENCE.md return []APIEndpointData{ { Method: "POST", Path: "/api/auth/register", Auth: false, ContentType: "application/json", RequestBody: `{ "email": "user@example.com", "username": "john", "password": "SecureP@ss123!", "first_name": "John", "last_name": "Doe" }`, Response: `{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "d4f5g6h7...", "user": { "id": "uuid-here", "email": "user@example.com", "username": "john", "role": "user", "theme": "tokyo-night", "created_at": "2026-01-31T10:00:00Z" } }`, Description: "Create a new user account", }, // ... add all 73 endpoints } } ``` #### 3.3 Update HTTP handler to check authentication **File**: `internal/docs/http_handler.go` **Update** `ShowDocumentation` method to pass login status: ```go func (h *HTTPHandler) ShowDocumentation(c echo.Context) error { // ... existing code ... // Check if user is logged in is_logged_in := false if userID := c.Get("user_id"); userID != nil { is_logged_in = true } // Render docs with auth status // Pass to template } ``` #### 3.4 Integrate API Explorer into docs template **File**: `templates/docs.templ` **Update**: ```templ templ DocsLayout(nav Navigation, doc Document, user User, explorer *APIExplorer) { if explorer != nil { @APIExplorer(*explorer) } } ``` --- ## Phase 4: Lunr.js Search Implementation (2-3 hours) **Priority**: High (core documentation feature) ### Architecture ``` ┌──────────────────────────────────────────────────────────────┐ │ Sidebar │ │ ┌────────────────────────────────────────────────┐ │ │ │ 🔍 Search... │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ 📚 Getting Started ▼ │ │ │ │ - Documentation Index │ │ │ │ - Sync Guide │ │ │ │ - Troubleshooting │ │ │ │ │ │ │ │ 🔌 API Reference ▼ │ │ │ │ - Authentication │ │ │ │ - Users & Profiles │ │ │ │ - Libraries │ │ │ │ - ... │ │ │ └────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Search Results (overlay): │ │ ┌──────────────────────────────────────────────┐ │ │ │ Register User │ │ │ │ /api/auth/register │ │ │ │ "Create a new user account..." │ │ │ └──────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────┐ │ │ │ Login User │ │ │ │ /api/auth/login │ │ │ │ "Authenticate with email and password..." │ │ │ └──────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────┐ │ │ │ Kobo Setup │ │ │ │ /docs/devices/KOBO_SETUP.md │ │ │ │ "Set up your Kobo e-reader..." │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ [ View all results → ] │ │ │ │ Main Content (Documentation) │ │ # POST /api/auth/login │ │ ... │ └─────────────────────────────────────────────────────────────┘ ``` ### Implementation Tasks #### 4.1 Add search index generation **File**: `internal/docs/handler.go` **Add to `DocsHandler` struct**: ```go type SearchDoc struct { ID string `json:"id"` Title string `json:"title"` Content string `json:"content"` URL string `json:"url"` } func (h *DocsHandler) GenerateSearchIndex() ([]SearchDoc, error) { docs, err := h.ListDocuments() if err != nil { return nil, fmt.Errorf("failed to list documents: %w", err) } var searchDocs []SearchDoc for _, path := range docs { doc, err := h.LoadDocument(path) if err != nil { continue } // Strip HTML tags for better search content := h.stripHTML(doc.Content) searchDocs = append(searchDocs, SearchDoc{ ID: path, Title: doc.Title, Content: content, URL: "/docs/" + strings.TrimSuffix(path, ".md"), }) } return searchDocs, nil } // stripHTML removes HTML tags from string (simple implementation) func (h *DocsHandler) stripHTML(html string) string { var result strings.Builder inTag := false for _, r := range html { if r == '<' { inTag = true continue } if r == '>' { inTag = false continue } if !inTag { result.WriteRune(r) } } return result.String() } ``` #### 4.2 Add search index endpoint **File**: `internal/docs/http_handler.go` **Add**: ```go // ServeSearchIndex serves the Lunr.js search index func (h *HTTPHandler) ServeSearchIndex(c echo.Context) error { index := h.docs.GenerateSearchIndex() if index == nil { return c.JSON(http.StatusInternalServerError, map[string]string{ "error": "failed to generate search index", }) } return c.JSON(http.StatusOK, index) } ``` **Add route in `cmd/server/main.go`**: ```go // After other docs routes e.GET("/docs/search-index.json", docsHandler.ServeSearchIndex) ``` #### 4.3 Add Lunr.js to docs template **File**: `templates/docs.templ` **Add to ``**: ```html ``` **Add search input in sidebar**: ```html ``` **Add search results overlay**: ```html ``` **Add search JavaScript**: ```html ``` **Add search styles**: ```css /* Add to template styles */ .search-box { margin-bottom: 1rem; } #search-input { width: 100%; padding: 0.75rem 1rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); color: var(--text-primary); font-size: 0.875rem; } #search-input:focus { outline: 2px solid var(--accent); } #search-results { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.95); overflow-y: auto; padding: 2rem; z-index: 1000; } .search-result { display: block; padding: 1rem; border-bottom: 1px solid var(--border); color: var(--text-primary); text-decoration: none; } .search-result:hover { background: var(--bg-secondary); } .result-title { font-weight: 600; margin-bottom: 0.5rem; } .result-snippet { font-size: 0.875rem; color: var(--text-secondary); } .no-results { text-align: center; padding: 2rem; color: var(--text-secondary); } mark { background: var(--accent); color: white; padding: 0 0.2rem; border-radius: 2px; } ``` --- ## Phase 5: Mobile Responsive Design (1-2 hours) **Priority**: Medium (UX improvement for mobile users) ### Implementation Tasks #### 5.1 Add mobile sidebar toggle **File**: `templates/docs.templ` **Add to header**: ```html
``` **Update sidebar**: ```css .sidebar { /* Desktop */ left: 0; width: 280px; transition: transform 0.3s ease; } /* Mobile styles */ @media (max-width: 768px) { .sidebar { transform: translateX(-100%); position: fixed; z-index: 100; box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2); } .sidebar.open { transform: translateX(0); } .main-content { margin-left: 0 !important; padding: 1rem; } .mobile-menu-btn { display: block !important; } #search-results { padding: 1rem; padding-top: 4rem; } } ``` **Add JavaScript for sidebar toggle**: ```html ``` #### 5.2 Adjust TOC for mobile **File**: `templates/docs.templ` **Add mobile TOC styling**: ```css @media (max-width: 768px) { .toc { position: static; margin-bottom: 1rem; padding: 1rem; background: var(--bg-secondary); border-radius: 8px; } } ``` --- ## Phase 6: Testing & Polish (1-2 hours) **Priority**: High (quality assurance) ### Test Checklist #### 6.1 Documentation System Tests - [ ] All 9 existing docs render correctly - [ ] API docs split into individual files load correctly - [ ] Navigation sidebar links work for all pages - [ ] Breadcrumbs are accurate - [ ] Table of contents links jump to correct sections #### 6.2 Search Tests - [ ] Search index loads on page load - [ ] Typing "kobo" finds Kobo setup guide - [ ] Typing "sync" finds sync guide - [ ] Fuzzy search: "colletion" finds "Collection" - [ ] Search results link to correct pages - [ ] Highlighting works in search results - [ ] Search works offline (after index loaded) #### 6.3 API Explorer Tests - [ ] Mock mode shows correct example data - [ ] Real mode executes actual API calls - [ ] Login state detected correctly - [ ] "Try It Out" button makes request - [ ] Response displays with status and timing - [ ] Copy buttons work (JSON, cURL) - [ ] Method switcher updates request type - [ ] Error handling displays properly #### 6.4 Mobile Tests - [ ] Sidebar opens/closes on mobile - [ ] Search results overlay displays correctly - [ ] Content is readable on mobile (320px width) - [ ] Code blocks scroll horizontally on mobile - [ ] Touch targets are 44px+ minimum #### 6.5 Cross-Browser Tests - [ ] Works in Chrome/Firefox/Safari/Edge (latest versions) - [ ] Works on iOS Safari - [ ] Works on Android Chrome --- ## Implementation Order (Recommended) ### Sprint 1: Critical Fixes (0.5 hours) 1. Phase 1: Fix Markdown Rendering 2. Quick test: Verify docs display correctly ### Sprint 2: Core Features (5-6 hours) 3. Phase 4: Lunr.js Search (2-3 hours) 4. Phase 2: Split API Docs (2-3 hours) 5. Sprint 2 test: Verify all features work ### Sprint 3: Advanced Features (4-6 hours) 6. Phase 3: Interactive API Explorer (3-4 hours) 7. Phase 5: Mobile Responsive Design (1-2 hours) ### Sprint 4: Polish (1-2 hours) 8. Phase 6: Testing & Polish --- ## Total Time Estimate | Phase | Time | Priority | |--------|-------|----------| | Phase 1: Fix Markdown Rendering | 0.5h | Critical | | Phase 2: Split API Docs | 2-3h | High | | Phase 3: API Explorer | 3-4h | High | | Phase 4: Lunr.js Search | 2-3h | High | | Phase 5: Mobile Responsive | 1-2h | Medium | | Phase 6: Testing & Polish | 1-2h | High | | **Total** | **10-15h** | - | --- ## Files to Modify ### New Files to Create ``` docs/api/ ├── INDEX.md ├── authentication/*.md (4 files) ├── users/*.md (4 files) ├── libraries/*.md (6 files) ├── media-items/*.md (7 files) ├── progress/*.md (3 files) ├── notes/*.md (4 files) ├── highlights/*.md (4 files) ├── ratings/*.md (2 files) ├── devices/*.md (5 files) ├── analytics/*.md (2 files) ├── book-matching/*.md (3 files) ├── collections/INDEX.md ├── opds/*.md (3 files) ├── sync/*.md (2 files) └── websocket/*.md (1 file) ``` ### Files to Modify ``` internal/docs/handler.go # Add SearchDoc type, GenerateSearchIndex, stripHTML internal/docs/http_handler.go # Add ServeSearchIndex, update to check auth status internal/docs/navigation.go # Update BuildNavigation for new API structure templates/docs.templ # Add Lunr.js, search UI, mobile sidebar toggle, search styles templates/api_explorer.templ # NEW - Create this file cmd/server/main.go # Add /docs/search-index.json route ``` ### Files to Keep (No Changes) ``` docs/API_REFERENCE.md # Keep as reference, but may deprecate docs/COLLECTIONS_API.md # Keep, link from API index docs/SYNC_USER_GUIDE.md # No changes docs/TROUBLESHOOTING.md # No changes docs/INDEX.md # No changes docs/devices/*.md # No changes docs/contributing/DEVELOPMENT.md # No changes docs/api/WEBSOCKET_API.md # Keep, link from API index ``` --- ## Success Criteria The documentation system is complete when: ### Functionality - ✅ All markdown files render as HTML - ✅ API docs are split into individual endpoint files - ✅ Search works with fuzzy matching and highlighting - ✅ Search is live (debounced input) - ✅ API Explorer has both mock and real modes - ✅ API Explorer executes real API calls when logged in - ✅ Sidebar navigation reflects new API structure - ✅ Mobile users can toggle sidebar - ✅ Search results overlay works on mobile ### Performance - ✅ Search index loads in <500ms - ✅ Search results appear in <200ms after typing stops - ✅ Initial docs page load <2s - ✅ API explorer response displays in <500ms ### Code Quality - ✅ All templates compile without errors - ✅ Go code passes `go build` - ✅ No console errors in browser - ✅ LSP shows no warnings ### Documentation Quality - ✅ All API endpoints have "Try It Out" section - ✅ Mock data is valid and realistic - ✅ Real mode shows actual responses - ✅ Search results show relevant content - ✅ Mobile layout is usable on 320px width --- ## Notes for Implementers ### Important Constraints 1. **Don't modify backend** - Only add search index route to `main.go` 2. **Use Lunr.js plugins**: `lunr-flex` for fuzzy, `lunr-highlight` for highlighting 3. **Mock vs Real logic**: Check `localStorage.getItem('token')` to determine auth state 4. **Debounce search input**: 150ms is optimal balance 5. **Strip HTML from search index**: Goldmark outputs HTML, need plain text for search 6. **Pre-build index** (optional): Generate `search_index.json` on startup, cache it ### Gotchas 1. **Templ unsafe HTML**: Use `@rawHTML(doc.Content)` directive, not function call 2. **Import fmt**: Must import in template if using `fmt.Sprintf` 3. **Lunr CDN versions**: Use compatible versions (lunr@2.3.9, lunr-flex@1.0.5, lunr-highlight@1.0.0) 4. **Mobile breakpoint**: Use `@media (max-width: 768px)` for mobile styles 5. **Sidebar z-index**: Must be higher than content for mobile overlay 6. **Search results z-index**: Must be highest (1000) to appear above sidebar ### Testing Strategy 1. Start with Phase 1 only - verify markdown rendering works 2. Add Phase 4 search - test before splitting API docs 3. Split API docs gradually - test each section 4. Add API Explorer last - complex feature, easier to isolate bugs 5. Do mobile testing throughout, not just at the end ### Rollback Plan If any phase causes issues: 1. Revert the specific files modified 2. Test to ensure previous state works 3. Review the specific implementation 4. Try alternative approach if needed --- ## Related Documentation - [PROJECT_GUIDELINES.md](../PROJECT_GUIDELINES.md) - Development rules - [README.md](../README.md) - Project overview - [API_REFERENCE.md](API_REFERENCE.md) - Current API reference - [COLLECTIONS_API.md](COLLECTIONS_API.md) - Collections API --- **Last Updated**: 2026-02-01 **Next Review**: After Sprint 1 completion