Releases: Dim145/FigureCollector
Releases · Dim145/FigureCollector
Release list
0.45.3 — Bug fixes
A bug-fix release: the reported catalogue-ambiance click, plus a frontend/backend correctness sweep and one dependency security bump.
Fixed
Catalogue / browse
- Ambiance preview click — clicking an ambiance tile in the catalogue's "Ambiances visuelles" preview now opens it. Previously it did nothing unless you first went through "Toutes les ambiances".
Frontend
- The mobile "Générer 3D" checkbox now respects the same admin-only gate as desktop (a non-admin no longer gets a checkbox that reverts).
- The per-series MangaCollector pill/link now refreshes after linking / syncing / unlinking (was stale up to 5 min).
- The
gkeyboard-shortcut hint pill now dismisses after its timeout instead of lingering. - The duplicate-figure warning clears once the typed name drops below the search threshold (no more stale matches).
- Fixed timer/save leaks: achievement toasts no longer fire after navigating away; the shelf-planner's last layout edit is no longer dropped when leaving mid-save; the live-sync WebSocket no longer risks orphaned reconnect timers / duplicate sockets.
- The entity hero image no longer shows a false "no image" placeholder when moving between two entities that share the same cover URL.
Backend
- Pre-order stats: the "placed" tile counted every status (including received/cancelled) — it now counts only active pre-orders, and the breakdown total no longer double-counts.
- Notification channels: editing only a channel's destination no longer silently disables the channel.
- Follower / following counts now match the follower list (both count publicly-visible profiles), so the badge equals the list.
- Concurrent first-photo uploads to the same figure no longer 500 (the "primary photo" race is resolved + retried).
- Manga-server approval/revocation events now appear in the per-event notification-routing settings.
- The wishlist "already owned" guard is now race-free (evaluated atomically at insert time).
- Catalogue pagination is now deterministic — a stable tiebreaker prevents a figure being skipped or duplicated across pages when creation timestamps tie.
Security
- Bumped
cmov0.5.3 → 0.5.4 (GHSA-3rjw-m598-pq24): the previous version could compute wrong results on aarch64 when high register bits are set. It is pulled transitively by the Web-Push signing stack (web-push-native→jwt-simple).
Full changelog: 0.45.2...0.45.3
0.45.2 — Security & NSFW fixes
A security + bug-fix release. It also rolls up the 0.45.1 NSFW-visibility fixes, which weren't separately released.
🔒 Security
Hardening from an internal security review — self-hosters should upgrade.
- AI image fetch — SSRF / local-file read.
official_image_urlis now validated tohttp(s)when a figure is created or edited, and the embed/gsplat worker's image fetcher rejects non-http(s)schemes and non-public targets (with redirect re-validation). This prevents a signed-in user from steering the worker atfile://or internal addresses once visual search is enabled. - PDF parsing crash — RUSTSEC-2026-0187.
lopdfbumped to 0.42.0 (via the direct dependency +pdf-extract0.12) so a crafted invoice / insurance-dossier PDF can no longer abort the server process. A parse-concurrency cap was also added. - Notification webhooks — DNS rebinding. Outbound webhook / ntfy / apprise delivery now filters private, link-local and cloud-metadata addresses at connection time, closing a DNS-rebinding window. (OIDC discovery to a self-hosted internal IdP is intentionally unaffected.)
- Worker internal channel. The embed/gsplat worker refuses to send its token and private photo bytes over plaintext HTTP unless explicitly opted in for a trusted same-host network (
WORKER_ALLOW_INSECURE=1). - Private-photo caching. The PWA service worker no longer retains private photo bytes past the end of a session (NetworkFirst + cache purge on 401), so they can't linger on a shared device.
- Container hardening. The optional gsplat GPU worker now drops all Linux capabilities.
- Dependencies. Pillow pinned ≥ 12.2 (CVE-2026-25990, CVE-2026-40192) in the macOS worker; PyMuPDF pinned ≥ 1.26.7 in the GPU worker.
🖼️ Fixed — NSFW visibility (0.45.1)
- Hide now truly hides (rather than blurs) NSFW figures in the catalogue discovery rails and the ambiance mosaics — and applies immediately, without a page reload.
- Achievement seals honour the NSFW preference (generic placeholder when hidden, blurred when set to blur).
- Reaching an NSFW figure directly (pre-order link / URL) while hiding now shows a consent interstitial with a shortcut to the setting, instead of a generic 404.
Notes
- Backend and client are updated in place; the embed/gsplat worker images pick up their share of the fixes on their next rebuild. Visual search is admin-flag-gated and off by default.
Full changelog: 0.45.0...0.45.2
0.45.0
What's new in 0.45.0
A large cumulative release rolling up everything since 0.40.1 — five new features (across 0.41.0–0.45.0), the first automated test suite + CI, and a batch of fixes.
Added
- Per-shop stock availability (0.42.0) — figure pages and shop pages now show whether each linked shop has the figure in stock / out of stock / preorder, parsed from orzgk (the WooCommerce
is_in_stock/backorders_alloweddata) and, when the proxy reports it, from the proxy's/productstatusfield. The buy control adapts per shop: in stock keeps the usual Acheter, out of stock demotes to a quiet Voir + a red "Rupture" label, preorder becomes Précommander, and an unknown/unscraped state makes no claim. Each demoted state shows a "Vérifié il y a …" freshness line (flagged stale past 48h); a status not refreshed for 7 days ages back to "unknown" so a stale badge never lingers. - Add a figure by photo (0.43.0) — a new Photo tab in the add-figure lookup: snap or upload a photo → on-device DINOv2 embedding → nearest-neighbour match against the catalogue → pick a result and it prefills the form. The photo never leaves the device (only the embedding is sent).
- Tag your own photos (0.43.0) — owned-item photos can be auto-tagged with WD-Tagger v3 and used to filter your collection by appearance (tag chips on each photo + a tag filter on the collection). Owned-photo tagging is opt-in and stays off until
WORKER_INTERNAL_TOKENis set (see Notes). - Collection over time (0.44.0) — a new Évolution section on Insights: a dual-line growth curve of cumulative pieces and cumulative spend, reconstructed month-by-month from purchase dates (spend converted to your display currency).
- Provenance & archive reason (0.44.0) — record how each piece entered the collection (purchased / gift / trade / found / inherited) and, when archiving, why (sold / traded / lost / gifted). Shown in the owned-item editor and the archived banner.
- Public vitrine sharing (0.45.0) — share a display cabinet via a public, read-only link (
/v/:token), the same way the gift list is shared. Visitors see the cabinet's pieces (photos, condition, for-sale/trade flags) with no account; deliberately stricter than the public profile — prices, value and notes are never exposed. - Admin task console (0.41.0) —
/admin/tasksrebuilt into a real task-management console: every background task (server crons, 3D scans, OCR jobs) in one filterable table (state / type / source / trigger / search / since — all persisted), a result message for every run, a "hide no-op runs" toggle, a per-service health strip with readable tooltips, and per-row actions (cancel / relaunch / delete) showing who triggered manual runs.
Fixed
- Paid pre-order balances were still counted in the « Solde à régler » ribbon total — the per-entry view honoured
balance_paid_at, but the aggregate didn't. - Catalogue covers intermittently failed to load — added a service-worker cache rule + an on-error fallback to the source image so an already-loaded cover never silently breaks.
- Collection card's top border was clipped on hover.
- Settings nav rail wasn't sticky and scrolled away.
- Catalogue ambiance preview could stay stuck loading forever.
Tooling
- First automated tests + CI. Frontend unit tests (Vitest: money/currency math, admin task formatting, cover-URL resolution, pre-order stats), backend integration tests (
#[sqlx::test]against an ephemeral pgvector DB) on top of the existing unit tests, and Playwright E2E smoke flows (auth, navigation, manual figure entry, add-preorder dialog) against an ephemeral Docker stack — all wired into a newci.yml(client / server / e2e jobs). Advanced CodeQL setup added.
Database
All migrations are idempotent (ADD COLUMN/CREATE … IF NOT EXISTS):
server_job_runs.changed+triggered_by_user+ backfill,service_heartbeats(0.41.0)figure_shop_stock(0.42.0)owned_photo_tags(photos.visual_tags) +figure_embedding_queue.figure_idmade nullable (0.43.0)owned_provenance(acquisition_source/acquired_from/archive_reasononowned_items) (0.44.0)vitrine_share(collection_locations.share_token) (0.45.0)
Notes (opt-in / configuration)
- The semantic & appearance search, recommendations, and photo recognition are admin-flag-gated and off by default — enable them in Réglages admin (they need the embed worker to have indexed the catalogue).
- Owned-photo tagging requires a shared secret: set
WORKER_INTERNAL_TOKENon the server equal toEMBED_WORKER_TOKENon the worker. Unset = the feature stays off (the internal fetch route fail-closes). nginx also404s/api/internal/*externally.
Full changelog: 0.40.1...0.45.0
0.40.1
What's new in 0.40.1
Added
- PayPal invoice parsing — uploaded PayPal « Activités » receipts are now detected and parsed automatically. The parser reads the buyer-side amount from the
X € EUR = Y $ USDconversion line (falling back to the de-doubled receipt total), the transaction id (rejoined even when the print page wraps it across two lines), the invoice number, and the French payment date. It toleratespdf-extract's doubled-bold glyphs (116699,,5500→169,50). ORZGK PayPal Standard invoices keep using the generic parser. Adds 4 parser fixture tests. - Pre-order “balance paid” tracking — a new Solde réglé le date field on each pre-order records when the remaining balance was actually paid (manufacturers usually bill it weeks before shipment).
Fixed
- A pre-order no longer shows a phantom Solde restant once it is settled. The figure timeline now reads Payé intégralement when the order ships/arrives, when the deposit reaches the full price, or when the new balance paid date is set — and surfaces that date when present.
Database
- Migration
20260625000001_preorder_balance_paidadds the nullablepreorders.balance_paid_atcolumn (idempotentADD COLUMN IF NOT EXISTS).
Full changelog: 0.40.0...0.40.1
chore: bump version to 0.40.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: bump version to 0.36.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: bump version to 0.35.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: bump version to 0.33.1
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: bump version to 0.32.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0.25.2: embed-worker: use the fp16 model on CUDA (q8 is CPU-only)
EMBED_DEVICE=cuda was loading the q8 (int8) graph on the GPU, where its integer ops aren't supported by the CUDA provider — they fall back to CPU and shuffle tensors GPU↔CPU (the "171 Memcpy nodes" warning), with no real speedup. On CUDA the worker now loads model_fp16.onnx, which runs fully on the GPU (no memcpy, no warning, genuinely fast). - fp16 has the same float32 in/out as q8 (drop-in — no embed() change), and its vectors match q8 to ~0.008 cosine distance, so the fp16 index stays aligned with the browser's q8 query. - gsplat image bakes both graphs (q8 + fp16); CPU keeps q8 (faster there); a missing fp16 or CUDA provider falls back to q8 gracefully. Verified: q8↔fp16 same-image distance 0.008; cpu→q8; cuda-without-provider → warn + q8 fallback (no crash). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>