Photo Management
The Photo Management system lets carers and administrators upload, view, and manage photographs for each animal record. Photos are stored securely in private cloud storage and served through an authenticated proxy, ensuring that images are only accessible to members of the owning organisation.
Overview
Every animal in WildTrack360 can have two types of photos:
- Primary photo -- a single profile image displayed on the animal's card and detail header
- Gallery photos -- a collection of dated, described images shown in a carousel on the animal detail page
Both types are uploaded to private S3-compatible storage (Wasabi/AWS) and are never publicly accessible. When a user views a photo, the browser requests it through an authenticated server-side proxy that verifies the user's identity and organisation membership before returning the image bytes.
Uploading Photos
Supported Formats and Limits
| Constraint | Value |
|---|---|
| Maximum file size | 10 MB |
| Allowed formats | JPEG, PNG, WebP, GIF |
| File name sanitisation | Non-alphanumeric characters (except ., -, _) are replaced with underscores |
Primary Photo Upload
The primary photo is set from the animal edit form. When a file is uploaded:
- The server validates the file type and size.
- A unique key is generated in the format
orgs/{orgId}/animal-photos/{uuid}-{filename}. - The file is uploaded to private S3 storage.
- The S3 key (not a public URL) is saved to the animal's
photofield. - The upload is recorded in the audit log.
Gallery Photo Upload
Gallery photos are added from the Photo Gallery card on the animal detail page. Clicking Add Photo opens a dialog where the user:
- Selects an image file (with a live preview).
- Enters a description of the photo (required).
- Clicks Save Photo to upload.
The upload creates a Photo record in the database linked to the animal, storing the S3 key, description, and date.
Upload Dialog Fields
| Field | Required | Description |
|---|---|---|
| Picture | Yes | The image file to upload (JPEG, PNG, WebP, or GIF, max 10 MB) |
| Description | Yes | A brief text description of the photo |
Photo Gallery
The Photo Gallery appears as a card on the animal detail page. It displays uploaded gallery photos in a carousel with previous/next navigation.
Each photo in the carousel shows:
- The image itself (scaled to fit, max height 400px)
- The date the photo was taken, formatted as a readable date
- The description entered at upload time
Managing Photos
Users with photo management permissions see additional controls:
| Action | Control | Description |
|---|---|---|
| Add photo | Add Photo button in the gallery header | Opens the upload dialog |
| Delete photo | Trash icon on each photo | Permanently removes the photo from storage and the database |
When a photo is deleted, the gallery updates immediately without a page reload.
Authenticated Photo Serving
Photos are served through an authenticated proxy endpoint rather than direct S3 URLs. This is a deliberate security measure -- all objects in the S3 bucket are private, and there are no pre-signed URLs or public access policies.
How It Works
- The browser requests
/api/photos/serve?key={s3Key}. - The server authenticates the user via Clerk.
- The organisation ID embedded in the S3 key (e.g.,
orgs/{orgId}/...) is extracted and compared against the user's active organisation. - If the user belongs to the correct organisation, the server fetches the object from S3 and streams it back with appropriate headers.
- If any check fails, the request is rejected with a
401,403, or404status.
Response Headers
| Header | Value | Purpose |
|---|---|---|
Content-Type | Original MIME type of the image | Correct rendering in the browser |
Cache-Control | private, max-age=3600, must-revalidate | Caches in the user's browser for 1 hour but prevents shared/CDN caching |
X-Content-Type-Options | nosniff | Prevents MIME type sniffing attacks |
This approach ensures that even if an S3 key is leaked, the photo cannot be accessed without a valid authenticated session in the correct organisation.
Integration with Other Modules
| Module | Integration |
|---|---|
| Animal Record History | Gallery photos appear on the animal detail page alongside care records |
| Audit Logging | Photo uploads are recorded as CREATE actions on the AnimalPhoto entity |
| Data Export & Reporting | All animal photos (primary and gallery) are included in the full data export ZIP file |
| Roles & Permissions | The canManagePhotos permission controls who can add and delete gallery photos |