Users can now upload an photo for any recipe directly from the view page. The upload button appears as either a 'Replace' overlay on existing images or an empty dashed placeholder for recipes without one. Upload flow: 1. Click upload button -> file picker opens (accepts image/*) 2. JavaScript reads the file as base64, POSTs to /upload-image with form fields: filename, file-b64, file-name 3. Server decodes the base64, saves to <recipe-dir>/<basename>.<ext> 4. Server updates the .cook file's YAML front matter, adding or updating the 'image:' key with a /recipe-images/ URL 5. Server returns JSON success, page reloads to show the image Server routes added: - POST /upload-image — accepts base64-encoded image upload - GET /recipe-images/<filename> — serves saved recipe images (extension-whitelisted to .jpg/.jpeg/.png/.gif/.webp) Image files are stored alongside .cook files in the recipe directory and served via the /recipe-images/ path. The fsnotify watcher detects the .cook metadata change and triggers an SSE reload.
Roux
Roux is a personal/family recipe management site.
It's intended to be low friction for entering recipes and tracking when you've cooked them.
Cooklang
Roux uses Cooklang (https://cooklang.org/) as a source of truth for all recipe content. Any recipe either starts in Cooklang or is immediately converted to Cooklang by one mechanism or another.
Other details
Cook history
Roux lets you track when you cook recipes. I like this because we cook a lot of different recipes and I like to be able to go back to find things I liked in the past so I don't forget about them.
Technical details
Development environment
Docker is used for all development tools. Nothing is required to be installed on the local machine except Docker.
Backend API: Haskell + SQLite
Frontend: Static HTML + Pico CSS
The actual backing for recipes themselves is a single cooklang directory with an in-process search index that gets rebuilt whenever a file is added to the directory.
Project structure:
cooklang-hs
A Cooklang parser written in Haskell.
roux-server
The webserver for Roux. Parses Cooklang files on disk, indexes them, renders HTML templates for presenting recipes.