Adding Photos to Preparation Items
Materials, tools, and venues can now have photos attached. Reusing the existing attachment pattern while adapting it for preparation item context.
Adding Photos to Preparation Items
When Text Isn’t Enough
The preparation section has five categories: materials, tools, venue, personnel, and qualification. You could write names, descriptions, quantities, and links. But describing what an ingredient looks like or where a venue is located—in words alone—has its limits.
A single photo would do what a paragraph couldn’t.
Where to Attach
Task-level photo attachments already existed. StoredFile handles storage, thumbnail generation, and downloads. The question was how to connect this to individual preparation items.
Task attachments use an attachments: [{order, stored_file_id}] array. We added the same structure to the preparation item base model. Currently limited to one photo per item, but the array structure allows future expansion.
Three Out of Five
Only materials, tools, and venue got photo support. Personnel and qualification didn’t fit—attaching someone’s photo feels awkward, and qualification documents belong in a different context.
What the Server Does
An upload endpoint: POST /{task_id}/{category}/{order}/image/upload. Following the existing attachment pattern:
- Reject if a photo already exists—delete first, then re-upload
- Store the file and generate a 512px thumbnail
- Create a
StoredFiledocument and push to the item’sattachmentsarray
Deletion: DELETE /{task_id}/{category}/{order}/attachment/{attachment_order}/delete. Pulls the entry from the array.
Both task records and task templates got identical endpoints.
What the App Shows
A shared PreparationItemPhotoInput component serves all three screens—material, tool, and venue editing.
No photo? An add button appears. Choose from camera or photo library. Photo exists? A thumbnail shows. Tap to view the original at full size with zoom. Delete from the full-size view.
Desktop got the same feature: file picker, upload, thumbnail display, hover-to-delete.
A Serialization Oversight
First implementation had a bug: photos only appeared after leaving and returning to the screen. The cause was TaskModel.toJSON() missing the attachments field for preparation items.
The app uses SQLite cache. Tasks are serialized to JSON for storage. Without attachments in toJSON(), the data vanished on save and came back empty on read.
A one-line fix per category. But this kind of bug can recur whenever a new field is added—a weakness of manual serialization.
The Weight of One Photo
Functionally, it’s a small change. But a photo of an actual flour bag next to “Flour 500g” transforms the preparation section from abstract checklist to concrete reference. Photos fill the context that text alone can’t convey.