Skip to content

Releases: Dim145/FigureCollector

0.45.3 — Bug fixes

Choose a tag to compare

@Dim145 Dim145 released this 04 Jul 12:07

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 g keyboard-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 cmov 0.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-nativejwt-simple).

Full changelog: 0.45.2...0.45.3

0.45.2 — Security & NSFW fixes

Choose a tag to compare

@Dim145 Dim145 released this 03 Jul 20:33

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_url is now validated to http(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 at file:// or internal addresses once visual search is enabled.
  • PDF parsing crash — RUSTSEC-2026-0187. lopdf bumped to 0.42.0 (via the direct dependency + pdf-extract 0.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

Choose a tag to compare

@Dim145 Dim145 released this 27 Jun 21:43

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_allowed data) and, when the proxy reports it, from the proxy's /product status field. 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_TOKEN is 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/tasks rebuilt 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 new ci.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_id made nullable (0.43.0)
  • owned_provenance (acquisition_source / acquired_from / archive_reason on owned_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_TOKEN on the server equal to EMBED_WORKER_TOKEN on the worker. Unset = the feature stays off (the internal fetch route fail-closes). nginx also 404s /api/internal/* externally.

Full changelog: 0.40.1...0.45.0

0.40.1

Choose a tag to compare

@Dim145 Dim145 released this 24 Jun 23:18

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 $ USD conversion 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 tolerates pdf-extract's doubled-bold glyphs (116699,,5500169,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_paid adds the nullable preorders.balance_paid_at column (idempotent ADD COLUMN IF NOT EXISTS).

Full changelog: 0.40.0...0.40.1

chore: bump version to 0.40.0

Choose a tag to compare

@Dim145 Dim145 released this 23 Jun 21:02
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

chore: bump version to 0.36.0

Choose a tag to compare

@Dim145 Dim145 released this 19 Jun 19:17
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

chore: bump version to 0.35.0

Choose a tag to compare

@Dim145 Dim145 released this 19 Jun 16:47
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

chore: bump version to 0.33.1

Choose a tag to compare

@Dim145 Dim145 released this 19 Jun 15:15
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

chore: bump version to 0.32.0

Choose a tag to compare

@Dim145 Dim145 released this 18 Jun 20:50
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)

Choose a tag to compare

@Dim145 Dim145 released this 15 Jun 23:03
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>