feat: implement catalog ingredient file upload and voice-memo capture (#2038)#2079
Merged
Conversation
…#2038) Replace the two "coming soon" stubs on the CatalogIngredient Media panel with working file-upload and voice-memo capture. - New POST /catalog/ingredients/:id/media/upload persists a dropped/picked file into the matching federating library dir (image->data/images as PNG via the existing gallery saver, audio->data/audio, video->data/videos) and attaches it via the existing media-refs seam. Server picks the media kind from the MIME; documents are rejected (no federating dir -> would break peer references). - New POST /catalog/ingredients/:id/media/voice transcribes a recorded WAV via the existing Whisper pipeline and attaches a kind:'audio' row with the transcript in caption (persist after transcription; no orphan on failure). - Both routes Zod-validated (catalogMediaFileUploadSchema / catalogMediaVoiceMemoSchema). - Client: drag-drop of real files, Upload-file picker, Record-memo button (reusing startMemoRecording), inline audio/video players in MediaTile, and the two "coming soon" toasts removed. Federation is automatic (catalogSync ships the reference, peerMediaLibrarySync ships the bytes). - Unit tests for the new service (mime classification + upload/voice orchestration with injected deps). Claude-Session: https://claude.ai/code/session_01M1aQgtbUZZ9WmE9V6XyT8Q
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2038
Summary
Replaces the two "coming soon" stubs on the CatalogIngredient Media panel with working file-upload and voice-memo capture, both attaching through the existing
onAttach(mediaKey, kind)seam and federating like gallery attachments.What shipped
POST /catalog/ingredients/:id/media/uploadstores the file in the matching federating library dir (image→data/imagesas PNG via the existing gallery saver, audio→data/audio, video→data/videos), then attaches it. The server derives the mediakindfrom the MIME; documents are rejected (no federating dir → would break references on peers).startMemoRecording(MediaRecorder → 16 kHz mono WAV, mobile Safari/Chrome friendly). NewPOST /catalog/ingredients/:id/media/voicetranscribes via the existing Whisper pipeline and attaches akind:'audio'row with the transcript incaption(persist happens after transcription, so a failed transcript never orphans a file).catalogSyncships themedia_keyreference,peerMediaLibrarySyncships the bytes (audio/video dirs already replicate). NohashImageForManifestcall needed at the attach site.MediaTile; both "coming soon" toasts and the stale tracking comment removed.catalogMediaFileUploadSchema/catalogMediaVoiceMemoSchema) wired into both new routes.Files
server/services/catalogMedia.js(new) +catalogMedia.test.js(new, 13 tests)server/routes/catalog.js,server/lib/catalogValidation.jsclient/src/pages/CatalogIngredient.jsx,client/src/services/apiCatalog.js.changelog/NEXT.mdTest plan
npx vitest run services/catalogMedia.test.js→ 13 pass (mime classification + upload/voice orchestration with injected deps — no DB/disk/Whisper).lib/catalogValidation.test.js→ 100 pass;routes/catalog.test.jscorrectly skips on the realportosDB (safety gate).CatalogIngredient.test.jsx→ 21 pass, ESLint clean, production build succeeds.https://claude.ai/code/session_01M1aQgtbUZZ9WmE9V6XyT8Q