docs: capture autosave roll-out plan
This commit is contained in:
parent
c63608938a
commit
7b5af20dee
2 changed files with 399 additions and 0 deletions
61
docs/autosave-completion-guide.md
Normal file
61
docs/autosave-completion-guide.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Admin Autosave Completion Guide
|
||||||
|
|
||||||
|
## Objectives
|
||||||
|
- Eliminate redundant save requests triggered on initial page load.
|
||||||
|
- Restore reliable local draft recovery, including clear-up of stale backups.
|
||||||
|
- Deliver autosave status feedback that visibly transitions back to `idle` after successful saves.
|
||||||
|
- Ensure navigation/unload flows wait for pending autosaves instead of cancelling them mid-flight.
|
||||||
|
|
||||||
|
## Key Problem Areas
|
||||||
|
|
||||||
|
### Missing Draft Handlers
|
||||||
|
- `src/routes/admin/posts/[id]/edit/+page.svelte:425` references `restoreDraft` and `dismissDraft`, but the functions are never defined. Draft recovery buttons therefore break compilation and runtime behavior.
|
||||||
|
|
||||||
|
### Immediate Autosaves on Load
|
||||||
|
- Effects in `src/routes/admin/posts/[id]/edit/+page.svelte:307` and `src/lib/components/admin/ProjectForm.svelte:157` call `autoSave.schedule()` as soon as the component mounts. Because the payload hash includes `updatedAt`, each mount triggers redundant PUTs until the server response realigns the hash.
|
||||||
|
|
||||||
|
### Ineffective Navigation Guard
|
||||||
|
- `beforeNavigate(() => autoSave.flush())` (posts + project form) does not cancel the outbound navigation, so the flush typically aborts when the route unloads. Result: unsaved work if the user navigates away during a pending autosave.
|
||||||
|
|
||||||
|
### Controller Lifecycle Gaps
|
||||||
|
- `createAutoSaveController` timers/AbortController persist after leaving the page because callers never invoke `destroy()`.
|
||||||
|
- Post editor imports `clearDraft` but never clears the draft after successful saves or when dismissing the prompt, so stale backups reappear.
|
||||||
|
|
||||||
|
## Controller Enhancements (`src/lib/admin/autoSave.ts`)
|
||||||
|
- **Baseline priming**: Add a `prime(initialPayload)` (or allow `onSaved` to pass the response payload) to set `lastSentHash` immediately after fetching server data. This prevents an automatic save when the user has not made changes.
|
||||||
|
- **Auto-idle transition**: When status becomes `'saved'`, set a timeout (e.g., 2s) that reverts status to `'idle'`. Cancel the timeout on any new state change.
|
||||||
|
- **Robust destroy**: Ensure `destroy()` clears pending timers and aborts the current request; expose and require callers to invoke it on component teardown.
|
||||||
|
- Consider optional helper flags (e.g., `autoResetStatus`) so forms do not reimplement timing logic.
|
||||||
|
|
||||||
|
## Shared Lifecycle Helper
|
||||||
|
Create a utility (e.g., `initAutoSaveLifecycle`) that accepts the controller plus configuration:
|
||||||
|
- Registers keyboard shortcut (`Cmd/Ctrl+S`) to `flush()` once the page has loaded.
|
||||||
|
- Provides a real navigation guard that cancels the navigation event, awaits `flush()`, then resumes or surfaces an error.
|
||||||
|
- Hooks into `onDestroy` to remove listeners and call `controller.destroy()`.
|
||||||
|
- Optionally wires window unload handling if needed.
|
||||||
|
|
||||||
|
## Form Integration Checklist
|
||||||
|
|
||||||
|
### Posts Editor (`src/routes/admin/posts/[id]/edit/+page.svelte`)
|
||||||
|
1. Implement `restoreDraft` / `dismissDraft` and handle `clearDraft` after autosave or manual save success.
|
||||||
|
2. Introduce a `hasLoaded` flag set after `loadPost()` (and controller `prime`) before scheduling autosave.
|
||||||
|
3. Adopt the shared lifecycle helper for navigation, keyboard shortcuts, and cleanup.
|
||||||
|
|
||||||
|
### Project Form (`src/lib/components/admin/ProjectForm.svelte`)
|
||||||
|
1. Mirror baseline priming and `hasLoaded` gating before scheduling.
|
||||||
|
2. Clear drafts on success or dismissal, and reuse the lifecycle helper.
|
||||||
|
3. Ensure autosave only starts after the initial project data populates `formData`.
|
||||||
|
|
||||||
|
### Other Forms (Simple Post, Essay, Photo, etc.)
|
||||||
|
- Audit each admin form to ensure they use the shared lifecycle helper, seed baselines, clear drafts, and transition status back to `idle`.
|
||||||
|
|
||||||
|
## Testing & Verification
|
||||||
|
- **Unit Tests**: Cover controller state transitions, baseline priming, abort handling, and auto-idle timeout (`tests/autoSaveController.test.ts`). Run with `node --test --loader tsx tests/autoSaveController.test.ts`.
|
||||||
|
- **Component Tests**: Verify autosave does not fire on initial mount, drafts restore/clear correctly, and navigation waits for flush.
|
||||||
|
- **Manual QA**: Confirm keyboard shortcut behavior, offline fallback, and that UI returns to `idle` after showing “saved”.
|
||||||
|
|
||||||
|
## Structural Considerations
|
||||||
|
- Factor shared autosave wiring into reusable modules to avoid copy/paste drift.
|
||||||
|
- Ensure server response payloads used in `prime()` reflect the canonical representation (including normalized fields) so hashes stay in sync.
|
||||||
|
- Document the lifecycle helper so new admin screens adopt the proven pattern without regression.
|
||||||
|
|
||||||
338
prd/PRD-auto-save-functionality.md
Normal file
338
prd/PRD-auto-save-functionality.md
Normal file
|
|
@ -0,0 +1,338 @@
|
||||||
|
# Product Requirements Document: Auto-Save Functionality
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
Implement an intelligent auto-save system for all admin forms and editors to prevent data loss and improve the content creation experience.
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
Currently, users must manually save their work in the admin interface, which can lead to:
|
||||||
|
- Data loss if the browser crashes or connection is interrupted
|
||||||
|
- Anxiety about losing work during long editing sessions
|
||||||
|
- Inefficient workflow with frequent manual saves
|
||||||
|
- No recovery mechanism for unsaved changes
|
||||||
|
|
||||||
|
## Goals & Success Metrics
|
||||||
|
|
||||||
|
### Primary Goals
|
||||||
|
1. Prevent data loss during content creation
|
||||||
|
2. Provide seamless, unobtrusive saving experience
|
||||||
|
3. Enable recovery from unexpected interruptions
|
||||||
|
4. Maintain data consistency and integrity
|
||||||
|
|
||||||
|
### Success Metrics
|
||||||
|
- 0% data loss from browser crashes or network issues
|
||||||
|
- <3 second save latency for typical content
|
||||||
|
- 95% of saves complete without user intervention
|
||||||
|
- User satisfaction with editing experience improvement
|
||||||
|
|
||||||
|
## User Stories
|
||||||
|
|
||||||
|
### As a content creator
|
||||||
|
- I want my work to be automatically saved so I don't lose progress
|
||||||
|
- I want to see clear feedback about save status
|
||||||
|
- I want to recover my work if something goes wrong
|
||||||
|
- I want control over when auto-save is active
|
||||||
|
|
||||||
|
### As a site administrator
|
||||||
|
- I want to ensure data integrity across all saves
|
||||||
|
- I want to minimize server load from frequent saves
|
||||||
|
- I want to track save patterns for optimization
|
||||||
|
|
||||||
|
## Functional Requirements
|
||||||
|
|
||||||
|
### Core Auto-Save System
|
||||||
|
|
||||||
|
#### 1. Smart Debouncing
|
||||||
|
- **Content changes**: 2-second delay after user stops typing
|
||||||
|
- **Metadata changes**: Immediate save for critical fields
|
||||||
|
- **Navigation events**: Immediate save before leaving page
|
||||||
|
- **Keyboard shortcut**: Cmd/Ctrl+S for manual save
|
||||||
|
|
||||||
|
#### 2. Save States & Feedback
|
||||||
|
- **Idle**: No pending changes
|
||||||
|
- **Saving**: Active save in progress with spinner
|
||||||
|
- **Saved**: Confirmation with timestamp
|
||||||
|
- **Error**: Clear error message with retry option
|
||||||
|
- **Conflict**: Detection and resolution UI
|
||||||
|
|
||||||
|
#### 3. Data Persistence
|
||||||
|
- **Server-first**: Primary storage in database
|
||||||
|
- **Local backup**: IndexedDB for offline/recovery
|
||||||
|
- **Conflict detection**: Version tracking with timestamps
|
||||||
|
- **Partial saves**: Only send changed fields
|
||||||
|
|
||||||
|
### Visual Design
|
||||||
|
|
||||||
|
#### Status Indicator
|
||||||
|
```
|
||||||
|
States:
|
||||||
|
- Idle: No indicator (clean UI)
|
||||||
|
- Saving: "Saving..." with subtle spinner
|
||||||
|
- Saved: "All changes saved" (fades after 2s)
|
||||||
|
- Error: Red indicator with retry button
|
||||||
|
- Offline: "Working offline" badge
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Positioning
|
||||||
|
- Fixed position in editor header
|
||||||
|
- Non-intrusive, doesn't shift content
|
||||||
|
- Responsive to different screen sizes
|
||||||
|
- Accessible color contrast
|
||||||
|
|
||||||
|
### API Design
|
||||||
|
|
||||||
|
#### New Endpoints
|
||||||
|
```typescript
|
||||||
|
// Auto-save endpoint
|
||||||
|
POST /api/posts/[id]/autosave
|
||||||
|
Body: {
|
||||||
|
content?: JSONContent,
|
||||||
|
title?: string,
|
||||||
|
metadata?: object,
|
||||||
|
lastModified: timestamp
|
||||||
|
}
|
||||||
|
Response: {
|
||||||
|
success: boolean,
|
||||||
|
lastModified: timestamp,
|
||||||
|
conflict?: {
|
||||||
|
serverVersion: object,
|
||||||
|
serverModified: timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recovery endpoint
|
||||||
|
GET /api/posts/[id]/recover
|
||||||
|
Response: {
|
||||||
|
localDraft?: object,
|
||||||
|
serverVersion: object,
|
||||||
|
timestamps: {
|
||||||
|
local?: timestamp,
|
||||||
|
server: timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
|
||||||
|
#### Form Components to Update
|
||||||
|
1. **EssayForm.svelte** - Blog posts and essays
|
||||||
|
2. **ProjectForm.svelte** - Project case studies
|
||||||
|
3. **AlbumForm.svelte** - Album descriptions
|
||||||
|
4. **SimplePostForm.svelte** - Simple text posts
|
||||||
|
5. **PhotoPostForm.svelte** - Photo posts with captions
|
||||||
|
|
||||||
|
#### Composer Integration
|
||||||
|
- Hook into TipTap editor's `onUpdate` event
|
||||||
|
- Track content changes separately from metadata
|
||||||
|
- Handle rich media embeds appropriately
|
||||||
|
|
||||||
|
## Technical Requirements
|
||||||
|
|
||||||
|
### Frontend Architecture
|
||||||
|
|
||||||
|
#### Auto-Save Hook (`useAutoSave.svelte.ts`)
|
||||||
|
```typescript
|
||||||
|
class AutoSave {
|
||||||
|
private state = $state<'idle' | 'saving' | 'saved' | 'error'>('idle')
|
||||||
|
private lastSaved = $state<Date | null>(null)
|
||||||
|
private saveTimer: NodeJS.Timeout | null = null
|
||||||
|
private saveQueue: Set<string> = new Set()
|
||||||
|
|
||||||
|
constructor(options: AutoSaveOptions) {
|
||||||
|
// Initialize with endpoint, auth, debounce settings
|
||||||
|
}
|
||||||
|
|
||||||
|
track(field: string, value: any): void
|
||||||
|
save(immediate?: boolean): Promise<void>
|
||||||
|
recover(): Promise<RecoveryData>
|
||||||
|
reset(): void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Svelte 5 Integration
|
||||||
|
- Use `$state` rune for reactive state
|
||||||
|
- Use `$effect` for side effects and cleanup
|
||||||
|
- Use `$derived` for computed values
|
||||||
|
- Maintain compatibility with existing stores
|
||||||
|
|
||||||
|
### Backend Requirements
|
||||||
|
|
||||||
|
#### Database Schema Updates
|
||||||
|
```sql
|
||||||
|
-- Add version tracking
|
||||||
|
ALTER TABLE posts ADD COLUMN version INTEGER DEFAULT 1;
|
||||||
|
ALTER TABLE posts ADD COLUMN last_auto_save TIMESTAMP;
|
||||||
|
|
||||||
|
-- Auto-save drafts table
|
||||||
|
CREATE TABLE auto_save_drafts (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
entity_type VARCHAR(50),
|
||||||
|
entity_id INTEGER,
|
||||||
|
user_id INTEGER,
|
||||||
|
content JSONB,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Performance Optimizations
|
||||||
|
- Implement request coalescing for rapid changes
|
||||||
|
- Use database transactions for consistency
|
||||||
|
- Add Redis caching for conflict detection
|
||||||
|
- Implement rate limiting per user
|
||||||
|
|
||||||
|
### Security Considerations
|
||||||
|
- Validate user ownership before auto-save
|
||||||
|
- Sanitize content to prevent XSS
|
||||||
|
- Rate limit to prevent abuse
|
||||||
|
- Encrypt local storage data
|
||||||
|
- Audit trail for all saves
|
||||||
|
|
||||||
|
## Non-Functional Requirements
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- Save latency <500ms for text content
|
||||||
|
- <2MB memory overhead per form
|
||||||
|
- Debounce efficiency >90% reduction in requests
|
||||||
|
- Support 100+ concurrent editors
|
||||||
|
|
||||||
|
### Reliability
|
||||||
|
- 99.9% save success rate
|
||||||
|
- Graceful degradation on network issues
|
||||||
|
- Automatic retry with exponential backoff
|
||||||
|
- Data recovery from last 24 hours
|
||||||
|
|
||||||
|
### Usability
|
||||||
|
- Zero configuration for basic use
|
||||||
|
- Clear, non-technical error messages
|
||||||
|
- Intuitive conflict resolution
|
||||||
|
- Keyboard accessible
|
||||||
|
|
||||||
|
### Compatibility
|
||||||
|
- Chrome 90+, Firefox 88+, Safari 14+
|
||||||
|
- Mobile responsive
|
||||||
|
- Works with screen readers
|
||||||
|
- Progressive enhancement
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### Phase 1: Core Infrastructure (Week 1-2)
|
||||||
|
- [ ] Create `useAutoSave` hook
|
||||||
|
- [ ] Implement debouncing logic
|
||||||
|
- [ ] Add basic status component
|
||||||
|
- [ ] Create auto-save API endpoint
|
||||||
|
|
||||||
|
### Phase 2: Form Integration (Week 2-3)
|
||||||
|
- [ ] Integrate with EssayForm
|
||||||
|
- [ ] Integrate with ProjectForm
|
||||||
|
- [ ] Add keyboard shortcuts
|
||||||
|
- [ ] Implement local storage backup
|
||||||
|
|
||||||
|
### Phase 3: Advanced Features (Week 3-4)
|
||||||
|
- [ ] Conflict detection and resolution
|
||||||
|
- [ ] Offline support with service worker
|
||||||
|
- [ ] Recovery interface
|
||||||
|
- [ ] Performance monitoring
|
||||||
|
|
||||||
|
### Phase 4: Polish & Testing (Week 4-5)
|
||||||
|
- [ ] UI/UX refinements
|
||||||
|
- [ ] Comprehensive testing
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance optimization
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
- Debounce logic validation
|
||||||
|
- State management correctness
|
||||||
|
- API error handling
|
||||||
|
- Local storage operations
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
- Form component integration
|
||||||
|
- API endpoint validation
|
||||||
|
- Conflict resolution flow
|
||||||
|
- Recovery scenarios
|
||||||
|
|
||||||
|
### E2E Tests
|
||||||
|
- Complete save flow
|
||||||
|
- Network interruption handling
|
||||||
|
- Multi-tab scenarios
|
||||||
|
- Mobile experience
|
||||||
|
|
||||||
|
### Performance Tests
|
||||||
|
- Load testing with concurrent users
|
||||||
|
- Memory leak detection
|
||||||
|
- Network bandwidth usage
|
||||||
|
- Database query optimization
|
||||||
|
|
||||||
|
## Rollout Strategy
|
||||||
|
|
||||||
|
1. **Beta Testing**: Deploy to staging with select users
|
||||||
|
2. **Gradual Rollout**: Enable for 10% → 50% → 100% of forms
|
||||||
|
3. **Monitoring**: Track save success rates and user feedback
|
||||||
|
4. **Iteration**: Refine based on real-world usage
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
### Version 2.0
|
||||||
|
- Real-time collaboration indicators
|
||||||
|
- Revision history with diff view
|
||||||
|
- Auto-save templates and drafts
|
||||||
|
- AI-powered content suggestions
|
||||||
|
|
||||||
|
### Version 3.0
|
||||||
|
- Multi-device sync
|
||||||
|
- Offline-first architecture
|
||||||
|
- Advanced merge conflict resolution
|
||||||
|
- Team collaboration features
|
||||||
|
|
||||||
|
## Risks & Mitigations
|
||||||
|
|
||||||
|
| Risk | Impact | Mitigation |
|
||||||
|
|------|--------|------------|
|
||||||
|
| Data corruption | High | Implement checksums and validation |
|
||||||
|
| Performance degradation | Medium | Rate limiting and request batching |
|
||||||
|
| User confusion | Low | Clear UI feedback and documentation |
|
||||||
|
| Storage limits | Low | Implement cleanup and quotas |
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
### External Libraries
|
||||||
|
- None required (uses native Svelte/SvelteKit features)
|
||||||
|
|
||||||
|
### Internal Systems
|
||||||
|
- Existing authentication system
|
||||||
|
- Toast notification system
|
||||||
|
- TipTap editor integration
|
||||||
|
- Prisma database client
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] Auto-save activates within 2 seconds of changes
|
||||||
|
- [ ] Visual feedback appears for all save states
|
||||||
|
- [ ] Manual save button remains functional
|
||||||
|
- [ ] Recovery works after browser crash
|
||||||
|
- [ ] No data loss in normal operation
|
||||||
|
- [ ] Performance metrics meet targets
|
||||||
|
- [ ] Accessibility standards met
|
||||||
|
- [ ] Documentation complete
|
||||||
|
|
||||||
|
## Appendix
|
||||||
|
|
||||||
|
### Competitive Analysis
|
||||||
|
- **Notion**: Instant save with "Saving..." indicator
|
||||||
|
- **Google Docs**: Real-time with conflict resolution
|
||||||
|
- **WordPress**: Auto-save drafts every 60 seconds
|
||||||
|
- **Medium**: Continuous save with version history
|
||||||
|
|
||||||
|
### User Research Insights
|
||||||
|
- Users expect auto-save in modern editors
|
||||||
|
- Visual feedback reduces anxiety
|
||||||
|
- Recovery options increase trust
|
||||||
|
- Performance is critical for user satisfaction
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document Version**: 1.0
|
||||||
|
**Last Updated**: 2025-01-30
|
||||||
|
**Author**: System Architecture Team
|
||||||
|
**Status**: Ready for Implementation
|
||||||
Loading…
Reference in a new issue