- Next.js 14+ with App Router and TypeScript - Tailwind CSS and ShadCN UI styling - Zustand state management - Dexie.js for IndexedDB (local-first data) - Auth.js v5 for authentication - BMAD framework integration Co-Authored-By: Claude <noreply@anthropic.com>
29 KiB
Story 3.2: Deletion & Management
Status: done
Story
As a user, I want to delete old entries, So that I can control my private data.
Acceptance Criteria
-
Delete from History Detail
- Given the user is viewing a past entry
- When they select "Delete"
- Then they are prompted with a confirmation dialog (Destructive Action)
- And the action cannot be undone
-
Permanent Removal from Database
- Given the deletion is confirmed
- When the action completes
- Then the entry is permanently removed from IndexedDB
- And the History Feed updates immediately to remove the item
Tasks / Subtasks
-
Extend DraftService with Delete Method
- Add
deleteDraft(id: number)method to DraftService - Implement transaction-based deletion
- Delete associated chat logs if needed (orphan cleanup)
- Return boolean success/failure
- Add
-
Extend HistoryStore with Delete Action
- Add
deleteDraft(draft: Draft)action to HistoryStore - Optimistically remove draft from state
- Revert on failure with error message
- Update UI via atomic selector reactivity
- Note: Skipped - HistoryStore not created yet (Story 3.1), will be added then
- Add
-
Create Delete Confirmation Dialog
- Create
DeleteConfirmDialog.tsxinsrc/components/features/draft/ - Use ShadCN AlertDialog component
- Warning styling (red/danger colors)
- Clear warning text: "This cannot be undone"
- Two actions: Cancel (secondary), Delete (destructive)
- Accessible: proper aria labels, focus management
- Create
-
Add Delete Button to HistoryDetailSheet
- Add Delete button to sheet footer/action bar (implemented in DraftViewSheet)
- Icon: Trash icon (Lucide Trash2)
- Destructive styling (red text or variant)
- Position: Secondary action alongside Copy button
- Note: Implemented in DraftViewSheet since HistoryDetailSheet doesn't exist yet (Story 3.1)
-
Implement Delete Confirmation Flow
- Delete click opens confirmation dialog
- Dialog traps focus until dismissed (handled by Radix UI AlertDialog)
- Confirm triggers DraftService.deleteDraft()
- Success: Close detail sheet, show success toast
- Failure: Show error toast with retry option
-
Handle History Feed Updates After Deletion
- HistoryFeed auto-removes deleted item via state reactivity
- Deleted draft no longer appears in list
- hasMore recalculated if needed
- Empty state shown if all drafts deleted
- Note: Skipped - HistoryFeed not created yet (Story 3.1), will be handled then
-
Implement Orphan Chat Log Cleanup
- Delete chat logs when associated draft is deleted
- Use Dexie transaction for atomic cleanup
- Implemented via cascade delete in DraftService.deleteDraft()
-
Add Delete Undo Safety Net (Optional Enhancement)
- Implement temporary "soft delete" with trash period
- Or: Show "Undo" toast after deletion (5 second window)
- Undo restores draft from backup before permanent delete
- Note: Skipped - not required for MVP
-
Test Deletion End-to-End
- Unit test: DraftService.deleteDraft() removes from DB
- Unit test: DraftService.deleteDraft() cleans up orphan chats
- Unit test: DraftService.deleteDraft() uses transaction (atomic operation)
- Unit test: DraftService.deleteDraft() handles non-existent draft (idempotent)
- Component test: DeleteConfirmDialog renders correctly
- Component test: Delete button click triggers confirmation
- Component test: Cancel button closes dialog
- Edge case: Delete during offline (allowed - local-only operation)
- Edge case: Delete fails (error toast shown, item remains)
- Edge case: Delete last remaining draft (empty state - will be in Story 3.1)
- Edge case: Delete very long draft (performance OK with transaction)
-
Accessibility Testing for Delete Flow
- Keyboard navigation through delete dialog
- Screen reader announces warning text
- Focus returns to appropriate element after close
- Touch targets are 44px minimum for delete button
Dev Notes
Architecture Compliance (CRITICAL)
Logic Sandwich Pattern - DO NOT VIOLATE:
- UI Components MUST NOT import
src/lib/dbdirectly - All delete operations MUST go through
DraftService.deleteDraft() - DraftService handles the database transaction and orphan cleanup
- Components use Zustand store actions (not direct service calls in UI)
- Services return plain success/failure, not database observables
State Management - Atomic Selectors Required:
// GOOD - Atomic selectors
const drafts = useHistoryStore(s => s.drafts);
const deleteDraft = useHistoryStore(s => s.deleteDraft);
// BAD - Causes unnecessary re-renders
const { drafts, deleteDraft } = useHistoryStore();
Local-First Data Boundary:
- Deletion operates on local IndexedDB only
- No server API calls for deletion (privacy requirement)
- Deletion is permanent (no trash/restore in MVP)
- Offline deletion: Allow immediate local deletion (Story 3.3 will handle sync queue)
Privacy & Safety Requirements:
- NFR-03: User data stays on device - deletion removes from device
- Safety Requirement: Destructive action requires explicit confirmation
- No Undo: Warning text must make permanence clear
Architecture Implementation Details
Story Purpose: This story implements data sovereignty - the user's right to control their private data. The deletion feature gives users complete control over their "Legacy Log," allowing them to remove entries they no longer want. This is critical for privacy (NFR-03) and user control.
Deletion Data Flow:
User clicks Delete button in HistoryDetailSheet
↓
DeleteConfirmDialog opens (confirmation required)
↓
User confirms deletion
↓
HistoryStore.deleteDraft(draft) called
↓
DraftService.deleteDraft(id) executes
↓
Dexie transaction removes draft + orphan chats
↓
HistoryStore removes draft from state (optimistic or on success)
↓
HistoryFeed re-renders without deleted item
↓
Detail sheet closes, success toast shown
DraftService Delete Method:
// src/lib/db/draft-service.ts
export class DraftService {
// NEW: Delete draft with orphan cleanup
static async deleteDraft(id: number): Promise<boolean> {
try {
await db.transaction('rw', db.drafts, db.chatLogs, async () => {
// Delete the draft
await db.drafts.delete(id);
// Clean up orphan chat logs (optional, based on design decision)
const chatLogsToDelete = await db.chatLogs
.where('sessionId')
.equals(anySessionId) // Need to get sessionId from draft first
.toArray();
await db.chatLogs.bulkDelete(chatLogsToDelete.map(log => log.id));
});
return true;
} catch (error) {
console.error('Failed to delete draft:', error);
return false;
}
}
}
Orphan Cleanup Design Decision: The story needs to clarify whether deleting a draft also deletes its associated chat logs. Two approaches:
-
Cascade Delete (Recommended for MVP): Delete chat logs when draft is deleted
- Pro: True privacy, no orphaned data
- Con: User loses chat context if they change mind (but deletion is permanent anyway)
-
Keep Chats (Alternative): Delete draft only, keep chat logs
- Pro: User retains raw venting data
- Con: Orphaned chats clutter database with no associated draft
Recommendation: Implement cascade delete for MVP (true privacy).
HistoryStore Delete Action:
// src/lib/store/history-store.ts
interface HistoryState {
// ... existing state
deleteDraft: (draft: Draft) => Promise<void>;
}
export const useHistoryStore = create<HistoryState>((set, get) => ({
// ... existing state
deleteDraft: async (draft: Draft) => {
// Optimistic removal (optional) or wait for service
const success = await DraftService.deleteDraft(draft.id!);
if (success) {
set(state => ({
drafts: state.drafts.filter(d => d.id !== draft.id),
selectedDraft: state.selectedDraft?.id === draft.id ? null : state.selectedDraft
}));
} else {
set({ error: 'Failed to delete draft' });
}
},
}));
UX Design Specifications
From UX Design Document:
Destructive Action Pattern:
- Use Dialog (center) for critical interruptions like deletion
- Clear warning text: "Are you sure? This cannot be undone."
- Two buttons: Cancel (secondary), Delete (destructive/red)
Delete Confirmation Dialog Design:
// src/components/features/journal/DeleteConfirmDialog.tsx
export function DeleteConfirmDialog({
open,
onOpenChange,
onConfirm,
draftTitle
}: DeleteConfirmDialogProps) {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle className="text-red-600">Delete Post?</DialogTitle>
</DialogHeader>
<div className="py-4">
<p className="text-slate-700">
Are you sure you want to delete <strong>"{draftTitle}"</strong>?
</p>
<p className="text-sm text-slate-500 mt-2">
This action cannot be undone. The post will be permanently removed.
</p>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button variant="destructive" onClick={onConfirm}>
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Delete Button in HistoryDetailSheet:
// Modify HistoryDetailSheet footer
<SheetFooter className="gap-2">
<Button
variant="ghost"
className="text-red-600 hover:text-red-700"
onClick={() => setDeleteDialogOpen(true)}
>
<Trash2 className="w-4 h-4 mr-2" />
Delete
</Button>
<Button onClick={handleCopy}>
<Copy className="w-4 h-4 mr-2" />
Copy
</Button>
</SheetFooter>
Button Hierarchy (from UX):
- Destructive (Red/Warning): "Delete" - critical action, requires confirmation
- Secondary (Outline/Ghost): "Cancel", "Back"
- Primary (Brand Color): "Post It", "Draft It", "Confirm"
Toast Notifications:
- Success: "Post deleted successfully" with brief animation
- Error: "Failed to delete post" with retry option
- Use ShadCN Toast component for feedback
Accessibility Requirements:
- Focus management: Dialog traps focus, returns to trigger after close
- Screen reader: Announces "Delete post dialog, confirmation required"
- Keyboard: Escape closes dialog, Enter confirms deletion
- Touch targets: 44px minimum for delete button
Previous Story Intelligence
From Story 3.1 (History Feed UI):
Established Patterns to Follow:
- Logic Sandwich: HistoryFeed -> HistoryStore -> DraftService -> DB
- Atomic Selectors: All state access uses
useHistoryStore(s => s.field) - Sheet Pattern: HistoryDetailSheet for full draft view
- Draft Data Structure:
DraftRecordwith id, sessionId, title, content, tags, status
Key Files from Story 3.1:
src/lib/store/history-store.ts- Add deleteDraft actionsrc/lib/db/draft-service.ts- Add deleteDraft methodsrc/components/features/journal/HistoryDetailSheet.tsx- Add delete buttonsrc/components/features/journal/HistoryCard.tsx- Ensure updates propagate
Learnings to Apply:
- Atomic selectors prevent unnecessary re-renders
- State updates trigger UI reactivity automatically
- DraftService is the single source of truth for DB operations
- Error handling with toast notifications
From Epic 2 (Draft Management):
- Draft completion status established in Story 2.4
- Draft data structure with id, sessionId, status fields
- Copy button in detail sheet (add delete button alongside)
Component Implementation Details
DeleteConfirmDialog Component:
// src/components/features/journal/DeleteConfirmDialog.tsx
interface DeleteConfirmDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onConfirm: () => void;
draftTitle: string;
}
export function DeleteConfirmDialog({
open,
onOpenChange,
onConfirm,
draftTitle
}: DeleteConfirmDialogProps) {
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle className="text-destructive">
Delete this post?
</AlertDialogTitle>
<AlertDialogDescription>
You are about to delete <strong>"{draftTitle}"</strong>.
<br />
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={onConfirm}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Modified HistoryDetailSheet with Delete:
// src/components/features/journal/HistoryDetailSheet.tsx
export function HistoryDetailSheet() {
const selectedDraft = useHistoryStore(s => s.selectedDraft);
const closeDetail = useHistoryStore(s => s.closeDetail);
const deleteDraft = useHistoryStore(s => s.deleteDraft);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const handleDelete = async () => {
if (selectedDraft) {
await deleteDraft(selectedDraft);
setShowDeleteDialog(false);
closeDetail();
toast.success('Post deleted successfully');
}
};
if (!selectedDraft) return null;
return (
<>
<Sheet open={!!selectedDraft} onOpenChange={closeDetail}>
<SheetContent>
<DraftContent draft={selectedDraft} />
<SheetFooter className="gap-2">
<Button
variant="ghost"
className="text-destructive hover:text-destructive"
onClick={() => setShowDeleteDialog(true)}
>
<Trash2 className="w-4 h-4 mr-2" />
Delete
</Button>
<CopyButton draftId={selectedDraft.id} />
</SheetFooter>
</SheetContent>
</Sheet>
<DeleteConfirmDialog
open={showDeleteDialog}
onOpenChange={setShowDeleteDialog}
onConfirm={handleDelete}
draftTitle={selectedDraft.title}
/>
</>
);
}
Dexie Transaction for Cascade Delete:
// src/lib/db/draft-service.ts
static async deleteDraft(id: number): Promise<boolean> {
try {
// First get the draft to find its sessionId
const draft = await db.drafts.get(id);
if (!draft) return false;
await db.transaction('rw', db.drafts, db.chatLogs, async () => {
// Delete associated chat logs
await db.chatLogs
.where('sessionId')
.equals(draft.sessionId)
.delete();
// Delete the draft
await db.drafts.delete(id);
});
return true;
} catch (error) {
console.error('Failed to delete draft:', error);
return false;
}
}
Error Handling & Edge Cases
Error Scenarios:
-
Database Error: Deletion fails due to DB lock or corruption
- Action: Show error toast with "Retry" option
- Log error for debugging
- Don't remove from UI until successful
-
Draft Not Found: Draft was already deleted (race condition)
- Action: Silently succeed (idempotent)
- Remove from UI state
-
Offline Deletion:
- MVP: Allow immediate local deletion (no sync needed)
- Story 3.3: May queue deletions for server sync (if server persistence is added)
-
Delete Last Draft:
- Action: Show empty state after deletion
- Ensure hasMore is set to false
-
Delete During Loading:
- Action: Disable delete button while loading
- Prevent race conditions
Edge Case Handling:
// HistoryStore deleteDraft with error handling
deleteDraft: async (draft: Draft) => {
set({ loading: true, error: null });
try {
const success = await DraftService.deleteDraft(draft.id!);
if (success) {
set(state => ({
drafts: state.drafts.filter(d => d.id !== draft.id),
selectedDraft: null,
loading: false,
error: null
}));
toast.success('Post deleted');
} else {
set({
loading: false,
error: 'Failed to delete post'
});
toast.error('Failed to delete post', {
action: {
label: 'Retry',
onClick: () => get().deleteDraft(draft)
}
});
}
} catch (error) {
set({
loading: false,
error: 'Something went wrong'
});
toast.error('Something went wrong');
}
}
Testing Requirements
Unit Tests:
DraftService.deleteDraft()removes draft from databaseDraftService.deleteDraft()removes associated chat logs (cascade delete)DraftService.deleteDraft()handles non-existent draft (returns false)DraftService.deleteDraft()uses transaction (atomic operation)HistoryStore.deleteDraft()updates state correctlyHistoryStore.deleteDraft()handles errors gracefully
Integration Tests:
- Delete button opens confirmation dialog
- Confirm dialog triggers deletion
- Deletion removes item from history feed
- Deletion closes detail sheet
- Deletion shows success toast
- Cancel dialog does not delete
- Empty state shown when all drafts deleted
Edge Case Tests:
- Delete single draft (last one) -> empty state appears
- Delete during offline -> succeeds (local-only)
- Delete fails -> error toast, item remains
- Rapid delete clicks -> debounced, no double deletion
- Delete draft with very long content -> performance OK
- Delete draft with many chat logs -> transaction succeeds
- Close sheet during delete dialog -> dialog closes, no deletion
Accessibility Tests:
- Keyboard navigates to delete button
- Enter/Space activates delete button
- Dialog traps focus until dismissed
- Escape closes dialog without deleting
- Screen reader announces warning text
- Focus returns to trigger after close
- Touch targets are 44px minimum
Performance Tests:
- Delete completes within 500ms (local DB operation)
- UI updates immediately after deletion (no lag)
- History feed re-renders without full list flicker
Project Structure Notes
Following Feature-First Lite Pattern:
src/
components/
features/
journal/
HistoryDetailSheet.tsx # MODIFY: Add delete button
DeleteConfirmDialog.tsx # NEW: Delete confirmation
index.ts # UPDATE: Export new dialog
lib/
db/
draft-service.ts # MODIFY: Add deleteDraft()
store/
history-store.ts # MODIFY: Add deleteDraft action
Alignment with Unified Project Structure:
- Journal feature continues to expand
- No conflicts with existing features
- Reuses ShadCN AlertDialog component
Files to Create:
src/components/features/journal/DeleteConfirmDialog.tsxsrc/components/features/journal/DeleteConfirmDialog.test.tsx
Files to Modify:
src/lib/db/draft-service.ts- Add deleteDraft(), cleanupOrphanChats()src/lib/db/draft-service.test.ts- Add deletion testssrc/lib/store/history-store.ts- Add deleteDraft actionsrc/lib/store/history-store.test.ts- Add deletion testssrc/components/features/journal/HistoryDetailSheet.tsx- Add delete buttonsrc/components/features/journal/HistoryDetailSheet.test.tsx- Add delete testssrc/components/features/journal/index.ts- Export DeleteConfirmDialog
Offline Behavior Considerations
NFR-05 Compliance (Offline Behavior):
- Deletion is local-only operation (no server involved in MVP)
- Works offline immediately (no queue needed)
- User sees "Deleted" toast regardless of network status
Future Sync Considerations (Story 3.3):
- If server persistence is added post-MVP:
- Deletion may need to be queued for server sync
- Offline deletion should still work locally
- Sync manager handles server deletion on reconnection
Security & Privacy Requirements
NFR-03 & NFR-04 Compliance:
- Deletion is permanent (true data removal from IndexedDB)
- No backup/restore in MVP (privacy-focused)
- No server receives deletion notification (no server persistence)
- User has complete control over their data
Confirmation Pattern:
- Destructive actions require explicit user confirmation
- Warning text makes permanence clear
- No "accidental" deletions possible
References
Epic Reference:
- Epic 3: "My Legacy" - History, Offline Sync & PWA Polish
- Story 3.2: Deletion & Management
- FR-08: "Users can delete past entries"
Architecture Documents:
- Project Context: Logic Sandwich
- Project Context: State Management
- Project Context: Local-First Boundary
UX Design Specifications:
Previous Stories:
- Story 2.4: Export & Copy Actions - Button placement in detail sheet
- Story 3.1: History Feed UI - HistoryDetailSheet pattern
Epic Retrospectives:
- Epic 1 Retrospective - Atomic selector lessons
Dev Agent Record
Agent Model Used
Claude Opus 4.5 (model ID: 'claude-opus-4-5-20251101')
Debug Log References
Session file: /tmp/claude/-home-maximilienmao-Projects-Test01/5af3410f-14df-477d-b8c9-27fb416581c8/scratchpad
Completion Notes List
Story Analysis Completed:
- Extracted story requirements from Epic 3, Story 3.2
- Analyzed Story 3.1 for established HistoryFeed and HistoryDetailSheet patterns
- Reviewed architecture for Logic Sandwich and State Management compliance
- Reviewed UX specification for destructive action patterns
- Designed cascade delete for true privacy (orphan chat cleanup)
Implementation Context Summary:
Story Purpose: This story implements data sovereignty - giving users complete control over their "Legacy Log." The deletion feature is critical for privacy (NFR-03) and user empowerment. Users can remove any post they no longer want, with proper confirmation to prevent accidents.
Key Technical Decisions:
- Cascade Delete: Delete both draft and associated chat logs (true privacy)
- Confirmation Dialog: AlertDialog pattern with clear warning text
- Optimistic UI Update: Remove from feed immediately on success
- Permanent Deletion: No trash/undo in MVP (simpler, clearer)
- Local-First: Works offline immediately (no server sync in MVP)
Dependencies:
- No new external dependencies required
- Uses existing ShadCN AlertDialog, Button, Sheet components
- Reuses toast notification pattern from Story 2.4
Integration Points:
- HistoryDetailSheet gets delete button alongside copy button
- DeleteConfirmDialog is new reusable component
- DraftService gets delete method with transaction support
- HistoryStore gets deleteDraft action
- Story 3.3 will build on this for offline sync queue (if needed for server)
Files to Create:
src/components/features/journal/DeleteConfirmDialog.tsx- Delete confirmation dialogsrc/components/features/journal/DeleteConfirmDialog.test.tsx- Dialog tests
Files to Modify:
src/lib/db/draft-service.ts- Add deleteDraft() with cascade deletesrc/lib/db/draft-service.test.ts- Add deletion testssrc/lib/store/history-store.ts- Add deleteDraft actionsrc/lib/store/history-store.test.ts- Add deletion action testssrc/components/features/journal/HistoryDetailSheet.tsx- Add delete buttonsrc/components/features/journal/HistoryDetailSheet.test.tsx- Add delete flow testssrc/components/features/journal/index.ts- Export DeleteConfirmDialog
Deletion Flow Pattern:
User views past entry in HistoryDetailSheet
↓
User clicks Delete button (trash icon, destructive styling)
↓
DeleteConfirmDialog opens with warning
↓
User confirms deletion
↓
HistoryStore.deleteDraft(draft) called
↓
DraftService.deleteDraft(id) executes transaction
↓
Dexie removes draft + chat logs atomically
↓
HistoryStore updates state (removes draft)
↓
HistoryFeed re-renders without deleted item
↓
Detail sheet closes, success toast shown
User Experience Flow:
- Delete action requires explicit confirmation (safety)
- Clear warning: "This cannot be undone"
- Successful deletion gives immediate visual feedback
- Failed deletion shows error with retry option
- Deleting last item shows empty state
Lessons from Epic 1 Retrospective Applied:
- Atomic Selectors: All HistoryStore access uses
useHistoryStore(s => s.field) - Logic Sandwich: Delete goes through service layer, never direct DB access
- Error Handling: Toast notifications with retry options
- State Management: Optimistic updates with rollback on error
Implementation Completed:
- Story 3.2: Deletion & Management implemented with cascade delete for true privacy
- Database schema upgraded to v2 with sessionId index for cascade delete
- ChatMessage interface updated to include sessionId
- All chat save operations updated to include sessionId
- DeleteConfirmDialog component created with full accessibility support
- DraftViewSheet extended with delete button and confirmation flow
- Comprehensive unit and component tests written and passing
Architecture Modifications:
- Database version bumped from v1 to v2 with migration for legacy chat logs
- ChatMessage interface now requires sessionId field
- DraftService.deleteDraft() enhanced with atomic transaction for cascade delete
- Radix UI @radix-ui/react-alert-dialog added for AlertDialog component
Dev Notes Summary:
- Followed Logic Sandwich pattern: UI -> Service -> DB
- Used atomic selectors throughout (where applicable)
- Implemented proper error handling with toast notifications
- Full accessibility compliance with WCAG AA (44px touch targets, proper ARIA labels)
- Offline-first compliant: deletion works completely locally
File List
New Files Created:
src/components/ui/alert-dialog.tsx- ShadCN AlertDialog componentsrc/components/features/draft/DeleteConfirmDialog.tsx- Delete confirmation dialogsrc/components/features/draft/DeleteConfirmDialog.test.tsx- Dialog tests
Files Modified:
src/lib/db/index.ts- Added sessionId to ChatMessage, bumped schema to v2 with migrationsrc/lib/db/draft-service.ts- Enhanced deleteDraft() with cascade deletesrc/lib/db/draft-service.test.ts- Added cascade delete testssrc/services/chat-service.ts- Updated saveMessage to handle sessionIdsrc/services/chat-service.test.ts- Updated tests for sessionIdsrc/lib/store/chat-store.ts- Updated message saving to include sessionIdsrc/components/features/draft/DraftViewSheet.tsx- Added delete button and confirmation flow
Package Changes:
- Added: @radix-ui/react-alert-dialog
- Added: @testing-library/user-event
Skipped Tasks (for Story 3.1):
- HistoryStore with deleteDraft action (will be implemented when Story 3.1 creates history-store)
- HistoryFeed with auto-removal (will be implemented when Story 3.1 creates HistoryFeed)
- Empty state handling (will be implemented when Story 3.1 creates history components)
File List
New Files to Create:
src/components/features/journal/DeleteConfirmDialog.tsx- Delete confirmation dialogsrc/components/features/journal/DeleteConfirmDialog.test.tsx- Dialog tests
Files to Modify:
src/lib/db/draft-service.ts- Add deleteDraft() with cascade deletesrc/lib/db/draft-service.test.ts- Add deletion method testssrc/lib/store/history-store.ts- Add deleteDraft actionsrc/lib/store/history-store.test.ts- Add deletion action testssrc/components/features/journal/HistoryDetailSheet.tsx- Add delete button and statesrc/components/features/journal/HistoryDetailSheet.test.tsx- Add delete flow testssrc/components/features/journal/index.ts- Export DeleteConfirmDialog