Delete Memory API
Plan Metadata
- Plan type:
plan - Parent plan:
N/A - Depends on:
N/A docs/plans/memory-fetch-display.md(Memory data model)docs/plans/memory-enrichment-flow.md(Existing memory processing)- Status:
documentation
Status semantics: - draft: Plan is being created or updated and is not final. - approved: Plan is approved but not yet applied in code. - documentation: Code currently exists and matches the plan contract.
System Intent
-
What is being built: A delete memory API endpoint and UI component that allows users to permanently remove a memory from their feed and delete all associated assets from S3. The UI consists of a hamburger menu button in the top-right corner of an opened memory card, which displays a dropdown menu with a delete option.
-
Primary consumer(s): Mobile app users viewing memories in the feed; frontend MemoryViewer component; backend API consumers.
-
Boundary (black-box scope only):
- Input: User interaction (click menu button → click delete option) + memory ID
- Processing: Delete database records, delete S3 assets, update frontend state
- Output: Success/error response, UI state update (memory removed from feed)
Stage Gate Tracker
- [x] Stage 1 Mermaid approved
- [x] Stage 2 I/O contracts approved
- [x] Stage 3 pseudocode/technical details approved or skipped
1. Mermaid Diagram
Reference: .agent/skills/create-mermaid-diagram/SKILL.md
graph TD
MemoryViewer["memory-viewer-modal.tsx — components/memory/memory-viewer-modal.tsx"]:::unchanged
DeleteMenu["memory-delete-menu.tsx — components/memory/memory-delete-menu.tsx"]:::unchanged
DeleteClient["deleteMemory.ts — lib/api/memory/deleteMemory.ts"]:::unchanged
DeleteEndpoint["delete app.py — api/memories/delete/app.py"]:::unchanged
DynamoDB["DynamoDB — external"]:::unchanged
S3["S3 — external"]:::unchanged
MemoryViewer -->|"memory_id + open menu event"| DeleteMenu
DeleteMenu -->|"confirmed delete request with memory_id"| DeleteClient
DeleteClient -->|"DELETE /api/memories/:id with auth token"| DeleteEndpoint
DeleteEndpoint -->|"delete record by memory_id"| DynamoDB
DeleteEndpoint -->|"delete all assets by memory_id prefix"| S3
DynamoDB -->|"deletion confirmation"| DeleteEndpoint
S3 -->|"deletion confirmation"| DeleteEndpoint
DeleteEndpoint -->|"DeleteMemoryResponse"| DeleteClient
DeleteClient -->|"success or error result"| DeleteMenu
DeleteMenu -->|"remove memory from feed"| MemoryViewer
classDef unchanged fill:#d3d3d3,stroke:#666,stroke-width:1px;
classDef updated fill:#ffe58a,stroke:#666,stroke-width:1px;
classDef deleted fill:#f4a6a6,stroke:#666,stroke-width:1px;
classDef created fill:#a8e6a3,stroke:#666,stroke-width:1px; Stage 1 diagram shows the complete flow from user interaction through deletion and feedback.
2. Black-Box Inputs and Outputs
Keep this short. Define types in JSON-style blocks and capture each flow with path-level rows.
Global Types
MemoryId {
value: string (stable unique identifier for a memory)
}
RequestMetadata {
trace_id: string (request trace identifier)
requested_at: timestamp (request timestamp)
}
StandardError {
status: number (HTTP status)
code: string (stable machine-readable code)
message: string (human-readable summary)
}
DeleteMemoryResponse {
success: boolean (whether deletion was successful)
memory_id: MemoryId (the deleted memory ID)
deleted_at: timestamp (when deletion occurred)
}
Flow: deleteMemoryFromMenu
- Test files:
app/__tests__/components/memory-viewer-delete.test.tsx,main/server/tests/integration/test_delete_memory_api.py - Core files:
components/memory/memory-viewer-modal.tsx,api/memories/delete/app.py,lib/api/memory/deleteMemory.ts
Type Definitions
DeleteMemoryInput {
memory_id: MemoryId (required, from URL path)
request_metadata: RequestMetadata (trace context)
}
DeleteMemoryOutput {
response: DeleteMemoryResponse (deletion confirmation)
}
DeleteMemoryError {
status: number (400, 404, 500, etc.)
code: string (invalid-id, not-found, internal-error, unauthorized)
message: string (human-readable error)
}
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
|---|---|---|---|---|---|
deleteMemory.success | DeleteMemoryInput | DeleteMemoryResponse success=true; memory removed from feed, all S3 assets deleted (video, audio, thumbnails, transcripts, metadata), database record deleted | happy path | Database and S3 deletions are transactional; if S3 deletion fails, log error but respond success if DB deletion succeeded | |
deleteMemory.not-found | DeleteMemoryInput | DeleteMemoryError status=404 code=not-found message="Memory not found" | error | Memory ID does not exist in database; no state change | |
deleteMemory.unauthorized | DeleteMemoryInput | DeleteMemoryError status=403 code=unauthorized message="Not authorized to delete this memory" | error | User is not the owner of the memory; no state change | |
deleteMemory.invalid-id | DeleteMemoryInput | DeleteMemoryError status=400 code=invalid-id message="Invalid memory ID format" | error | Memory ID format is invalid; no state change | |
deleteMemory.s3-cleanup-partial | DeleteMemoryInput | DeleteMemoryResponse success=true (with optional warning) | edge case | Some S3 assets may already be deleted or inaccessible; endpoint succeeds if DB deletion succeeds regardless of S3 state |
Flow: renderDeleteMenuUI
- Test files:
app/__tests__/components/memory-viewer-modal.test.tsx - Core files:
components/memory/memory-viewer-modal.tsx,components/memory/memory-delete-menu.tsx
Type Definitions
MenuUIInput {
memory_id: MemoryId (required)
user_id: UserId (required, to check ownership)
is_loading: boolean (whether deletion is in progress)
}
MenuUIState {
menu_visible: boolean
dropdown_open: boolean
is_deleting: boolean
error_message: string | null
}
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
|---|---|---|---|---|---|
renderMenu.default | MenuUIInput | Menu button visible in top-right; clicking opens dropdown | happy path | Menu only shown if user is owner of memory | |
deleteOption.click | User click event | API call triggered, is_deleting flag set, button disabled during request | happy path | UI should show loading state while request is pending | |
deleteMemory.success-ui | Success response from API | Memory card slides out/fades out, feed re-renders without deleted memory | happy path | Smooth transition animation; maintain scroll position if possible | |
deleteMemory.error-ui | Error response from API | Error message displayed in toast/alert, menu remains open or closes with error shown | error | User can retry or dismiss error |
Stage 2 contracts define the API input/output types and all success/error paths with their expected behavior.
3. Pseudocode / Technical Details for Critical Flows (Optional)
Flow: deleteMemoryFromMenu
Backend (Python/FastAPI):
1. Extract memory_id from URL path
2. Authenticate request (verify JWT token)
3. Query DynamoDB for memory record with given ID
4. If not found, return 404 error
5. Check if authenticated user is owner of memory (compare user_id in memory record)
6. If not owner, return 403 unauthorized error
7. Begin transaction:
a. Delete memory record from DynamoDB (delete main memory item)
b. Query S3 for all objects with memory_id prefix
c. Delete all S3 objects (video, audio, thumbnails, transcripts, metadata JSON)
d. If S3 deletion has errors, log them but do not fail the transaction
e. Commit database deletion
8. Return success response with deletion timestamp
9. If exception occurs: rollback transaction if possible, return 500 error
Frontend (TypeScript/React Native):
1. User clicks hamburger menu in MemoryViewer
2. Menu button opens dropdown with delete option
3. User clicks "Delete Memory" option
4. Show confirmation dialog: "Are you sure? This cannot be undone."
5. If user confirms:
a. Send DELETE /api/memories/:id request
b. Set is_deleting=true, disable UI interactions
c. Show loading spinner
6. On success response:
a. Update local state to remove memory from feed
b. Trigger animation (fade out / slide away)
c. Refetch feed or update cache to reflect deletion
d. Show success toast: "Memory deleted"
7. On error response:
a. Show error toast with message from server
b. Reset is_deleting=false, re-enable menu
c. Allow user to retry
- Implementation notes:
- Frontend confirmation dialog is critical to prevent accidental deletions
- S3 deletion failures should not block the overall success response (user sees memory deleted, orphaned assets can be cleaned up by a separate job)
- Consider implementing soft-delete first, with a grace period, if we want to support un-delete in the future
- Ensure all S3 prefixes for a memory are deleted (video files, audio files, thumbnails, metadata, transcripts, etc.)
- Track deletion in audit logs for compliance
Stage 3 pseudocode shows the detailed implementation strategy for both backend and frontend flows.
4. Plan Status
All planning stages are complete: - Stage 1: Mermaid diagram created and approved - Stage 2: Black-box input/output contracts defined - Stage 3: Pseudocode and technical implementation details specified
Ready for implementation phase.
5. Handoff to Related Plan Reconciliation
After approval, apply .agent/skills/reconcile-plans/SKILL.md to propagate contract updates across linked plans.