docs: capture autosave roll-out plan

This commit is contained in:
Justin Edmund 2025-10-07 03:18:02 -07:00
parent c63608938a
commit 7b5af20dee
2 changed files with 399 additions and 0 deletions

View 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.

View 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