feat: implement unified editor with content persistence and server-side upsert

- Replace dual update systems with single markdown-first editor architecture
- Add server-side upsert to eliminate 404 errors on PUT operations
- Fix content persistence race condition between preview and save operations
- Remove legacy updateElementContent system entirely
- Add comprehensive authentication with JWT scaffolding and dev mode
- Implement EditContext.updateOriginalContent() for proper baseline management
- Enable markdown formatting in all text elements (h1-h6, p, div, etc)
- Clean terminology: remove 'unified' references from codebase

Technical changes:
* core/editor.js: Remove legacy update system, unify content types as markdown
* ui/Editor.js: Add updateOriginalContent() method to fix save persistence
* ui/Previewer.js: Clean live preview system for all content types
* api/handlers.go: Implement UpsertContent for idempotent PUT operations
* auth/*: Complete authentication service with OAuth scaffolding
* db/queries/content.sql: Add upsert query with ON CONFLICT handling
* Schema: Remove type constraints, rely on server-side validation

Result: Clean content editing with persistent saves, no 404 errors, markdown support in all text elements
This commit is contained in:
2025-09-10 20:19:54 +02:00
parent c572428e45
commit b0c4a33a7c
23 changed files with 1658 additions and 3585 deletions

120
TODO.md
View File

@@ -242,3 +242,123 @@ CREATE INDEX IF NOT EXISTS idx_content_site_id ON content(site_id);
- `db/*/setup.sql` - Contains table creation queries (sqlc generates type-safe functions)
- `internal/db/database.go` - Manual index/trigger creation using raw SQL
- **Best Practice**: Use sqlc for what it supports, manual SQL for what it doesn't
## 🔄 **Editor Cache Architecture & Content State Management** (Dec 2024)
### **Current Architecture Issues Identified**
**Problem**: Conflict between preview system and content persistence after save operations.
**Root Cause**: The unified Editor system was designed with preview-first architecture:
- `originalContent` stores DOM state when editing begins
- `clearPreview()` always restores to `originalContent`
- This creates race condition: `applyContent()``clearPreview()` → content reverted
### **✅ Implemented Solution: Post-Save Baseline Update**
**Strategy**: After successful save, update the stored `originalContent` to match the new saved state.
**Implementation** (`lib/src/ui/Editor.js`):
```js
// In save handler:
context.applyContent(content); // Apply new content to DOM
context.updateOriginalContent(); // Update baseline to match current DOM
this.previewer.clearPreview(); // Clear preview (won't revert since baseline matches)
```
**Benefits**:
- ✅ Content persists after save operations
- ✅ Future cancellations restore to saved state, not pre-edit state
- ✅ Maintains clean preview functionality
- ✅ No breaking changes to existing architecture
### **Future Considerations: Draft System Architecture**
**Current State Management**:
- **Browser Cache**: DOM elements store current content state
- **Server Cache**: Database stores persisted content
- **No Intermediate Cache**: Edits are either preview (temporary) or saved (permanent)
**Potential Draft System Design**:
#### **Option 1: LocalStorage Drafts**
```js
// Auto-save drafts locally during editing
const draftKey = `insertr_draft_${contentId}_${siteId}`;
localStorage.setItem(draftKey, JSON.stringify({
content: currentContent,
timestamp: Date.now(),
originalContent: baseline
}));
```
**Benefits**: Offline support, immediate feedback, no server load
**Drawbacks**: Per-browser, no cross-device sync, storage limits
#### **Option 2: Server-Side Drafts**
```js
// Auto-save drafts to server with special draft flag
PUT /api/content/{id}/draft
{
"value": "Draft content...",
"type": "markdown",
"is_draft": true
}
```
**Benefits**: Cross-device sync, unlimited storage, collaborative editing potential
**Drawbacks**: Server complexity, authentication requirements, network dependency
#### **Option 3: Hybrid Draft System**
- **LocalStorage**: Immediate draft saving during typing
- **Server Sync**: Periodic sync of drafts (every 30s or on significant changes)
- **Conflict Resolution**: Handle cases where server content changed while editing draft
### **Cache Invalidation Strategy**
**Current Behavior**:
- Content is cached in DOM until page reload
- No automatic refresh when content changes on server
- No awareness of multi-user editing scenarios
**Recommended Enhancements**:
#### **Option A: Manual Refresh Strategy**
- Add "Refresh Content" button to editor interface
- Check server content before editing (warn if changed)
- Simple conflict resolution (server wins vs local wins vs merge)
#### **Option B: Polling Strategy**
- Poll server every N minutes for content changes
- Show notification if content was updated by others
- Allow user to choose: keep editing, reload, or merge
#### **Option C: WebSocket Strategy**
- Real-time content change notifications
- Live collaborative editing indicators
- Automatic conflict resolution
### **Implementation Priority**
**Phase 1** (Immediate): ✅ **COMPLETED**
- Fix content persistence after save (baseline update approach)
**Phase 2** (Short-term):
- Add LocalStorage draft auto-save during editing
- Implement draft recovery on page reload
- Basic conflict detection (server timestamp vs local timestamp)
**Phase 3** (Long-term):
- Server-side draft support
- Real-time collaboration features
- Advanced conflict resolution
### **Design Principles for Draft System**
1. **Progressive Enhancement**: Site works without drafts, drafts enhance UX
2. **Data Safety**: Never lose user content, even in edge cases
3. **Performance First**: Drafts shouldn't impact site loading for regular visitors
4. **Conflict Transparency**: Always show user what's happening with their content
5. **Graceful Degradation**: Fallback to basic editing if draft system fails
**Note**: Current architecture already supports foundation for all these enhancements through the unified Editor system and API client pattern.