bloombase/docs/superpowers/specs/2026-05-28-plant-card-photos-design.md
Stephan Kerkman 90c209aef0 docs: add plant card photos design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 21:23:32 +02:00

89 lines
2.8 KiB
Markdown

# 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/<pk>/card-photos/upload/` | Creates a `PlantCardPhoto`, re-renders the card page partial |
| `delete_card_photo(request, card_photo_pk)` | `card-photos/<pk>/delete/` | Deletes the file and record, re-renders the card page partial |
A new GET view:
| View | URL |
|---|---|
| `plant_card(request, pk)` | `plants/<pk>/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 %}
<a href="{% url 'plant_card' plant.pk %}" class="btn btn-sm btn-outline-secondary mb-2">🪧 View plant card</a>
{% 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 `<div id="card-gallery">` that wraps the grid + upload form, following the same pattern as `photo_gallery.html`.
### New partial: `plants/partials/card_gallery.html`
Contains the photo grid and upload form, rendered by both the initial page load and htmx responses.
---
## Migration
Single migration adding `PlantCardPhoto`.
---
## Out of Scope
- OCR or data extraction from card photos (future work)
- Viewing card photos inline on the plant detail page
- Lightbox / full-screen image viewer