Unified Story Canvas
Status: Planned (Phase 0) Priority: Critical Estimated Effort: 3-4 weeks Related: Product Roadmap, v1.1 UX Roadmap
Overview
The Unified Story Canvas transforms the story editor into the primary creative workspace, with Voice Recording and AI Conversation as integrated side-panel tools rather than separate pages requiring a conversion step.
Key Principle: The story is the destination; voice and AI are tools to help create it.
Problem Statement
Current Flow (Fragmented)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CURRENT FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β /books/[id]/record /books/[id]/conversations β
β ββββββββββββββββ ββββββββββββββββ β
β β Voice Record β β AI Converse β β
β β Page β β Page β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β
β βΌ βΌ β
β ββββββββββββββββββββββββββββββββββββββββ β
β β "Convert to Story" β β
β β (Separate Step) β β
β ββββββββββββββββββββ¬ββββββββββββββββββββ β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββ β
β β Story Editor β β
β β /stories/[id]/edit β β
β ββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββProblems with Current Flow
- Tool-first, not goal-first - Users start with tools (voice/AI) instead of the goal (story)
- Conversion friction - Extra step creates cognitive load and drop-off
- Disconnected context - Voice recordings and conversations lack story context
- Multiple entry points - Confuses new users about where to start
- Hard to iterate - Difficult to combine methods (record, refine with AI, edit)
Target State (Unified Canvas)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UNIFIED STORY CANVAS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β STORY EDITOR (Primary) β β
β β /stories/[id]/edit or /stories/new β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β β β
β β β Story Content Area β β β
β β β (TipTap Editor Canvas) β β β
β β β β β β
β β β [User types, or content appears from β β β
β β β voice/AI tools in side panels] β β β
β β β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β ββββββββββββββββ ββββββββββββββββ β β
β β β π€ Voice β β π€ AI Chat β β β
β β β Panel β β Panel β β β
β β β (Slide-in) β β (Slide-in) β β β
β β β β β β β β
β β β β’ Record β β β’ Ask Elena β β β
β β β β’ Transcribe β β β’ Get ideas β β β
β β β β’ Add to β β β’ Generate β β β
β β β Story ββββββΌβββββββββββββββΌββΊ Add to β β β
β β β β β Story β β β
β β ββββββββββββββββ ββββββββββββββββ β β
β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββBenefits
- Story is the destination - Tools are helpers, not separate workflows
- No conversion step - Content flows directly into story
- Maintained context - Voice and AI understand whatβs already written
- Single entry point - Reduces confusion for new users
- Easy method combination - Record, then refine with AI, then edit manually
Architecture Decisions
Data Ownership: Dual Access
Recordings and AI conversations are:
- Linked to a story via
story_idforeign key - Also visible in global library for browsing all content
This gives users the best of both worlds - content is organized by story but still accessible from a central library.
Content Reuse: 1-to-1 Simple
Each recording or conversation belongs to ONE story at a time.
- Simple mental model for users
- Clear data ownership
- To use content in another story, copy the text
- Avoids complex many-to-many relationships
Library Priority: Full Featured
The global library (Recordings, AI Conversations) shows:
- Badges: βUsed in: [Story Name]β for linked content
- Quick Actions: βAdd to Storyβ button for unlinked content
- Filters: All | Linked | Unlinked
Database Schema
Current State
-- recordings table already has story_id
recordings (
id UUID PRIMARY KEY,
story_id UUID REFERENCES stories(id), -- β Already exists
book_id UUID,
...
)
-- ai_conversations table lacks story_id
ai_conversations (
id UUID PRIMARY KEY,
book_id UUID,
campaign_id UUID,
-- story_id is MISSING
...
)Required Migration
-- Add story_id to ai_conversations (matching recordings pattern)
ALTER TABLE ai_conversations
ADD COLUMN story_id UUID REFERENCES stories(id) ON DELETE SET NULL;
CREATE INDEX idx_ai_conversations_story_id ON ai_conversations(story_id);Data Flow
| Scenario | story_id Value | Library Badge |
|---|---|---|
| Created from Story Editor | Set to current story | βUsed in: [Story]β |
| Created from standalone page | NULL | βAdd to Storyβ button |
| Orphan content | NULL | βAdd to Storyβ button |
Implementation Plan
Phase 1: Side Panel Architecture
Extend EditorRightPanel to support new panel types:
// Current types
type RightPanelContent = 'comments' | 'ai' | 'grammar' | 'spellcheck' | 'refinement'
// Extended types
type RightPanelContent =
| 'comments' | 'ai' | 'grammar' | 'spellcheck' | 'refinement'
| 'voice-record' // NEW: Voice recording panel
| 'ai-conversation' // NEW: AI chat panel (enhanced)Tasks:
- Add
voice-recordpanel type to EditorRightPanel - Add
ai-conversationpanel type (enhanced from currentai) - Create quick-access buttons in toolbar
- Implement panel slide-in animation
- Support simultaneous panels on desktop
- Mobile: bottom sheet or full-screen modal
Phase 2: Voice Recording Panel
Create VoiceRecordPanel.tsx:
interface VoiceRecordingPanelProps {
storyId: string
bookId?: string
onTranscriptReady: (transcript: string) => void
onInsertToStory: (content: string, position: 'cursor' | 'end') => void
}Features:
- Compact recording interface in side panel
- Real-time transcription display
- βInsert at Cursorβ button
- βInsert at Endβ button
- Recording history for this story
- Playback of previous recordings
UX Flow:
- User clicks π€ in toolbar
- Voice panel slides in from right
- User records their story segment
- Transcription appears in panel
- User clicks βAdd to Storyβ β text inserted at cursor
- Panel stays open for additional recordings
Phase 3: AI Conversation Panel
Create AIConversationPanel.tsx:
interface AIConversationPanelProps {
storyId: string
bookId?: string
storyContent: string // Current editor content for context
storyTitle: string
onInsertToStory: (content: string, position: 'cursor' | 'end' | 'replace') => void
onResumeConversation?: (conversationId: string) => void
}Features:
- Chat interface in side panel
- Story-aware context (AI knows whatβs already written)
- Quick actions: βContinue this storyβ, βAdd more detailβ, βSuggest memoriesβ
- βInsert Responseβ button
- Conversation history for this story
- Resume previous conversations
UX Flow:
- User clicks π€ in toolbar
- AI panel slides in from right
- User asks: βWhat else might grandma remember about the farm?β
- AI responds with suggestions based on story context
- User clicks βInsertβ on a suggestion β added to story
- User can continue conversation or close panel
Phase 4: Empty State Enhancement
When story is empty, show creation options:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β How would you like to start? β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β βοΈ β β π€ β β π€ β β
β β Just Write β β Record Your β β Chat with β β
β β β β Voice β β Elena β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β
β All methods can be combined at any time β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββPhase 5: Library Enhancement
Update library views to show story linkage:
Recordings Page:
- Badge: βUsed in: [Story Name]β with link
- Quick action: βAdd to Storyβ dropdown for unlinked
- Filter tabs: All | Linked | Unlinked
AI Conversations Page:
- Same badge and quick action pattern
- Show which story each conversation belongs to
Content Insertion Logic
Handle inserting voice/AI content into TipTap editor:
const insertContent = (content: string, position: 'cursor' | 'end' | 'replace') => {
if (!editor) return
switch (position) {
case 'cursor':
editor.chain().focus().insertContent(content).run()
break
case 'end':
editor.chain()
.focus()
.setTextSelection(editor.state.doc.content.size)
.insertContent('\n\n' + content)
.run()
break
case 'replace':
editor.chain().focus().deleteSelection().insertContent(content).run()
break
}
}Critical Files
| Category | File Path |
|---|---|
| Database | supabase/migrations/xxx_add_story_id_to_ai_conversations.sql |
| Editor Shell | apps/web-app/app/components/editor/EnhancedEditorShell.tsx |
| Right Panel | apps/web-app/app/components/editor/EditorRightPanel.tsx |
| Voice Panel | apps/web-app/app/components/editor/panels/VoiceRecordPanel.tsx (new) |
| AI Panel | apps/web-app/app/components/editor/panels/AIConversationPanel.tsx (new) |
| Recordings API | apps/web-app/app/api/recordings/route.ts |
| Conversations API | apps/web-app/app/api/ai/conversations/route.ts |
| Recordings Library | apps/web-app/app/recordings/page.tsx |
| Conversations Library | apps/web-app/app/ai-conversations/page.tsx |
| TypeScript Types | apps/web-app/types/database.ts |
Priority Matrix
| Task | Impact | Effort | Priority |
|---|---|---|---|
| Side panel architecture | High | Low | P0 |
| Voice panel integration | High | Medium | P0 |
| βAdd to Storyβ flow | High | Low | P0 |
| AI panel integration | High | Medium | P1 |
| Empty state enhancement | Medium | Low | P1 |
| Toolbar quick actions | Medium | Low | P1 |
| Mobile responsiveness | Medium | High | P2 |
| Context preservation | Medium | Medium | P2 |
| Library enhancements | Medium | Medium | P2 |
Risk Areas
| Risk | Mitigation |
|---|---|
| Panel state management complexity | Use existing EditorRightPanel patterns |
| Transcription flow in embedded context | Reuse VoiceRecorder component as-is |
| AI context maintenance | Pass storyContent prop to AI panel |
| Mobile UX for side panels | Bottom sheet or full-screen modal approach |
| Migration of orphan content | Backwards compatible (NULL story_id allowed) |
Success Metrics
| Metric | Current | Target |
|---|---|---|
| Steps to create story from voice | 4+ | 2 |
| Conversion step drop-off | ~20% | 0% |
| Stories using multiple input methods | 5% | 30% |
| Time from record to published story | 10+ min | 5 min |
Document History
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2025-12-05 | Initial documentation |