From 90c209aef0467cb1aa49eef4c3d272574f43fca8 Mon Sep 17 00:00:00 2001 From: Stephan Kerkman Date: Thu, 28 May 2026 21:23:32 +0200 Subject: [PATCH] docs: add plant card photos design spec Co-Authored-By: Claude Sonnet 4.6 --- .../2026-05-28-plant-card-photos-design.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-28-plant-card-photos-design.md diff --git a/docs/superpowers/specs/2026-05-28-plant-card-photos-design.md b/docs/superpowers/specs/2026-05-28-plant-card-photos-design.md new file mode 100644 index 0000000..53bd9b4 --- /dev/null +++ b/docs/superpowers/specs/2026-05-28-plant-card-photos-design.md @@ -0,0 +1,89 @@ +# Plant Card Photos — Design Spec + +**Date:** 2026-05-28 + +## Overview + +Allow users to store photos of the physical plant label/care card that came with a plant. Up to 3 photos per plant (e.g. front and back of the card). Accessed via a small button on the plant detail page, opening a dedicated card page — keeping the detail page clean. + +--- + +## Model + +New model `PlantCardPhoto`: + +- `plant` — ForeignKey to `Plant`, `on_delete=CASCADE`, `related_name='card_photos'` +- `image` — ImageField, `upload_to='plants/cards/'` +- `uploaded_at` — DateTimeField, `auto_now_add=True` + +No thumbnail concept. Ordering by `uploaded_at`. + +The upload view enforces a maximum of 3 card photos per plant (silently blocks if already at 3). + +--- + +## Views & URLs + +Two new views in `plants/views/plants.py`, both `@require_POST`: + +| View | URL | Action | +|---|---|---| +| `upload_card_photo(request, pk)` | `plants//card-photos/upload/` | Creates a `PlantCardPhoto`, re-renders the card page partial | +| `delete_card_photo(request, card_photo_pk)` | `card-photos//delete/` | Deletes the file and record, re-renders the card page partial | + +A new GET view: + +| View | URL | +|---|---| +| `plant_card(request, pk)` | `plants//card/` | + +The card page renders `plants/plant_card.html` with all card photos for the plant. + +--- + +## Templates + +### `plants/views/plants.py` change + +The `plant_detail` view's `prefetch_related` call needs `'card_photos'` added so the `card_photos.exists()` check in the template doesn't fire an extra query. + +### `plants/plant_detail.html` change + +Add a small button near the bottom (above the delete link), rendered only when `plant.card_photos.exists()`: + +```html +{% if plant.card_photos.exists %} +🪧 View plant card +{% endif %} +``` + +### New: `plants/plant_card.html` + +Full page extending `base.html`: + +- Back button → `plant_detail` +- Title: "Plant card" +- Photo grid (portrait thumbnails, 3-column) with delete button per photo +- Upload form with `capture="environment"` for mobile camera +- Upload form hidden when 3 photos already uploaded +- Hint text: "Up to 3 photos — front & back of the label" + +The upload and delete forms use htmx (`hx-post`, `hx-target="#card-gallery"`, `hx-swap="outerHTML"`) targeting a `