Add checkup review flags, duplicate detection, and corrected painting images.

Introduce checkup_checked/checkup_fixed on paintings with Checkup page filters and API. Fixed paintings auto-mark as reviewed. Add find-duplicates tooling and document debug/checkup workflow. Include Botticelli and Michelangelo image fixes from checkup.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Danila Khodjaef
2026-06-20 20:45:55 +03:00
co-authored by Cursor
parent 4683089495
commit 4c6acd5a3a
55 changed files with 750 additions and 39 deletions
+111
View File
@@ -204,6 +204,112 @@ Returns the image bytes with `Cache-Control: public, max-age=86400`, or `404` if
---
## Developer image audit
Routes for the **Checkup** page and **Debug mode** on painting detail. Register `GET /api/paintings/checkup` **before** `GET /api/paintings/:id` so `"checkup"` is not parsed as a painting id.
### `GET /api/paintings/checkup`
Full-catalog audit table for the Checkup UI.
**Response**
```json
{
"paintings": [
{
"id": 36,
"title": "Trinity",
"artist_name": "Andrei Rublev",
"year": 1411,
"gallery_file": "paintings/Andrei_Rublev_Trinity.jpg",
"gallery_preview": "paintings/thumbs/Andrei_Rublev_Trinity_thumb.jpg",
"detail_file": "paintings/Andrei_Rublev_Trinity.jpg",
"detail_preview": "paintings/thumbs/Andrei_Rublev_Trinity_thumb.jpg",
"detail_on_demand": false,
"gallery_file_exists": true,
"detail_file_exists": true,
"checked": false,
"fixed": false
}
],
"total": 1201
}
```
| Field | Meaning |
|-------|---------|
| `checked` | Reviewed in checkup workflow (`checkup_checked`) |
| `fixed` | Image replaced via Fix (`checkup_fixed`) |
| `detail_on_demand` | `true` when detail would use `GET /api/paintings/:id/image?size=full` |
| `gallery_file_exists` / `detail_file_exists` | Disk check under `IMAGE_DIR` |
---
### `PATCH /api/paintings/:id/checkup-flags`
Update review flags. Body: `{ "checked"?: boolean, "fixed"?: boolean }` — at least one field required.
Setting `fixed: true` also sets `checked: true`. While `fixed` is true, the API rejects clearing `checked`.
**Response**
```json
{ "checked": true, "fixed": false }
```
---
### `GET /api/paintings/:id/debug-image-search`
Google-family image search for debug / checkup (Custom Search → Google Arts & Culture → scrape → DuckDuckGo). Used by **Search visible** on the Checkup page and the debug panel on painting detail.
**Response**
```json
{
"query": "Andrei Rublev Trinity painting",
"imageUrl": "https://…",
"source": "google-arts",
"pageUrl": "https://…"
}
```
---
### `POST /api/paintings/:id/fix-image`
Download a remote URL and replace the paintings local full image + thumbnail. Sets `checkup_fixed = true` and `checkup_checked = true`.
**Body**
```json
{ "imageUrl": "https://…" }
```
**Response**
```json
{
"imagePath": "paintings/Artist_Title.jpg",
"thumbnailPath": "paintings/thumbs/Artist_Title_thumb.jpg",
"fixed": true,
"checked": true
}
```
---
### `GET /api/debug/image-proxy`
Proxy a remote image URL for debug preview (avoids hotlink / CORS blocks in the browser).
**Query:** `url` — must be `http://` or `https://`
Returns image bytes with appropriate `Content-Type`.
---
## Frontend helpers
The React client wraps these endpoints in `client/src/api/client.ts`:
@@ -220,3 +326,8 @@ The React client wraps these endpoints in `client/src/api/client.ts`:
| `imageUrl(path)` | `/images/<path>` or placeholder |
| `galleryImageUrl(painting)` | Local thumb/full only (3D) |
| `paintingImageUrl(painting)` | Local file or on-demand API |
| `api.getPaintingCheckup()` | `GET /api/paintings/checkup` |
| `api.updatePaintingCheckupFlags(id, flags)` | `PATCH /api/paintings/:id/checkup-flags` |
| `api.getPaintingDebugImageSearch(id)` | `GET /api/paintings/:id/debug-image-search` |
| `api.fixPaintingImage(id, imageUrl)` | `POST /api/paintings/:id/fix-image` |
| `debugImageProxyUrl(imageUrl)` | `GET /api/debug/image-proxy?url=…` |