docs: add plant card photos design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f594105311
commit
90c209aef0
1 changed files with 89 additions and 0 deletions
|
|
@ -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/<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
|
||||
Loading…
Add table
Reference in a new issue