chore(release): 2.0.0 [skip ci]

# [2.0.0](https://github.com/snapotter-hq/snapotter/compare/v1.17.2...v2.0.0) (2026-07-07)

* feat!: SnapOtter 2.0.0 ([6205525](https://github.com/snapotter-hq/snapotter/commit/620552569e1b6b163df66ee824a480e6d5750abb)), closes [#254](https://github.com/snapotter-hq/snapotter/issues/254) [#261](https://github.com/snapotter-hq/snapotter/issues/261)
* feat(db)!: SnapOtter 2.0 phase 1 foundation: postgres, migrator, compose stack ([#216](https://github.com/snapotter-hq/snapotter/issues/216)) ([1c724d5](https://github.com/snapotter-hq/snapotter/commit/1c724d5d21659be24423a22c7d6737d59b3d6310))

### Bug Fixes

* adopt sharp 0.35.2+ by centralizing the FormatEnum key type ([#362](https://github.com/snapotter-hq/snapotter/issues/362)) ([9052da2](https://github.com/snapotter-hq/snapotter/commit/9052da27f3a298f950a9949a0e0929e72b569b04))
* **ai-bundles:** lock the numpy-1.x ABI closure so the OCR bundle can't strand scipy ([67c5566](https://github.com/snapotter-hq/snapotter/commit/67c55669d610801e8cd07e4d65c5642a08fc0b07))
* **ai-bundles:** lock the numpy-1.x ABI closure so the OCR bundle can't strand scipy ([#437](https://github.com/snapotter-hq/snapotter/issues/437)) ([fd39f66](https://github.com/snapotter-hq/snapotter/commit/fd39f66f464e21836e8cfd72ab38f3d5c6d3528f))
* **ai-bundles:** repair bundle build + publish pipeline (deepsafe repo, CPU provider, manifest) ([3b50bcd](https://github.com/snapotter-hq/snapotter/commit/3b50bcdc5ccb630998c60003d5eddd9803780013))
* **ai:** broaden SSRF pre-scan regex to cover srcset, poster, formaction, [@import](https://github.com/import) ([5397f9b](https://github.com/snapotter-hq/snapotter/commit/5397f9b21c5b8566fed355f13d62378035456981))
* **ai:** detect a paddle-only GPU so OCR uses PaddleOCR-GPU not Tesseract ([#439](https://github.com/snapotter-hq/snapotter/issues/439)) ([7cd514d](https://github.com/snapotter-hq/snapotter/commit/7cd514dd8cdee28b9f600722f43ba63bcdbe2928))
* **ai:** enforce the feature gate on the per-request fallback path ([#331](https://github.com/snapotter-hq/snapotter/issues/331)) ([7a70aff](https://github.com/snapotter-hq/snapotter/commit/7a70affac51153cf0bd6432a7d9bdc4e6c76bc4b)), closes [#327](https://github.com/snapotter-hq/snapotter/issues/327)
* **ai:** gate AI tools on per-framework GPU detection, not a shared boolean ([#445](https://github.com/snapotter-hq/snapotter/issues/445)) ([36dde9a](https://github.com/snapotter-hq/snapotter/commit/36dde9ad8784867270bbfe766650b4c4515dbcb9))
* **ai:** pin protobuf<5 on arm64 so mediapipe face landmarks work ([#417](https://github.com/snapotter-hq/snapotter/issues/417)) ([2c2fb65](https://github.com/snapotter-hq/snapotter/commit/2c2fb65fcaaa835ca589e59255366819cece5fdf))
* **ai:** pin rembg to 2.0.69 to keep numpy<2 compatibility ([3726335](https://github.com/snapotter-hq/snapotter/commit/3726335063984bd572a14eea36c532bda74bc1d6))
* **ai:** surface actionable fix for libGL.so.1 missing on headless installs ([7c70c60](https://github.com/snapotter-hq/snapotter/commit/7c70c60b9e3e0912b1f8be6acf87f378f8b9c080))
* **ai:** update arm64 bundle sha256/size after protobuf<5 rebuild ([#421](https://github.com/snapotter-hq/snapotter/issues/421)) ([2a36b3d](https://github.com/snapotter-hq/snapotter/commit/2a36b3dfe0e4388f7bd1c2a8183f7d87e57dc144)), closes [#417](https://github.com/snapotter-hq/snapotter/issues/417)
* allow reinstall of AI bundles with broken model files ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([27a56c7](https://github.com/snapotter-hq/snapotter/commit/27a56c774bfd8f920355a1f5b70553639ad165df))
* always show NonNativePreview for non-native formats, even after processing ([abaae18](https://github.com/snapotter-hq/snapotter/commit/abaae18669a281a03aeafebec764f9992659c862))
* **analytics:** harden analytics opt-out and feedback surfaces ([#423](https://github.com/snapotter-hq/snapotter/issues/423)) ([23efce9](https://github.com/snapotter-hq/snapotter/commit/23efce9df0f8cedabd9aab033b896f7f3dffc768))
* **api:** batch user-files delete to eliminate N+1 queries ([e2c5714](https://github.com/snapotter-hq/snapotter/commit/e2c57144dd1f8f9a7de629228967725861cb50c7))
* **api:** decode RAW via LibRaw first so DNG processes at full resolution ([#289](https://github.com/snapotter-hq/snapotter/issues/289)) ([#290](https://github.com/snapotter-hq/snapotter/issues/290)) ([3d9ff1e](https://github.com/snapotter-hq/snapotter/commit/3d9ff1e0d2c60a88fdba03c11f45e1422eacf84d))
* **api:** drop app-logger import from media-input; update stale errors mock ([c483897](https://github.com/snapotter-hq/snapotter/commit/c483897452d0769a3a1fbca8758fdc7eaf1b3cc0))
* **api:** fix batch user-files delete recursive CTE query ([82991b6](https://github.com/snapotter-hq/snapotter/commit/82991b6a412f84dd2d1d7295379da3cb189d1440))
* **api:** isolate the factory validation scratch dir from the worker's ([7a205ee](https://github.com/snapotter-hq/snapotter/commit/7a205eeb1239f6fa0d1e3c84c744325b9e953237))
* **api:** log only genuine processing faults at error level ([965501a](https://github.com/snapotter-hq/snapotter/commit/965501aef95fff1f5924e030434ea2688c4f0e8c))
* **api:** make OpenAPI spec ASCII-only so Schemathesis can load it ([#344](https://github.com/snapotter-hq/snapotter/issues/344)) ([c2ae334](https://github.com/snapotter-hq/snapotter/commit/c2ae334c81e18561931247db8f8e68ab08c1ef74))
* **api:** narrow friendlyError matching to avoid collapsing valid messages ([6220885](https://github.com/snapotter-hq/snapotter/commit/6220885e0cfd61b57186136aba174f0042dc6457))
* **api:** propagate lenient structural-validation flag to batch + pipeline ([e52e0bb](https://github.com/snapotter-hq/snapotter/commit/e52e0bb3d53bed90a58d0daca15c9aef633d7d02)), closes [#244](https://github.com/snapotter-hq/snapotter/issues/244)
* **api:** reject non-PDF inputs in pdf-to-image ([37b9c6d](https://github.com/snapotter-hq/snapotter/commit/37b9c6d7bf0d38ffc48febc324e96288b5f59fd4))
* **api:** respect RATE_LIMIT_PER_MIN for tool routes ([#272](https://github.com/snapotter-hq/snapotter/issues/272)) ([ce02ce1](https://github.com/snapotter-hq/snapotter/commit/ce02ce13486989d51314d2afabbdcaf8e0d2a9f9)), closes [#280](https://github.com/snapotter-hq/snapotter/issues/280)
* **api:** return user-safe processing errors, keep raw stderr in logs ([4af4bfa](https://github.com/snapotter-hq/snapotter/commit/4af4bfa8eba5ba059e804af33581ada7250a7d1c))
* **api:** section override for backwards-compat alias routes (adjust-colors) ([fc205c7](https://github.com/snapotter-hq/snapotter/commit/fc205c7428f3d27d542065a70c4a948e4e9742fd))
* **api:** stop leaking raw ffprobe stderr in media validation errors ([3fc4149](https://github.com/snapotter-hq/snapotter/commit/3fc41491437a2968b2ebfd79447d59e68da7ec1d))
* **api:** support sharp 0.35 types ([6f85b3d](https://github.com/snapotter-hq/snapotter/commit/6f85b3d12acac73caf747313511c49c7bdc6c257))
* **api:** wrap role rename and delete in transactions ([b564932](https://github.com/snapotter-hq/snapotter/commit/b5649320833ad0c5d6c57c887ef8587d74564dcb))
* apply processedFileName fallback everywhere processedFilename is used ([857aa75](https://github.com/snapotter-hq/snapotter/commit/857aa75562816dbcc0827eda93125605c495af7c))
* **audio:** low-samplerate ogg encode + post-2.0 QA hygiene ([19d9ed1](https://github.com/snapotter-hq/snapotter/commit/19d9ed181ae0051e0df6a01585036628dd31700a))
* **benchmark:** use section-prefixed tool URLs for 2.0 route scheme ([76fc695](https://github.com/snapotter-hq/snapotter/commit/76fc695233eae54c803ae1730cefb9acd161db45))
* build script venv handling and lint fixes ([b1e94bd](https://github.com/snapotter-hq/snapotter/commit/b1e94bd98851d3cc6da57b343ac8d2528dfda890))
* cache useSyncExternalStore snapshot to prevent infinite re-render ([f68fcb8](https://github.com/snapotter-hq/snapotter/commit/f68fcb8ca6724be0ca83a42593192608cde1a784))
* **ci:** address spec review findings in verify-bundle.sh ([4b5b351](https://github.com/snapotter-hq/snapotter/commit/4b5b35186d925f95566b7d36c9d3994255fc95e2))
* **ci:** deploy landing from dist, not the stale Next.js out path ([#240](https://github.com/snapotter-hq/snapotter/issues/240)) ([44bfca1](https://github.com/snapotter-hq/snapotter/commit/44bfca105fc4bfa1d5d2bfc0da861ed4e0a1e496))
* **ci:** grant ai-bundles reusable call its required token scopes ([03c1a5e](https://github.com/snapotter-hq/snapotter/commit/03c1a5e36f9dd7f904882b7cb19fc27006a61f5d))
* **ci:** harden smoke tests against set -e and fix parameter issues ([efac88c](https://github.com/snapotter-hq/snapotter/commit/efac88c20517c22b3a18a9cb227350cd10bdd3c1))
* **ci:** resolve pre-existing failures making main red ([#250](https://github.com/snapotter-hq/snapotter/issues/250)) ([622c9f9](https://github.com/snapotter-hq/snapotter/commit/622c9f98a5772eae05343407b8408cd7d7539ef9)), closes [#249](https://github.com/snapotter-hq/snapotter/issues/249) [246/#248](https://github.com/snapotter-hq/snapotter/issues/248)
* **ci:** revert rembg to 2.0.62 (2.0.75 requires numpy>=2.3) ([3b8d529](https://github.com/snapotter-hq/snapotter/commit/3b8d529b4422deb4d0782a5e4d536328563afd1e))
* clean file info cards for non-native video/media formats on tool page ([511e941](https://github.com/snapotter-hq/snapotter/commit/511e941da0516e27237621be1eeaf6beb64b2d89))
* clear file store when navigating between tools ([f32b3bd](https://github.com/snapotter-hq/snapotter/commit/f32b3bd51f2107040c081d0d9bee5ac5b0450157))
* correct SAML idpCert property name for @node-saml/node-saml v5 ([b9dac59](https://github.com/snapotter-hq/snapotter/commit/b9dac597362e2fbdd90447bfd7889f85dddfff90))
* critical first-login soft-lock in usage survey overlay ([#392](https://github.com/snapotter-hq/snapotter/issues/392)) ([ca076f9](https://github.com/snapotter-hq/snapotter/commit/ca076f91fde252fd98d3014a260d8ae7534481f0))
* **deps:** close js-yaml DoS alert + document rembg non-reachability ([#286](https://github.com/snapotter-hq/snapotter/issues/286)) ([5d5117a](https://github.com/snapotter-hq/snapotter/commit/5d5117acf729d3b2c00119eede9ba20f0aa17a28))
* **deps:** drop undici override (broke jsdom@29) ([5662532](https://github.com/snapotter-hq/snapotter/commit/56625325013b6c8ac47e159a4d517f7eef29a056))
* **deps:** patch Dependabot security alerts ([8792080](https://github.com/snapotter-hq/snapotter/commit/87920809820cb0179c029ccb7234370431abff67))
* **doc-engine:** treat qpdf exit code 3 (warnings) as success, not failure ([2a2151d](https://github.com/snapotter-hq/snapotter/commit/2a2151d7dd19faa1e4d43d49540729dab33a8eed))
* **docker:** copy patches/ before pnpm install so cold builds succeed ([#300](https://github.com/snapotter-hq/snapotter/issues/300)) ([f74f648](https://github.com/snapotter-hq/snapotter/commit/f74f648e47fb76a30b9fa34cd6dc84f4c0295972))
* **docker:** make storage writable under non-root/foreign UIDs (TrueNAS, OpenShift) ([#299](https://github.com/snapotter-hq/snapotter/issues/299)) ([1fec971](https://github.com/snapotter-hq/snapotter/commit/1fec97111bf4cf4620131e38651b8e114c7b0566)), closes [#230](https://github.com/snapotter-hq/snapotter/issues/230)
* **docker:** make venv bootstrap upgrade-aware with pip-freeze stamp ([39543d6](https://github.com/snapotter-hq/snapotter/commit/39543d651219d4741868ec7ebe34186aa038a914)), closes [#85](https://github.com/snapotter-hq/snapotter/issues/85)
* **docker:** patch OS + pip image CVEs, document accepted Trivy residuals ([#288](https://github.com/snapotter-hq/snapotter/issues/288)) ([c203267](https://github.com/snapotter-hq/snapotter/commit/c203267866aa87994de80d2214f70deff72b7b5f))
* **docker:** repair copied AI venv paths ([#390](https://github.com/snapotter-hq/snapotter/issues/390)) ([7e01d36](https://github.com/snapotter-hq/snapotter/commit/7e01d3637edec10c4b7c73cd6c9d54c6414972f6)), closes [#127](https://github.com/snapotter-hq/snapotter/issues/127) [#127](https://github.com/snapotter-hq/snapotter/issues/127)
* **docker:** restore Postgres/Redis in GPU compose stack + pause image publishing ([9b64a96](https://github.com/snapotter-hq/snapotter/commit/9b64a96bcd2e60ce8e3e051a9d2b57811e98a223))
* **e2e,landing:** robust path escaping (CodeQL) + unique file-tools card ([a6837b6](https://github.com/snapotter-hq/snapotter/commit/a6837b687a096b754367223b4472481071a450b7))
* **e2e:** disable Astro Dev Toolbar during landing e2e tests ([2927e0d](https://github.com/snapotter-hq/snapotter/commit/2927e0d4be063353abb9d23494158849ac3a191a))
* **e2e:** wait for post-login redirect before forcing navigation ([#341](https://github.com/snapotter-hq/snapotter/issues/341)) ([5b75d81](https://github.com/snapotter-hq/snapotter/commit/5b75d813b8523fd378c731de76c429fe900d9d28)), closes [#340](https://github.com/snapotter-hq/snapotter/issues/340)
* **editor:** apply layer effects + object flip, add Beta badge, repair e2e specs ([3120e67](https://github.com/snapotter-hq/snapotter/commit/3120e6708dd4e0eb39c2d3af01623e8f1e9c4473)), closes [#259](https://github.com/snapotter-hq/snapotter/issues/259)
* **editor:** capture document pixels without the zoom/pan transform ([#259](https://github.com/snapotter-hq/snapotter/issues/259)) ([81e16d7](https://github.com/snapotter-hq/snapotter/commit/81e16d7ce6648e3d7acace0b1915fd42774d1096)), closes [#258](https://github.com/snapotter-hq/snapotter/issues/258)
* **editor:** fill canvas viewport, fix black rulers, add resizable panel ([#258](https://github.com/snapotter-hq/snapotter/issues/258)) ([063a2e4](https://github.com/snapotter-hq/snapotter/commit/063a2e47e298e41d1115f4e6e92a96922a607ce6))
* enforce file type filtering using tool's acceptedInputs ([adfa532](https://github.com/snapotter-hq/snapotter/commit/adfa53246ae228eebe2fdd071f23a83400f1296c))
* **enterprise:** SCIM token generation, GDPR job cancellation, MFA replay, config redaction, encryption validation, SCIM rate limit ([29dd675](https://github.com/snapotter-hq/snapotter/commit/29dd675f4262ac0380df3113ae140b4fc7330d21))
* **enterprise:** ship enterprise package in prod image + S3, analytics, tracing, queue fixes ([#342](https://github.com/snapotter-hq/snapotter/issues/342)) ([8f4235d](https://github.com/snapotter-hq/snapotter/commit/8f4235d2c664337f3b970b1be5acc6f92474aeb6)), closes [#82](https://github.com/snapotter-hq/snapotter/issues/82)
* fetch settings on home page mount so tools are visible ([cf543f6](https://github.com/snapotter-hq/snapotter/commit/cf543f6976166b179deb1e5c0fa993bb9e037f0e))
* file library upload accepts all file types, not just images ([6bcee1e](https://github.com/snapotter-hq/snapotter/commit/6bcee1e0739daaad8c66abcc4a4e1bc00bb40735))
* **files:** record the source tool in toolChain on Save to Files ([#435](https://github.com/snapotter-hq/snapotter/issues/435)) ([47a60e7](https://github.com/snapotter-hq/snapotter/commit/47a60e7fad229a9bb9c8e4f33f152cacb3f3dfb4))
* first-run QA sweep of the single-container image ([#413](https://github.com/snapotter-hq/snapotter/issues/413)) ([bf417a5](https://github.com/snapotter-hq/snapotter/commit/bf417a509e529ee6b39d2d5a13a308172b4d08aa))
* GPU deployment robustness (6 fixes from end-to-end testing on an RTX 4070) ([#334](https://github.com/snapotter-hq/snapotter/issues/334)) ([35e18d8](https://github.com/snapotter-hq/snapotter/commit/35e18d8b79861b4aba46d4cb022be868d4d3e757))
* grey out incompatible files in library instead of hiding them ([3a5d55c](https://github.com/snapotter-hq/snapotter/commit/3a5d55cf268301df158163acbeaeaf50c6625a10))
* handle non-image modalities across uploads, previews, and filenames ([#255](https://github.com/snapotter-hq/snapotter/issues/255)) ([8eee17a](https://github.com/snapotter-hq/snapotter/commit/8eee17aeea41577a55b30ead97ca36224b387c04))
* harden against three production Sentry crashes ([#328](https://github.com/snapotter-hq/snapotter/issues/328)) ([8952e9b](https://github.com/snapotter-hq/snapotter/commit/8952e9ba475000da9d2d8e0959c63f3cf2b4506e))
* harden Docker image and async job responses ([f3342a1](https://github.com/snapotter-hq/snapotter/commit/f3342a1e571db5a12f5d8f659903ffe590fa2044))
* harden install queue/dispatcher lifecycle and repair review-sweep regressions ([#395](https://github.com/snapotter-hq/snapotter/issues/395)) ([b4375e5](https://github.com/snapotter-hq/snapotter/commit/b4375e558dfc5ccf34ee6736b886e90f662b1688)), closes [#388](https://github.com/snapotter-hq/snapotter/issues/388) [#390](https://github.com/snapotter-hq/snapotter/issues/390) [#391](https://github.com/snapotter-hq/snapotter/issues/391) [#392](https://github.com/snapotter-hq/snapotter/issues/392) [#393](https://github.com/snapotter-hq/snapotter/issues/393) [#394](https://github.com/snapotter-hq/snapotter/issues/394) [#392](https://github.com/snapotter-hq/snapotter/issues/392)
* **i18n:** complete and correct Italian translation ([#231](https://github.com/snapotter-hq/snapotter/issues/231)) ([#298](https://github.com/snapotter-hq/snapotter/issues/298)) ([c0a8b36](https://github.com/snapotter-hq/snapotter/commit/c0a8b36dcbf56f49fa2e58c8d040171e9e6b63e3))
* **i18n:** complete the Italian feedback translations ([#426](https://github.com/snapotter-hq/snapotter/issues/426)) ([3ae48cc](https://github.com/snapotter-hq/snapotter/commit/3ae48cc76ad4021854a805fcea486f58b045f595)), closes [#425](https://github.com/snapotter-hq/snapotter/issues/425)
* **i18n:** complete the Italian translation update ([#438](https://github.com/snapotter-hq/snapotter/issues/438)) ([#450](https://github.com/snapotter-hq/snapotter/issues/450)) ([0fafeb2](https://github.com/snapotter-hq/snapotter/commit/0fafeb26766ed49014d13b649f9b43ffc2fffca5))
* **i18n:** restore accents in Italian loading-message arrays ([#322](https://github.com/snapotter-hq/snapotter/issues/322)) ([29fcc87](https://github.com/snapotter-hq/snapotter/commit/29fcc8770887b981e73a17e43bea79a2f13da1e5)), closes [#298](https://github.com/snapotter-hq/snapotter/issues/298)
* **i18n:** translate Arabic (ar) UI strings ([#314](https://github.com/snapotter-hq/snapotter/issues/314)) ([ab37505](https://github.com/snapotter-hq/snapotter/commit/ab37505e681602d67ad447e3ad49588e905d48d9))
* **i18n:** translate Brazilian Portuguese (pt-BR) UI strings ([#307](https://github.com/snapotter-hq/snapotter/issues/307)) ([3900350](https://github.com/snapotter-hq/snapotter/commit/3900350ad56d63e9b8ed119539c94c54faf971e0))
* **i18n:** translate Dutch (nl) UI strings ([#309](https://github.com/snapotter-hq/snapotter/issues/309)) ([d036ff6](https://github.com/snapotter-hq/snapotter/commit/d036ff6d44fa9fd8025d3c38b382127066b248c3))
* **i18n:** translate French (fr) UI strings ([#306](https://github.com/snapotter-hq/snapotter/issues/306)) ([fe5c7c8](https://github.com/snapotter-hq/snapotter/commit/fe5c7c8c8667a24cebcd0af8b68f031ddc01ef15))
* **i18n:** translate German (de) UI strings ([#308](https://github.com/snapotter-hq/snapotter/issues/308)) ([4de24b8](https://github.com/snapotter-hq/snapotter/commit/4de24b8c9e4e703b4fd51965ccb9387e1e09fa59))
* **i18n:** translate Hindi (hi) UI strings ([#316](https://github.com/snapotter-hq/snapotter/issues/316)) ([00c89e4](https://github.com/snapotter-hq/snapotter/commit/00c89e4ae9060c1cc4100340f5db223bfd768e0f))
* **i18n:** translate Indonesian (id) UI strings ([#318](https://github.com/snapotter-hq/snapotter/issues/318)) ([8a8a4f9](https://github.com/snapotter-hq/snapotter/commit/8a8a4f99a431ec10ccfdbb472672e976b5b86db2))
* **i18n:** translate Japanese (ja) UI strings ([#304](https://github.com/snapotter-hq/snapotter/issues/304)) ([d8b037c](https://github.com/snapotter-hq/snapotter/commit/d8b037c8c6e8c6cde9c4c6900c1d5689143f5d5d))
* **i18n:** translate Korean (ko) UI strings ([#305](https://github.com/snapotter-hq/snapotter/issues/305)) ([e7b412f](https://github.com/snapotter-hq/snapotter/commit/e7b412fc097d6c745037781e7478414a33d6db25))
* **i18n:** translate Polish (pl) UI strings ([#312](https://github.com/snapotter-hq/snapotter/issues/312)) ([7ce9c64](https://github.com/snapotter-hq/snapotter/commit/7ce9c64b50c5b1fa1eb153c8635384eb5ae0e03b))
* **i18n:** translate Russian (ru) UI strings ([#311](https://github.com/snapotter-hq/snapotter/issues/311)) ([eb9a14a](https://github.com/snapotter-hq/snapotter/commit/eb9a14a226824047cdf00ac94ef647e2bfdcf23a))
* **i18n:** translate Simplified Chinese (zh-CN) UI strings ([#302](https://github.com/snapotter-hq/snapotter/issues/302)) ([26d8a06](https://github.com/snapotter-hq/snapotter/commit/26d8a0685c6b2a216fd72b9431d18543abfa89ee))
* **i18n:** translate Spanish (es) UI strings ([#301](https://github.com/snapotter-hq/snapotter/issues/301)) ([b3ff8ac](https://github.com/snapotter-hq/snapotter/commit/b3ff8accec5494d2fe97a27355257b3c5fa2f91d))
* **i18n:** translate Swedish (sv) UI strings ([#310](https://github.com/snapotter-hq/snapotter/issues/310)) ([c4ce5f9](https://github.com/snapotter-hq/snapotter/commit/c4ce5f96dfe6daf8e560de34cd748b1795ed12ff))
* **i18n:** translate Thai (th) UI strings ([#319](https://github.com/snapotter-hq/snapotter/issues/319)) ([5a6368d](https://github.com/snapotter-hq/snapotter/commit/5a6368db89df5419885b3f8dc568eeaa16cd8206))
* **i18n:** translate Traditional Chinese (zh-TW) UI strings ([#303](https://github.com/snapotter-hq/snapotter/issues/303)) ([de4d2ed](https://github.com/snapotter-hq/snapotter/commit/de4d2ed166d858530dcbbb0634ddcb9c7536ab07))
* **i18n:** translate Turkish (tr) UI strings ([#315](https://github.com/snapotter-hq/snapotter/issues/315)) ([8c1c2c3](https://github.com/snapotter-hq/snapotter/commit/8c1c2c310eac95d5a75fcfd563b9026dba9a4fae))
* **i18n:** translate Ukrainian (uk) UI strings ([#313](https://github.com/snapotter-hq/snapotter/issues/313)) ([6ee1b0f](https://github.com/snapotter-hq/snapotter/commit/6ee1b0f7a1b58dd7ae113fc4268067e0ac1e0b3c))
* **i18n:** translate Vietnamese (vi) UI strings ([#317](https://github.com/snapotter-hq/snapotter/issues/317)) ([4702721](https://github.com/snapotter-hq/snapotter/commit/470272169d947e27ff826e2c0e24e1553eda0543))
* **image-engine:** support sharp 0.35 types ([2137be4](https://github.com/snapotter-hq/snapotter/commit/2137be479e1a23e163587acd1609e77058e9e134))
* **jobs:** pre-warm QueueEvents to kill first-sync-wait flake ([#285](https://github.com/snapotter-hq/snapotter/issues/285)) ([dba8a85](https://github.com/snapotter-hq/snapotter/commit/dba8a85a8013231945741a8fabd09ed86db0d963))
* **jobs:** strip internal paths from all worker SSE error frames ([fc718c1](https://github.com/snapotter-hq/snapotter/commit/fc718c168487de1213c978797c3fc84288f26513))
* **landing:** add www redirect, noindex JS chunks, and website badge ([47b6984](https://github.com/snapotter-hq/snapotter/commit/47b6984be0c8d8de07e0770a34d61a9795b71eaf))
* **lint:** biome-format tool-factory and json-xml to green apps/api lint ([#252](https://github.com/snapotter-hq/snapotter/issues/252)) ([7865339](https://github.com/snapotter-hq/snapotter/commit/7865339fc8c3b8696af5919212ddba4120c07f23)), closes [#251](https://github.com/snapotter-hq/snapotter/issues/251)
* **lint:** clear remaining biome errors (unused code, optional chains, non-null assertions, effect deps) ([19dc6ba](https://github.com/snapotter-hq/snapotter/commit/19dc6ba554a05f531db01f23ce3e71297f651f81))
* **lint:** make husky hook executable; rename backend useS3 to isS3Enabled (clears 17 false-positive useHookAtTopLevel) ([7561f2a](https://github.com/snapotter-hq/snapotter/commit/7561f2a8c3a92c412f0d38b9f1323aa8bcfcf4a4))
* **lint:** resolve [#280](https://github.com/snapotter-hq/snapotter/issues/280) Lint failures (route formatting + landing import sort) ([6e1b9cd](https://github.com/snapotter-hq/snapotter/commit/6e1b9cd3cc3b33b18724eb071f3ad4023ab1ee80))
* make search bar full-width to align with tabs and grid ([207c1c3](https://github.com/snapotter-hq/snapotter/commit/207c1c348be5af23c793a96bf07b9f7b7c26ce31))
* **media:** encode gif-to-video WebM as yuv420p ([e96c314](https://github.com/snapotter-hq/snapotter/commit/e96c314ab9b049c3b01d49ff2622d2a351962cd9))
* **migrator:** correct and harden the 1.x to 2.0 SQLite import ([#434](https://github.com/snapotter-hq/snapotter/issues/434)) ([dadf766](https://github.com/snapotter-hq/snapotter/commit/dadf76689933faa8208de9730525409e2497518f))
* **nightly:** de-flake matrix timeouts, exclude browser tool from fuzz ([#349](https://github.com/snapotter-hq/snapotter/issues/349)) ([bbad953](https://github.com/snapotter-hq/snapotter/commit/bbad953e79a132007490c17dab2b774c4b8ae697)), closes [#347](https://github.com/snapotter-hq/snapotter/issues/347)
* **nightly:** qpdf in test image, NUL-byte settings, AI sub-path fuzz exclude ([#348](https://github.com/snapotter-hq/snapotter/issues/348)) ([078743d](https://github.com/snapotter-hq/snapotter/commit/078743d6b28aa4078f213cae4c39a3b99e515d8d)), closes [#346](https://github.com/snapotter-hq/snapotter/issues/346) [#346](https://github.com/snapotter-hq/snapotter/issues/346)
* **normalize-audio:** preserve source sample rate after loudnorm ([#248](https://github.com/snapotter-hq/snapotter/issues/248)) ([1548d47](https://github.com/snapotter-hq/snapotter/commit/1548d475ca3d1ace0f14d24ecc5e9a13ca5770a2))
* offline CodeFormer face-enhance (ship RealESRGAN_x2plus in upscale-enhance bundle) ([#433](https://github.com/snapotter-hq/snapotter/issues/433)) ([cf884b5](https://github.com/snapotter-hq/snapotter/commit/cf884b52cdf4e8852e0cd24215b22ed2220230da))
* **passport-photo:** require the face-detection bundle, not just background-removal ([#329](https://github.com/snapotter-hq/snapotter/issues/329)) ([32c1192](https://github.com/snapotter-hq/snapotter/commit/32c1192d635898012af2ff14cdbd68c0acd6a3e1)), closes [#327](https://github.com/snapotter-hq/snapotter/issues/327) [#327](https://github.com/snapotter-hq/snapotter/issues/327)
* PDF tool QA sweep - library auto-save versioning, AI fileId threading, modality polish ([#251](https://github.com/snapotter-hq/snapotter/issues/251)) ([08961fc](https://github.com/snapotter-hq/snapotter/commit/08961fcc8941bada2608e386bfa6d6b12e996f35))
* post-2.0 audit bug fixes (404 route, worker logging, outpaint gate, pandoc path) ([2bd3e23](https://github.com/snapotter-hq/snapotter/commit/2bd3e2302ad11b306971d0f651f8ad1ee1e9b785))
* prevent double scrollbar by locking html/body overflow ([914ff1b](https://github.com/snapotter-hq/snapotter/commit/914ff1b1aab345237f325cd152bd3ebc693bab52))
* preview generation works for processed results too ([b93dc95](https://github.com/snapotter-hq/snapotter/commit/b93dc95bcaa197cfd4b29c030a04decaa7babcf8))
* QA sweep - tool routes, security, i18n, a11y, + AI bundle install hardening ([#393](https://github.com/snapotter-hq/snapotter/issues/393)) ([b37faed](https://github.com/snapotter-hq/snapotter/commit/b37faed95fc3d2f51c78f40954fdbb5c7b94779d)), closes [hi#resolution](https://github.com/hi/issues/resolution) [hi#severity](https://github.com/hi/issues/severity)
* reassign 4 tools to correct display modes ([619f61b](https://github.com/snapotter-hq/snapotter/commit/619f61b4700c9fd3b21f90b7c9512672fae57dab))
* release-acceptance QA follow-ups (upload crash, scipy ABI conflict, rate limit, OCR fallback) ([#458](https://github.com/snapotter-hq/snapotter/issues/458)) ([60d01ab](https://github.com/snapotter-hq/snapotter/commit/60d01ab2ddfad4bf837d30369c2f39e9734cb571)), closes [#413](https://github.com/snapotter-hq/snapotter/issues/413) [#437](https://github.com/snapotter-hq/snapotter/issues/437)
* remove all legacy redirects from routes ([fd26fa3](https://github.com/snapotter-hq/snapotter/commit/fd26fa35868b75ca7fd352115396ec9b23dd4280))
* remove automatic third-party egress of user data + optional strict offline mode (OSM tiles, Scalar fonts, editor fonts, AI model downloads) ([#422](https://github.com/snapotter-hq/snapotter/issues/422)) ([6e3a14e](https://github.com/snapotter-hq/snapotter/commit/6e3a14ec6bfc15f18aef3c7aa20cde6d4823dc29))
* remove double scrollbar on home page ([ae95976](https://github.com/snapotter-hq/snapotter/commit/ae959760e3fec115021e2ada7af579ecd13f181c))
* remove duplicated 1.x migration callout in README ([#456](https://github.com/snapotter-hq/snapotter/issues/456)) ([2a899ef](https://github.com/snapotter-hq/snapotter/commit/2a899ef9041c3c637380a91e532273a3581a19d1)), closes [#448](https://github.com/snapotter-hq/snapotter/issues/448) [#454](https://github.com/snapotter-hq/snapotter/issues/454)
* remove redundant Getting Started section from home page ([287f6f1](https://github.com/snapotter-hq/snapotter/commit/287f6f15ded4b84e9d0f019522915ccac822d083))
* repair docker validation QA tooling, dispatcher crash-accounting, and image-enhancement RAW hang ([#391](https://github.com/snapotter-hq/snapotter/issues/391)) ([bd1838e](https://github.com/snapotter-hq/snapotter/commit/bd1838e40b0d11715eaf9eff6b4152a707a29b5b))
* repair URL import (DNS-pinned fetch on Node 22 + non-image modalities) ([#246](https://github.com/snapotter-hq/snapotter/issues/246)) ([8f6312c](https://github.com/snapotter-hq/snapotter/commit/8f6312c521246215ef1a27c65475aa2005e409e0))
* resolve 18 QA-discovered bugs across tools, previews, and the AI pipeline ([#242](https://github.com/snapotter-hq/snapotter/issues/242)) ([d8cf979](https://github.com/snapotter-hq/snapotter/commit/d8cf979d4ba31b802c254f7eeb5ef50b424a56b7))
* resolve 6 bugs from enterprise audit (SIEM cursor, legal hold join, SCIM role, GDPR self-purge, export OOM, quota check) ([7f62b1b](https://github.com/snapotter-hq/snapotter/commit/7f62b1bf12d2cf1baaf5586b201458eab100a111))
* resolve hardcoded /app paths and loosen mediapipe pin for native installs ([60e3ac2](https://github.com/snapotter-hq/snapotter/commit/60e3ac2210f93a350729246cf2b4bb303ab2ebc7)), closes [community-scripts/ProxmoxVE#14720](https://github.com/community-scripts/ProxmoxVE/issues/14720)
* resolve Sharp 0.35.1 and BullMQ type incompatibilities after dep bumps ([b76dc68](https://github.com/snapotter-hq/snapotter/commit/b76dc68682c664d4c6a22cf921e786d4c010b757))
* Save to Files shows green success state with checkmark after saving ([f4061fe](https://github.com/snapotter-hq/snapotter/commit/f4061fe4b0417ba896de138a791cfc869d3b33f3))
* **security:** basename-sanitize file-preview paths (CodeQL js/path-injection) ([7a3b4e6](https://github.com/snapotter-hq/snapotter/commit/7a3b4e6b3bbdee7c382bd4ad739485b37bb45f46))
* **security:** close file-preview path-injection + tighten subtitle detection ([c1cd871](https://github.com/snapotter-hq/snapotter/commit/c1cd8712f45d9defd5321f2d683cf207ee9d3740))
* **security:** close remaining high-severity CodeQL alerts ([bdadb84](https://github.com/snapotter-hq/snapotter/commit/bdadb843d8238d738e9f849f1754765f5de82411)), closes [hi#severity](https://github.com/hi/issues/severity)
* **security:** explicit per-route rate limits (CodeQL js/missing-rate-limiting) ([ae4fc1d](https://github.com/snapotter-hq/snapotter/commit/ae4fc1decf006b15a2f747cde07d4c1e35c5de13))
* **security:** harden auth and outbound fetches ([c6319cf](https://github.com/snapotter-hq/snapotter/commit/c6319cf8a9efe8745a29339613002c22f82e5393))
* **security:** harden rate limits, Redis auth, resource caps, and error sanitization ([d612264](https://github.com/snapotter-hq/snapotter/commit/d61226496b5745ff7f57ee8138009d4f81826095))
* **security:** numeric CIDR matching for IPv6 SSRF allow/deny ([f75cc32](https://github.com/snapotter-hq/snapotter/commit/f75cc328acd18b4714291400ac348058db6d28d8))
* send auth token with preview generation request ([6090688](https://github.com/snapotter-hq/snapotter/commit/609068870842629e085a77d9d5144c5102beae19))
* set a writable HOME for the app user so PaddleOCR works in non-root deployments ([#430](https://github.com/snapotter-hq/snapotter/issues/430)) ([e0dbf2a](https://github.com/snapotter-hq/snapotter/commit/e0dbf2a5c3cc9622218d31698452697957936e00))
* settings dialog and settings API correctness bugs ([8e9452e](https://github.com/snapotter-hq/snapotter/commit/8e9452e65073c500098fde040ce021e3b1c39639))
* show all tools on All tab, remove Popular and Browse sections ([b166f47](https://github.com/snapotter-hq/snapotter/commit/b166f47de515739d87a14ae408a351f81dd37c00))
* show image viewer for video-to-gif/webp results instead of broken video player ([90acd5b](https://github.com/snapotter-hq/snapotter/commit/90acd5bcd905f461f28a5b511c619d896d4a6724))
* show modality starting points in landing command center ([#387](https://github.com/snapotter-hq/snapotter/issues/387)) ([852f6ce](https://github.com/snapotter-hq/snapotter/commit/852f6cecba106eb9d000f95fc1ae9863157a5d3b))
* show tool-specific accepted formats in dropzone, remove privacy note ([5241ccd](https://github.com/snapotter-hq/snapotter/commit/5241ccd1247bda2d9e634576354f3b14a4077c63))
* sort enterprise exports for Biome lint compliance ([3b7f44e](https://github.com/snapotter-hq/snapotter/commit/3b7f44e50e450bff62560b9f21cb12330b0b2b82))
* stamp SnapOtter as Producer on generated PDFs ([#416](https://github.com/snapotter-hq/snapotter/issues/416)) ([8b3f1e6](https://github.com/snapotter-hq/snapotter/commit/8b3f1e6884361ef080c0165059bd8fdb4a14fd79))
* sync demo theme with app ([f6f7b5a](https://github.com/snapotter-hq/snapotter/commit/f6f7b5a4bc2867f680441a91a9af9e1bd148edf4))
* test server registration gaps, Redis subscriber cleanup, atomic settings upsert ([954cfb0](https://github.com/snapotter-hq/snapotter/commit/954cfb01a657ec49293a4e10e72e23eb69e4d9b2))
* **test:** align analytics-env test with ANALYTICS_ENABLED=true default ([96764ec](https://github.com/snapotter-hq/snapotter/commit/96764ec375189ebec396d0397b116407bfd75e05))
* **test:** mock db/index.js in unit tests that import API modules ([5b3b3c7](https://github.com/snapotter-hq/snapotter/commit/5b3b3c76329d62636c886dfa798b9e14acd7cc90))
* **test:** repair integration suite after analytics column/endpoint removal ([#340](https://github.com/snapotter-hq/snapotter/issues/340)) ([6917a8b](https://github.com/snapotter-hq/snapotter/commit/6917a8b0c7864fc9b244ecda23dcdbcbf02f9733)), closes [#336](https://github.com/snapotter-hq/snapotter/issues/336)
* **test:** resolve CI failures from the overhaul ([34b006d](https://github.com/snapotter-hq/snapotter/commit/34b006ded772b96d7b4336e5ffcc67e1039253c3))
* **tests:** section-prefix tool API URLs across overhauled suite ([d4dc2ea](https://github.com/snapotter-hq/snapotter/commit/d4dc2eae5db66b098d8a4e735ab61053ddb50635)), closes [#280](https://github.com/snapotter-hq/snapotter/issues/280)
* **test:** update import paths for cleanup.test.ts after move to integration ([78679c5](https://github.com/snapotter-hq/snapotter/commit/78679c57f46d11d89dcb384373a63e28e1a75635))
* **tools:** honest content-type for edit-metadata pass-through ([#350](https://github.com/snapotter-hq/snapotter/issues/350)) ([88af8d4](https://github.com/snapotter-hq/snapotter/commit/88af8d46fb001dd019de54e48dd7c73c5feaea73))
* **tools:** surface chars count in pdf-to-text result payload ([3c44335](https://github.com/snapotter-hq/snapotter/commit/3c4433583b836e53ee2a35b79c8d9be07760992e))
* top nav respects dark mode theme ([43b1901](https://github.com/snapotter-hq/snapotter/commit/43b190134e8858301fa3bffd1882260d6928c441))
* **ui:** constrain preview dropzone height in pipeline builder ([931e15a](https://github.com/snapotter-hq/snapotter/commit/931e15a6bd04fc84d236b41dbbd7df0feefe29a9))
* **ui:** show repair UI when AI bundle models are broken ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([edea82b](https://github.com/snapotter-hq/snapotter/commit/edea82ba27cd92aa5188144e525f9889b6ba1b9d))
* update privacy policy to reference PostgreSQL instead of SQLite ([5af1ac4](https://github.com/snapotter-hq/snapotter/commit/5af1ac4dcf0c8ff17bdcc0efc6c179afc8543168))
* use media-player for all video/audio tools that had no-comparison or side-by-side ([69300b5](https://github.com/snapotter-hq/snapotter/commit/69300b5c83f43ebde213473f66d9f255e33cf9dc))
* use processedFileName fallback for non-native format detection after processing ([14ded6f](https://github.com/snapotter-hq/snapotter/commit/14ded6fbd0babb43de8a544527bb2293b9d83b2d))
* validate non-image inputs by modality (batch + pipeline) ([#244](https://github.com/snapotter-hq/snapotter/issues/244)) ([03e7123](https://github.com/snapotter-hq/snapotter/commit/03e71236f93853e28d7ad8428fe8a9b918849773))
* **web:** add modality to fuse search keys, merge docs+files in fullscreen grid ([3114323](https://github.com/snapotter-hq/snapotter/commit/3114323d07a941cfcb261bc245250a8f3f6e8222))
* **web:** point tool keyboard shortcuts at section routes ([0689ae5](https://github.com/snapotter-hq/snapotter/commit/0689ae554fa353a231f01e4dffd3ac362afcb3ba))
* **web:** resolve feature install status sync and mutual exclusivity ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([492da82](https://github.com/snapotter-hq/snapotter/commit/492da820f8ce298addd3038dad2f55e91cdb12bd))
* **web:** restore preview panel rendering for all file types ([1181b1f](https://github.com/snapotter-hq/snapotter/commit/1181b1fe22c7f5a998f8954f9e02a184a3513cf8))
* **web:** show modality thumbnails for non-image files in the strip ([#245](https://github.com/snapotter-hq/snapotter/issues/245)) ([aa3ae6e](https://github.com/snapotter-hq/snapotter/commit/aa3ae6ec915821d664cef0c1537e2b64d9a6fcee))
* **web:** update dropzone to accept all file types, not just images ([b8b6b0a](https://github.com/snapotter-hq/snapotter/commit/b8b6b0a44ada1670e4e41bcf6cd22f713d14c512))
* **web:** wrap modality tabs to prevent overflow in narrow sidebar ([dab31d6](https://github.com/snapotter-hq/snapotter/commit/dab31d6e32c7eee95199d7a686d507a98d58138f))

### Features

* add a Keep it free sponsor button to the top nav ([#427](https://github.com/snapotter-hq/snapotter/issues/427)) ([7b04317](https://github.com/snapotter-hq/snapotter/commit/7b04317ed20e062c273fe60a19cdcaac2b50e651))
* add AES-256-GCM encryption at rest for sensitive settings ([2520cdd](https://github.com/snapotter-hq/snapotter/commit/2520cdd556c8a5946b4eb6426aebc8811944e8d9))
* add audio waveform visualization with wavesurfer.js ([d8a8e05](https://github.com/snapotter-hq/snapotter/commit/d8a8e055906eeab9d1f9a048c4f8d5517cff8f80))
* add backup status tracking endpoints ([2aea351](https://github.com/snapotter-hq/snapotter/commit/2aea351f70cfd171befad164bc553e7feb998884))
* add bundle build script for CI ([52b9405](https://github.com/snapotter-hq/snapotter/commit/52b940585afa1788119dc50f6d44e98f32192ad3))
* add CI workflow for building and publishing AI bundles ([7dabfe2](https://github.com/snapotter-hq/snapotter/commit/7dabfe293dd171bb7b7ec6909ced85b178e67961))
* add Cmd+Enter (process) and Cmd+S (download) keyboard shortcuts ([7c9ca85](https://github.com/snapotter-hq/snapotter/commit/7c9ca85952bc155580becc8f95125482875a3ed5))
* add enterprise Phase 1-4 feature flags and new permissions ([86d6f50](https://github.com/snapotter-hq/snapotter/commit/86d6f50ea6696032bed8f24ba0fd58fe54af5887))
* add full-width dropzone state and tool branding to tool page ([f2ac057](https://github.com/snapotter-hq/snapotter/commit/f2ac05747e1f3ffde4f2e3b3bf321237ef699e85))
* add GET /api/v1/tools/popular endpoint ([1107005](https://github.com/snapotter-hq/snapotter/commit/110700520cfaf4c70e54ff11e7cdee7f7cf50f66))
* add landing tool command center ([#386](https://github.com/snapotter-hq/snapotter/issues/386)) ([3b1d484](https://github.com/snapotter-hq/snapotter/commit/3b1d484b4d4cc9e9da843ceeb442c6dbf7c8066c))
* add OpenTelemetry distributed tracing (enterprise) ([#232](https://github.com/snapotter-hq/snapotter/issues/232)) ([3fb8164](https://github.com/snapotter-hq/snapotter/commit/3fb8164fa539ef952fddcef89bcec01097db991e))
* add page-level drop overlay and paste handler on tool page ([6ea515c](https://github.com/snapotter-hq/snapotter/commit/6ea515ccdd7cd35f3727d0cf4137b81e9bdea050))
* add per-tool permission model with category and per-tool modes ([9fa23f4](https://github.com/snapotter-hq/snapotter/commit/9fa23f454322808d8c791b9d26b6bdbd1a5e9e73))
* add per-user rate limiting and concurrent job limits ([239f85f](https://github.com/snapotter-hq/snapotter/commit/239f85f098c5c6d3576531e915f57f6128bec357))
* add PostHog customer feedback ([649e65b](https://github.com/snapotter-hq/snapotter/commit/649e65b035c6efbfbe32e4b1db040aa0f9f6ac81))
* add recent tools tracking via localStorage ([6c61ae4](https://github.com/snapotter-hq/snapotter/commit/6c61ae47f496b1aaf937228fe7c55058b0b0756f))
* add request correlation IDs to audit logs and response headers ([1cf1f47](https://github.com/snapotter-hq/snapotter/commit/1cf1f47d6f0554853a501ae1220dbdc0678820cb))
* add session idle timeout and concurrent session limit ([3cc4ef6](https://github.com/snapotter-hq/snapotter/commit/3cc4ef6895ddfc904252e4e99c48d5df41b4c17e))
* add settings slide-in, review panel with size delta, start-over preserving settings ([45121c1](https://github.com/snapotter-hq/snapotter/commit/45121c1a1e8f8f4ab8cbf9601c50faf4a2237803))
* add Sign PDF tool (draw/type/upload signatures, place on a PDF) ([#370](https://github.com/snapotter-hq/snapotter/issues/370)) ([0cdd560](https://github.com/snapotter-hq/snapotter/commit/0cdd560ac46827f7e103e9f1921aec58d226a7db))
* add storage usage tracking with DB counters and reconciliation ([aaa8a37](https://github.com/snapotter-hq/snapotter/commit/aaa8a37c9b3b490a8455311be89a0bd4b858a897))
* add team-level storage quotas with enforcement on upload and save ([d064286](https://github.com/snapotter-hq/snapotter/commit/d0642865590a56769adbc2d7bc6741a12800af52))
* add TopNav and AvatarDropdown components ([f79958a](https://github.com/snapotter-hq/snapotter/commit/f79958a6229015ad64149dadc1fe27909f314a57))
* add usage onboarding survey overlay ([#388](https://github.com/snapotter-hq/snapotter/issues/388)) ([a0d1c70](https://github.com/snapotter-hq/snapotter/commit/a0d1c70172f24af0d4656b6256fc1bfcb9256e69))
* add webhook delivery module with retry and backoff ([ab88b9a](https://github.com/snapotter-hq/snapotter/commit/ab88b9ad0d9104ae69862309f9d2b35c0251d6bc))
* **ai:** add a Reset AI Environment admin feature for the upgrade gap ([#459](https://github.com/snapotter-hq/snapotter/issues/459)) ([fb96cf8](https://github.com/snapotter-hq/snapotter/commit/fb96cf874364b331f152d414b69f8831d0004d07))
* All tab groups tools by modality with collapsible sections ([e7126f9](https://github.com/snapotter-hq/snapotter/commit/e7126f92931e1c0277aca6c56ef06276d961ef64))
* all-in-one embedded single-container mode ([#377](https://github.com/snapotter-hq/snapotter/issues/377)) ([084a9c9](https://github.com/snapotter-hq/snapotter/commit/084a9c9faa48a0b090b1d74be97297a3d5d6f727))
* **analytics:** build-time bake + telemetry depth ([#336](https://github.com/snapotter-hq/snapotter/issues/336)) ([5d36ac0](https://github.com/snapotter-hq/snapotter/commit/5d36ac06d88fc4ca3dbf48294c132249921207d9))
* **analytics:** inject Sentry DSN + PostHog key from build env ([#367](https://github.com/snapotter-hq/snapotter/issues/367)) ([9819c58](https://github.com/snapotter-hq/snapotter/commit/9819c5885eab3ea9857dc3b4ca4465fb4b0994f9)), closes [#336](https://github.com/snapotter-hq/snapotter/issues/336)
* **analytics:** upload web source maps to Sentry + tie release to build ([#369](https://github.com/snapotter-hq/snapotter/issues/369)) ([1c202c6](https://github.com/snapotter-hq/snapotter/commit/1c202c6ef08943f05d31fd4d83dff817e1c1503b))
* **api:** section-prefix all custom tool route literals ([10bb73f](https://github.com/snapotter-hq/snapotter/commit/10bb73ffc116814f4dc6ba9c33ed32d8d32d912d))
* **api:** section-prefix factory + batch routes via apiToolPath (+section validation) ([68dd7da](https://github.com/snapotter-hq/snapotter/commit/68dd7dabaa7a9e6d87017b257b5c8cb0f34ae90e))
* arrow key navigation in Files list ([52693fc](https://github.com/snapotter-hq/snapotter/commit/52693fc843143b9ac2d788fb9b5321ee3a52409f))
* **audit:** add TOOL_EXECUTED logging with opt-in setting ([36f083b](https://github.com/snapotter-hq/snapotter/commit/36f083ba64bfa2063c724223c3d59ffadb626cb5))
* **audit:** capture IP address, make TRUST_PROXY configurable ([5d2f520](https://github.com/snapotter-hq/snapotter/commit/5d2f520d7823969578945acfd3e6799bfd6ff3f7))
* **audit:** extensible event type system with shared constants ([37b2b9c](https://github.com/snapotter-hq/snapotter/commit/37b2b9c2eef0e2926dbee03f6b24f16eb53f544e))
* **automate:** make the pipeline builder fully multi-modal ([#335](https://github.com/snapotter-hq/snapotter/issues/335)) ([a53038e](https://github.com/snapotter-hq/snapotter/commit/a53038ed9610a964090a98f6973a25449a1e4a9f))
* bump feature manifest to v2 with archive metadata ([a4ac7cf](https://github.com/snapotter-hq/snapotter/commit/a4ac7cf7d66240f64fc7c394711a4ab5b5036056))
* **ci:** add verify job to ai-bundles workflow ([7d09927](https://github.com/snapotter-hq/snapotter/commit/7d099274c120c28845ab40fa8b00754015552901))
* **ci:** add verify-bundle.sh for AI bundle smoke testing ([5ee948d](https://github.com/snapotter-hq/snapotter/commit/5ee948d36a998f8a39b92d31cc9e3def331535e8))
* clean preview button with progress bar, add document preview support ([3decfaa](https://github.com/snapotter-hq/snapotter/commit/3decfaae3ea0180415851cacfc88674b50418c01))
* clean tool page nav, add Import from Files on dropzone ([b5eef64](https://github.com/snapotter-hq/snapotter/commit/b5eef644e3c932b18884141055b65a7904d57665))
* copy-primary for data tools, download-all label for multi-output, batch failure display ([bc3ad2b](https://github.com/snapotter-hq/snapotter/commit/bc3ad2b008e789b92597688923690f28d5cf54ed))
* **db:** add audit integrity/requestId columns, user_preferences table, audit indexes ([cafd2d8](https://github.com/snapotter-hq/snapotter/commit/cafd2d8b6547eccdb9735acf344207534c13aeae))
* **db:** add data lifecycle columns (deleteAfter, legalHold, quotas, retention) ([7e5843c](https://github.com/snapotter-hq/snapotter/commit/7e5843cd403b2d59d844d5a1d8d3a9ccb0618899))
* **db:** add identity columns (lastActivity, toolPermissions, TOTP) ([7ed043e](https://github.com/snapotter-hq/snapotter/commit/7ed043ec5301106ad64ec0accc7ce411d818a469))
* disable auto-save, add Save to Files button, accept all file types in library ([d0795b6](https://github.com/snapotter-hq/snapotter/commit/d0795b69eaecf61cdb65377ee5561fca64c1de26))
* **docs:** Two-Doors home, otter-orange brand, Pagefind search, and enterprise SSO/SCIM/roles guides ([91ac583](https://github.com/snapotter-hq/snapotter/commit/91ac583e873d70fed01ecdb337c60a0234ebdc1d))
* **enterprise:** add audit log archival with crash-safe state machine ([c1dc27f](https://github.com/snapotter-hq/snapotter/commit/c1dc27f2484120f7f4571c8472fccd292e43f259))
* **enterprise:** add audit log export endpoint (CSV/JSON) ([913dd6b](https://github.com/snapotter-hq/snapotter/commit/913dd6bbe1518e7b709dd002329417789e103f49))
* **enterprise:** add configuration export/import with dry-run and dependency validation ([0f883fe](https://github.com/snapotter-hq/snapotter/commit/0f883fe853fb818275bcdb44248f99e24ca33083))
* **enterprise:** add GDPR user data export (async) ([b6a8226](https://github.com/snapotter-hq/snapotter/commit/b6a82268377bc331e38e65dcf80fe60aec6a2ff2))
* **enterprise:** add GDPR user/team data purge with audit redaction ([dd2a507](https://github.com/snapotter-hq/snapotter/commit/dd2a50799a255a05e732de5943a7481b91b2c86d))
* **enterprise:** add IP allowlisting with CIDR matching and Redis cache ([db6f7bf](https://github.com/snapotter-hq/snapotter/commit/db6f7bf38af677f896a69ea75c2cd68ec05bffb7))
* **enterprise:** add legal hold with cleanup bypass ([fa7da7c](https://github.com/snapotter-hq/snapotter/commit/fa7da7ce0c3bf480a59b429c1ad39ab23fe7cf18))
* **enterprise:** add per-team retention overrides with deleteAfter ([b60f550](https://github.com/snapotter-hq/snapotter/commit/b60f550b3fa54c4b10681e6281e989678b6c955a))
* **enterprise:** add SAML 2.0 SSO with SP-initiated login ([54132d1](https://github.com/snapotter-hq/snapotter/commit/54132d1833439425825954c4c55fba7975e24d0a))
* **enterprise:** add SCIM 2.0 provisioning (Users + Groups) ([a1b5c6d](https://github.com/snapotter-hq/snapotter/commit/a1b5c6d2c30c8a195a17b534a18c5fb93733135a))
* **enterprise:** add SIEM webhook forwarding with circuit breaker ([d3f30a2](https://github.com/snapotter-hq/snapotter/commit/d3f30a2f5d1d846bb4d56a3d2f0c208065258ba8))
* **enterprise:** add SSO enforcement mode with break-glass admin ([0c4468a](https://github.com/snapotter-hq/snapotter/commit/0c4468a004c228e860912dd8e3e662d270d3d113))
* **enterprise:** add tamper-resistant audit mode with HMAC integrity ([895e29e](https://github.com/snapotter-hq/snapotter/commit/895e29e93fb141a279dcd090ad0199f248faed2f))
* **enterprise:** add TOTP MFA with enrollment, verification, and recovery codes ([1787be3](https://github.com/snapotter-hq/snapotter/commit/1787be35fe4b6d3b1f313511cc36c2277df64034))
* **enterprise:** add unified webhook system with admin alerts ([d86e458](https://github.com/snapotter-hq/snapotter/commit/d86e4585e4e1069fa95aa49de951827fbdccf8f3))
* **enterprise:** add upgrade management endpoints (version, migrations, readiness) ([03e12e6](https://github.com/snapotter-hq/snapotter/commit/03e12e6f0b92308dc311a33a848cf09cd7e74bfd))
* expand alternatives comparisons ([#384](https://github.com/snapotter-hq/snapotter/issues/384)) ([174001d](https://github.com/snapotter-hq/snapotter/commit/174001d3844172fbc8d7dad8282ef1d83a8e4d7f))
* expand Prometheus metrics with request duration, storage, and auth counters ([fb14f41](https://github.com/snapotter-hq/snapotter/commit/fb14f41512e8d65417b6a7dee129d48f05285459))
* extend crash recovery for pre-built bundle artifacts ([d1e9536](https://github.com/snapotter-hq/snapotter/commit/d1e9536cffb7a53a291627bd36d173d850082a41))
* extend health endpoints with disk space, S3, storage, and backup checks ([6237684](https://github.com/snapotter-hq/snapotter/commit/6237684ec86289fdfab5ed982dd2af6a9a5e37d1))
* extend importBundleArchive for site-packages and fixups ([5d5240e](https://github.com/snapotter-hq/snapotter/commit/5d5240e48131653e3a64917fae312a044326992c))
* **feedback:** always-on nav button with GitHub/email handoff when analytics is off ([#428](https://github.com/snapotter-hq/snapotter/issues/428)) ([5dcc06a](https://github.com/snapotter-hq/snapotter/commit/5dcc06a99ea18a6b5448b3a7a1e54b40158c8b07))
* **feedback:** route failed-run Report issue through the offline handoff ([#429](https://github.com/snapotter-hq/snapotter/issues/429)) ([8cdd85a](https://github.com/snapotter-hq/snapotter/commit/8cdd85a49339c2cce3c916b756e4c6da1fe2abfc))
* filter files by modality when importing from tool page ([826f1ef](https://github.com/snapotter-hq/snapotter/commit/826f1efc087d1708ee1171b145f710e57a9d7ed2))
* **i18n:** add repair UI strings for broken AI bundles ([8e15fe7](https://github.com/snapotter-hq/snapotter/commit/8e15fe7a3f633771ba05e1b4cb2f3eae15b5bed0))
* **i18n:** raise translation coverage across all 20 locales ([#332](https://github.com/snapotter-hq/snapotter/issues/332)) ([ffbf4f9](https://github.com/snapotter-hq/snapotter/commit/ffbf4f9e10f5e8f4fde9be286e0e7a024dde7a15))
* **i18n:** raise translation coverage across all 20 locales (round 2) ([#453](https://github.com/snapotter-hq/snapotter/issues/453)) ([44e1f90](https://github.com/snapotter-hq/snapotter/commit/44e1f90e4a847b7059869cd5750280f472ef3a05)), closes [#428](https://github.com/snapotter-hq/snapotter/issues/428) [425/#426](https://github.com/snapotter-hq/snapotter/issues/426)
* Import from Files works, remove pipeline button from files page ([b8a6b20](https://github.com/snapotter-hq/snapotter/commit/b8a6b2018ed1736ab4f9f234b435bce666c10d90))
* inline error messages with recovery actions ([56cd843](https://github.com/snapotter-hq/snapotter/commit/56cd843482ab93d59f26fc360fa48d11f161c815))
* **landing,docs:** SEO fixes and query-matched tool pages ([#383](https://github.com/snapotter-hq/snapotter/issues/383)) ([ec98dfd](https://github.com/snapotter-hq/snapotter/commit/ec98dfde9a63590f513c1448a18a57f836ad1515))
* **landing:** add animated shadergradient hero background ([#411](https://github.com/snapotter-hq/snapotter/issues/411)) ([5500fac](https://github.com/snapotter-hq/snapotter/commit/5500facc5d8d38437bd976663a10b41ba71bee10))
* **landing:** auto-refresh live GitHub stars and image-pull stats ([#292](https://github.com/snapotter-hq/snapotter/issues/292)) ([33671d2](https://github.com/snapotter-hq/snapotter/commit/33671d2d9227ffbb3580e8b7d40fd260c06d7853))
* **landing:** enterprise-focused hero redesign and section polish ([#239](https://github.com/snapotter-hq/snapotter/issues/239)) ([f622a4f](https://github.com/snapotter-hq/snapotter/commit/f622a4f691dce066adcc31bd8838b1f4014b92e0))
* **landing:** generate 301 redirects for old tool URLs; fix robots sitemap reference ([0051655](https://github.com/snapotter-hq/snapotter/commit/0051655bbf0201642f97436adf5c3130af8131c0))
* **landing:** migrate from Next.js to Astro 5 ([8403222](https://github.com/snapotter-hq/snapotter/commit/8403222d08034362382a902feec509665cb32bcb))
* **landing:** one-command Docker quickstart + live-demo CTA in hero ([#455](https://github.com/snapotter-hq/snapotter/issues/455)) ([aaf39a1](https://github.com/snapotter-hq/snapotter/commit/aaf39a1b7221e6581b681e776513063aed39eed3))
* **landing:** refocus hero on privacy-sensitive teams ([#431](https://github.com/snapotter-hq/snapotter/issues/431)) ([8451f9b](https://github.com/snapotter-hq/snapotter/commit/8451f9be0883dc58ac4413bc00c6e6edd082a896))
* **landing:** section-nested tool routes, section index pages, and section-prefixed links ([f158be6](https://github.com/snapotter-hq/snapotter/commit/f158be6aaa1e4ce907e0abe93a20f6791168b310))
* **landing:** swap Try Demo for Get Started Free CTA in top nav ([#418](https://github.com/snapotter-hq/snapotter/issues/418)) ([ea004a3](https://github.com/snapotter-hq/snapotter/commit/ea004a3308de489efa45fa77585ec4da9da82180))
* **landing:** warm up the contact CTAs ([#412](https://github.com/snapotter-hq/snapotter/issues/412)) ([3d4a84d](https://github.com/snapotter-hq/snapotter/commit/3d4a84d06865f0d790d39fee50809633cc6892c8))
* make password policy configurable via admin settings ([8b349b0](https://github.com/snapotter-hq/snapotter/commit/8b349b0341b8cde518558c8ef83523263a95abae))
* merge PostHog customer feedback ([1d99acf](https://github.com/snapotter-hq/snapotter/commit/1d99acf9ee30e0fe9528b02761a3eed5e808f0b8))
* mobile layout for tool-first flow ([896acda](https://github.com/snapotter-hq/snapotter/commit/896acda7ed033a13817d3556c50cea35ec884c3c))
* modality-aware file preview in Files library ([a70b13a](https://github.com/snapotter-hq/snapotter/commit/a70b13ad3207617c794fd90bf5c5dcd85c4a90ec))
* modality-based URLs (/image/resize, /video/compress-video) ([ea83e1c](https://github.com/snapotter-hq/snapotter/commit/ea83e1c8b4af7e613b4a5184b7b3e816ba1f1376))
* **modality:** rename "file" modality label "Data" -> "Files" ([71fefc0](https://github.com/snapotter-hq/snapotter/commit/71fefc05b08bdfc344de6beb16963b7cc632fac2))
* move theme toggle and language selector to top nav bar ([aff9159](https://github.com/snapotter-hq/snapotter/commit/aff9159ae0ef251a5be46bbae5a8a20ede2c419a))
* on-demand preview generation with progress messages for non-native formats ([d3cd4e4](https://github.com/snapotter-hq/snapotter/commit/d3cd4e41b5c8fab1732c16243c0a6c5c46b0b63e))
* pin frequently-used tools to the top of the dashboard ([#440](https://github.com/snapotter-hq/snapotter/issues/440)) ([3aaaacc](https://github.com/snapotter-hq/snapotter/commit/3aaaacc7a1830d748a3f6602cc6a81efbc9a9f32))
* pipeline templates, analytics opt-out, 83 conversion presets, positioning + e2e modernization ([63a03d2](https://github.com/snapotter-hq/snapotter/commit/63a03d26f2f627578420dc4b7011e1078635651a)), closes [#355](https://github.com/snapotter-hq/snapotter/issues/355) [#354](https://github.com/snapotter-hq/snapotter/issues/354) [#356](https://github.com/snapotter-hq/snapotter/issues/356) [#353](https://github.com/snapotter-hq/snapotter/issues/353) [#351](https://github.com/snapotter-hq/snapotter/issues/351)
* polish home page UI -- card borders, colored icons, 3-col grid, Cmd+K hint ([ade79c5](https://github.com/snapotter-hq/snapotter/commit/ade79c53a59cd3a991224f5e82b9a6e3861457bf))
* redesign review panel action hierarchy ([ed458d4](https://github.com/snapotter-hq/snapotter/commit/ed458d4bbdfaeb7054fa15c1fbaf2616ed19f45f))
* remove /fullscreen route, add dynamic page titles ([f9ebb30](https://github.com/snapotter-hq/snapotter/commit/f9ebb304db1b71ad0e6149d094dd7f6cac8777db))
* replace sidebar with top nav bar across all pages ([71fef43](https://github.com/snapotter-hq/snapotter/commit/71fef439a0d41bce34890d637c40a670fb2ce443))
* request a tool when home search finds nothing ([#385](https://github.com/snapotter-hq/snapotter/issues/385)) ([c68297d](https://github.com/snapotter-hq/snapotter/commit/c68297d5a49e659645b510da245241aa26a40cb6))
* rewrite home page as tool-first browser with search and modality tabs ([0d751b7](https://github.com/snapotter-hq/snapotter/commit/0d751b7d143a9102b3fe24e94c4e49ce616ee310))
* rewrite install_feature.py for pre-built tar bundles ([a4fa3ce](https://github.com/snapotter-hq/snapotter/commit/a4fa3ce2a71930a8b57fd3f17181c51f703a2081))
* **scripts:** add segment-anchored tool-path rewrite transform ([c17a4a4](https://github.com/snapotter-hq/snapotter/commit/c17a4a422582594c6e2127429a7373c2e0ade11c))
* **scripts:** add tool-path codemod CLI ([0691457](https://github.com/snapotter-hq/snapotter/commit/0691457f94dd63a53285107ab56d9ba73c1b3b47))
* server-side preview generation for non-native video/audio formats ([412a21e](https://github.com/snapotter-hq/snapotter/commit/412a21ee4d9a68baadef817509a5cc1a675a5143))
* **shared:** add apiToolPath() and section-prefixed routes; drop MODALITY_URL_SLUG ([9ca901f](https://github.com/snapotter-hq/snapotter/commit/9ca901f8d5b23b0a03060b3384af58c60cfbbaa0))
* **shared:** add Section concept and toolSection() partition ([7907471](https://github.com/snapotter-hq/snapotter/commit/790747188afe4fa0347579d6ce2db80d68bcfd2b))
* tiered processing feedback and upload progress indicator ([433d59c](https://github.com/snapotter-hq/snapotter/commit/433d59c726d196c7b51ea2cc29b0e2d44fa11feb))
* tool-first workflow polish -- fix tests, lint cleanup ([f387e98](https://github.com/snapotter-hq/snapotter/commit/f387e98fff6049a4869cebd4e4d7a717e7c1f28e))
* **tools:** 2.0 phase 5 wave 2 - pdf depth (21 tools) ([#220](https://github.com/snapotter-hq/snapotter/issues/220)) ([2f39e38](https://github.com/snapotter-hq/snapotter/commit/2f39e3816209fe81fac4620dd1233921e5de90d4))
* **tools:** 2.0 phase 5 wave 3a - video depth (22 tools) ([#221](https://github.com/snapotter-hq/snapotter/issues/221)) ([5f98b48](https://github.com/snapotter-hq/snapotter/commit/5f98b485935f07e40c0a6e57548892b2e17fc03b))
* **tools:** 2.0 phase 5 wave 3b - audio depth (14 tools) ([#222](https://github.com/snapotter-hq/snapotter/issues/222)) ([638288e](https://github.com/snapotter-hq/snapotter/commit/638288e196f05d889b5d818c0c8a11b0697ec49c))
* **tools:** 2.0 phase 5 wave 4 - office, ebooks, data, archives (14 tools) ([#224](https://github.com/snapotter-hq/snapotter/issues/224)) ([fc7c1f8](https://github.com/snapotter-hq/snapotter/commit/fc7c1f850e36fd01db9f08caf574f6f48d606b93))
* **tools:** 2.0 phase 5 wave 5a - image gap-fill (11 tools) ([#225](https://github.com/snapotter-hq/snapotter/issues/225)) ([6e1b986](https://github.com/snapotter-hq/snapotter/commit/6e1b9865f10c50badddb693a09ec20557379fe63))
* **tools:** 2.0 phase 5 wave 5b - ai pool: ocr-pdf, transcription, background composites (5 tools) ([#226](https://github.com/snapotter-hq/snapotter/issues/226)) ([51666cd](https://github.com/snapotter-hq/snapotter/commit/51666cdd5fd207ceee4da38b63d998af9a044809))
* **web:** add data retention settings to admin UI ([3016571](https://github.com/snapotter-hq/snapotter/commit/3016571c2b2925e8fc7677d9d2daae2bd8191db1))
* **web:** add MFA login prompt and security settings UI ([d397f57](https://github.com/snapotter-hq/snapotter/commit/d397f576676d127ee23c49a2948b041a6a6a777e))
* **web:** add storage dashboard and team retention settings ([c7e9b1d](https://github.com/snapotter-hq/snapotter/commit/c7e9b1ddc6189f847633399a982ce88cb6ae4a85))
* **web:** apply Otter Orange design system and UI improvements ([bcd59c2](https://github.com/snapotter-hq/snapotter/commit/bcd59c20c7da6208e937cac0a9b9f02ecf73b4f1)), closes [#E07832](https://github.com/snapotter-hq/snapotter/issues/E07832) [#2563eb](https://github.com/snapotter-hq/snapotter/issues/2563eb)
* **web:** complete audit log viewer with IP column and all event types ([c6f9a29](https://github.com/snapotter-hq/snapotter/commit/c6f9a29687562c929d708a110eb0b7145c4dab11))
* **web:** fuzzy search with fuse.js for typo-tolerant tool discovery ([22cccd4](https://github.com/snapotter-hq/snapotter/commit/22cccd46c44c386aed5303efbd608105ddc1b30f))
* **web:** group home grid, tabs, and breadcrumb by section ([8301676](https://github.com/snapotter-hq/snapotter/commit/8301676e139fa0ed1d2423e133b11e0214bfe4cd))
* **web:** icon-only modality tabs, merge documents and files ([cc06c80](https://github.com/snapotter-hq/snapotter/commit/cc06c802c13b4d229fa2a97c3493aef4a555b1e6))
* **web:** in-canvas zoom & pan for the object eraser and split tools ([#320](https://github.com/snapotter-hq/snapotter/issues/320)) ([95d100c](https://github.com/snapotter-hq/snapotter/commit/95d100c20bd9b41cca3190a7791807516d2a17e4))
* **web:** modality filter tabs in sidebar tool panel ([8adceaf](https://github.com/snapotter-hq/snapotter/commit/8adceaf92d3effd8b4a2f15d6f8ecfc0f6c1ab8d))
* **web:** modality tabs on fullscreen grid page ([82fb798](https://github.com/snapotter-hq/snapotter/commit/82fb798142663b22d23bda69bf66d0d8cb56def9))
* **web:** section-prefix all tool API calls ([22b4b5c](https://github.com/snapotter-hq/snapotter/commit/22b4b5c3c17ea28712e2e9bf06ca35b6c5a23bd3))
* **web:** show icon + text labels on modality filter tabs ([888d243](https://github.com/snapotter-hq/snapotter/commit/888d243a653b7ecfab20830be2ea8baa961f8e71))
* **web:** stronger modality section visual hierarchy in tool catalog ([3db1b3b](https://github.com/snapotter-hq/snapotter/commit/3db1b3bafd9bfcde86c9d74037a30114437e4f71))
* wire AI bundle build into release pipeline ([d0732d4](https://github.com/snapotter-hq/snapotter/commit/d0732d4a586be25231be93e51e94db7ae05ae8ca))

### Reverts

* **deps:** keep rembg at 2.0.69 (2.0.75 conflicts with pinned numpy==1.26.4) ([4fdd10f](https://github.com/snapotter-hq/snapotter/commit/4fdd10f488642eabe671aa111796d343d0e2d358))

### BREAKING CHANGES

* SnapOtter 2.0 - the platform re-architecture (Postgres 17 +
Redis 8 + BullMQ durable jobs, 157 tools across five modalities) is the 2.0
release line, replacing the 1.x SQLite single-container architecture.
* SQLite is no longer the runtime database. Deployments now
require Postgres (and Redis, used from phase 2). Existing installs migrate
with SQLITE_MIGRATE_PATH or 'pnpm --filter @snapotter/api migrate:sqlite'.

* fix(ci): postgres service + fresh e2e database per run; ignore unfixable torch CVE-2025-3000
This commit is contained in:
semantic-release-bot
2026-07-07 07:36:51 +00:00
parent 9d1bbe7beb
commit 1d21184cfe
2 changed files with 339 additions and 104 deletions
-104
View File
@@ -1,104 +0,0 @@
# SnapOtter 2.0.0
## Highlights
SnapOtter 2.0 turns the image toolkit into a full file-manipulation suite: 200+ tools across five modalities (Image, Video, Audio, PDF, and Files) plus a layer-based image editor, all still self-hosted with no external SaaS. Under the hood the whole platform was rebuilt on Postgres 17 and a Redis-backed job queue, so long-running work (video transcodes, AI upscales, OCR) now runs as durable background jobs with live progress instead of blocking a request. And you can start the entire stack with a single `docker run`.
This is a major release. If you're on 1.x, read the Breaking Changes section before upgrading: your data migrates automatically, but the container stack changed.
## New Features
- **Four new tool modalities**: Video, Audio, PDF, and Files join Image, taking the catalog from a focused image toolkit to 200+ tools. Trim and transcode video, convert and normalize audio, split/merge/compress/sign PDFs, and run file utilities, all in the same self-hosted app.
- **Durable background jobs**: A Redis-backed queue (BullMQ) runs every tool as a tracked job. Fast tools still return instantly; long ones stream live progress over SSE and survive a page reload or a brief network drop.
- **All-in-one single-container mode**: `docker run -p 1349:1349 -v snapotter-data:/data snapotter/snapotter:2.0.0` now boots a complete instance with an embedded Postgres and Redis. No Compose file required for a quick start. Compose remains the recommended production path.
- **On-demand AI bundles**: Background removal, OCR, transcription, upscaling, face detection/enhancement, object eraser and colorize, and photo restoration install on demand from the UI into your data volume, so the base image stays lean and installed models survive container recreation. GPU acceleration is detected per framework.
- **Sign PDF**: Draw, type, or upload a signature and place it anywhere on a PDF, right in the browser.
- **Automate (visual pipeline builder)**: Chain tools into reusable pipelines where each step's output feeds the next, across all modalities, with nine prebuilt templates to start from.
- **83 one-click conversion presets**: Dedicated JPG-to-PNG, MP4-to-GIF, and similar converters with fuzzy search, so common conversions are a single click.
- **Layer-based image editor**: A Konva-powered editor at `/editor` with brushes, shapes, adjustments, filters, and curves.
- **Files library**: Save any result to a persistent library and reuse it as input to another tool without downloading and re-uploading.
- **Pinned tools**: Pin the tools you use most to the top of the dashboard.
- **In-canvas zoom and pan**: Zoom and pan directly inside the object eraser and split tools instead of relying on browser zoom.
- **Enterprise capabilities**: OIDC/SSO, SAML, SCIM provisioning, S3-compatible storage, per-tool permissions, audit export, and OpenTelemetry distributed tracing, all offline-validated and gated behind a license.
- **21 languages**: Full UI translations across 21 locales.
- **Analytics with a real opt-out**: Product analytics and error reporting are on by default with an instance-wide admin toggle in Settings that genuinely stops all egress.
## Improvements
- **Cancel a running process**: You can now cancel work in progress instead of waiting for it to finish. (#137)
- **Full-resolution RAW decoding**: RAW files (including DNG) decode through LibRaw first, so they process at full resolution instead of failing. (#289)
- **Non-root and foreign-UID deployments**: Storage is writable under arbitrary UIDs, and the app sets a writable HOME, so TrueNAS, Unraid, OpenShift, and PUID/PGID setups work correctly. (#230, #127)
- **Accurate AI install detection**: Tools that are already installed no longer prompt you to download them again, and the install flow is hardened against partial-download states. (#214, #352)
- **Privacy hardening**: Removed automatic third-party egress of user data. Map tiles, API-reference fonts, and editor fonts are self-hosted, and an optional strict-offline mode (`SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0`) disables even AI model self-heal downloads.
- **Always-on feedback button**: The feedback button stays visible even with analytics off, handing off to GitHub issues or email instead of going dark.
## Bug Fixes
- **RATE_LIMIT_PER_MIN=0 now disables rate limiting for tool routes**: Setting the limit to `0` correctly means unlimited on `/api/v1/tools/*` again. (#271)
- **AI venv paths in Docker**: Repaired copied AI virtualenv paths so bundles resolve correctly inside the container. (#390)
- **sharp 0.35.2+ compatibility**: Adopted the newer sharp `FormatEnum` typing so the image pipeline builds cleanly on current sharp. (#362)
- **Image editor layout**: Fixed rulers rendering as black bars, incorrect Paint Bucket/Fill behavior, a clipped right sidebar, and a canvas that used only part of the viewport. (#258, #259)
- **Italian translations**: Completed and corrected the Italian UI, feedback, and loading-message strings. (#231, #206, #425)
- **Audio sample rate**: Normalize/loudnorm now preserves the source sample rate instead of resampling.
- **SSRF hardening**: Numeric CIDR matching for IPv6 allow/deny lists and a broadened URL pre-scan (srcset, poster, formaction, `@import`) close server-side request forgery vectors.
- **PDF metadata**: Generated PDFs are stamped honestly with SnapOtter as the Producer.
- **mediapipe on Python 3.13 / Debian 13**: Loosened the mediapipe pin and made requirement paths resolve relative to the source file, so AI bundles install on newer base images.
## Breaking Changes
> **Action required:** 2.0 replaces the embedded SQLite database with Postgres 17 and adds Redis 8 for the job queue. Your 1.x data migrates automatically, but the container stack changed, so you can't just `pull` the new image onto your old single-container setup.
>
> **1. Back up your whole data volume first.** 1.x runs SQLite in WAL mode, so the committed data usually lives in `snapotter.db-wal`, not `snapotter.db` alone. Back up the entire `/data` volume, not just the `.db` file.
>
> **2. Pick a stack:**
> - **Single container (simplest):** `docker run -p 1349:1349 -v /path/to/your/data:/data snapotter/snapotter:2.0.0`. Postgres and Redis run embedded. This requires running as root; arbitrary-UID runtimes should use Compose.
> - **Compose (recommended for production):** use the updated `docker-compose.yml`, which now brings up the app plus Postgres 17 and Redis 8 (a three-container stack).
>
> **3. First boot migrates automatically.** On startup, SnapOtter detects a 1.x SQLite database on the mounted volume and imports it. To run it by hand, use `pnpm --filter @snapotter/api migrate:sqlite -- <path> [--dry-run|--verify]`, or set `SQLITE_MIGRATE_PATH` to point at the file.
>
> Full step-by-step instructions are in `MIGRATING.md` and the upgrade guide at `apps/docs/guide/upgrading.md`.
## Acknowledgements
This release leaned on a lot of community help. Thank you to everyone who filed bugs, requested features, contributed code and translations, joined the discussions, and disclosed security issues.
Code and translations:
- **@mvanhorn**: Adopted sharp 0.35.2+ by centralizing the `FormatEnum` key type. (#362)
- **@EnanoFurtivo**: Reported and fixed rate limiting not honoring `RATE_LIMIT_PER_MIN=0` on tool routes. (#271, #272)
- **@SyntaxSawdust**: Fixed the copied AI virtualenv paths in the Docker image. (#390)
- **@albanobattistella**: Ongoing Italian translation contributions across the UI and feedback strings. (#231, #206, #425, #414)
Bug reports:
- **@feelugly**: RAW (DNG) decoding failing with a ufraw-batch error. (#289)
- **@shrisha108**: Image editor ruler rendering and layout issues. (#258, #259)
- **@spaganini**: "Workspace folder is not writable" on TrueNAS. (#230)
- **@mptpro**: Remove Background prompting to download a model that was already installed. (#214)
- **@wiltwong**: AI tools not compatible with PUID/PGID environment variables. (#127)
- **@Aloe-recite**: AI background removal download failing. (#352)
Feature requests and discussions:
- **@LECOQQ**: Requested the ability to cancel a running process. (#137)
- **@d-air1**: Requested a way to zoom in and out of an image without using browser zoom, shipped as in-canvas zoom and pan. (#223)
- **@JamDaBam**: Raised reusing a result across tools without re-uploading, which shaped the Files library workflow. (#357, #389)
Security disclosures:
- **@tonghuaroot**: Responsibly disclosed two server-side request forgery reports that led to hardened IPv6 CIDR matching and a broadened URL pre-scan. (#287)
- **MickLesk** (Proxmox VE community-scripts): Reported the mediapipe pin failing to install on Python 3.13 / Debian 13. (community-scripts/ProxmoxVE#14720)
## Upgrade
```bash
docker compose pull && docker compose up -d
```
Or pull the app image directly:
```bash
docker pull snapotter/snapotter:2.0.0
```
**Full Changelog**: https://github.com/snapotter-hq/SnapOtter/compare/v1.17.2...v2.0.0
+339
View File
@@ -1,3 +1,342 @@
# [2.0.0](https://github.com/snapotter-hq/snapotter/compare/v1.17.2...v2.0.0) (2026-07-07)
* feat!: SnapOtter 2.0.0 ([6205525](https://github.com/snapotter-hq/snapotter/commit/620552569e1b6b163df66ee824a480e6d5750abb)), closes [#254](https://github.com/snapotter-hq/snapotter/issues/254) [#261](https://github.com/snapotter-hq/snapotter/issues/261)
* feat(db)!: SnapOtter 2.0 phase 1 foundation: postgres, migrator, compose stack ([#216](https://github.com/snapotter-hq/snapotter/issues/216)) ([1c724d5](https://github.com/snapotter-hq/snapotter/commit/1c724d5d21659be24423a22c7d6737d59b3d6310))
### Bug Fixes
* adopt sharp 0.35.2+ by centralizing the FormatEnum key type ([#362](https://github.com/snapotter-hq/snapotter/issues/362)) ([9052da2](https://github.com/snapotter-hq/snapotter/commit/9052da27f3a298f950a9949a0e0929e72b569b04))
* **ai-bundles:** lock the numpy-1.x ABI closure so the OCR bundle can't strand scipy ([67c5566](https://github.com/snapotter-hq/snapotter/commit/67c55669d610801e8cd07e4d65c5642a08fc0b07))
* **ai-bundles:** lock the numpy-1.x ABI closure so the OCR bundle can't strand scipy ([#437](https://github.com/snapotter-hq/snapotter/issues/437)) ([fd39f66](https://github.com/snapotter-hq/snapotter/commit/fd39f66f464e21836e8cfd72ab38f3d5c6d3528f))
* **ai-bundles:** repair bundle build + publish pipeline (deepsafe repo, CPU provider, manifest) ([3b50bcd](https://github.com/snapotter-hq/snapotter/commit/3b50bcdc5ccb630998c60003d5eddd9803780013))
* **ai:** broaden SSRF pre-scan regex to cover srcset, poster, formaction, [@import](https://github.com/import) ([5397f9b](https://github.com/snapotter-hq/snapotter/commit/5397f9b21c5b8566fed355f13d62378035456981))
* **ai:** detect a paddle-only GPU so OCR uses PaddleOCR-GPU not Tesseract ([#439](https://github.com/snapotter-hq/snapotter/issues/439)) ([7cd514d](https://github.com/snapotter-hq/snapotter/commit/7cd514dd8cdee28b9f600722f43ba63bcdbe2928))
* **ai:** enforce the feature gate on the per-request fallback path ([#331](https://github.com/snapotter-hq/snapotter/issues/331)) ([7a70aff](https://github.com/snapotter-hq/snapotter/commit/7a70affac51153cf0bd6432a7d9bdc4e6c76bc4b)), closes [#327](https://github.com/snapotter-hq/snapotter/issues/327)
* **ai:** gate AI tools on per-framework GPU detection, not a shared boolean ([#445](https://github.com/snapotter-hq/snapotter/issues/445)) ([36dde9a](https://github.com/snapotter-hq/snapotter/commit/36dde9ad8784867270bbfe766650b4c4515dbcb9))
* **ai:** pin protobuf<5 on arm64 so mediapipe face landmarks work ([#417](https://github.com/snapotter-hq/snapotter/issues/417)) ([2c2fb65](https://github.com/snapotter-hq/snapotter/commit/2c2fb65fcaaa835ca589e59255366819cece5fdf))
* **ai:** pin rembg to 2.0.69 to keep numpy<2 compatibility ([3726335](https://github.com/snapotter-hq/snapotter/commit/3726335063984bd572a14eea36c532bda74bc1d6))
* **ai:** surface actionable fix for libGL.so.1 missing on headless installs ([7c70c60](https://github.com/snapotter-hq/snapotter/commit/7c70c60b9e3e0912b1f8be6acf87f378f8b9c080))
* **ai:** update arm64 bundle sha256/size after protobuf<5 rebuild ([#421](https://github.com/snapotter-hq/snapotter/issues/421)) ([2a36b3d](https://github.com/snapotter-hq/snapotter/commit/2a36b3dfe0e4388f7bd1c2a8183f7d87e57dc144)), closes [#417](https://github.com/snapotter-hq/snapotter/issues/417)
* allow reinstall of AI bundles with broken model files ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([27a56c7](https://github.com/snapotter-hq/snapotter/commit/27a56c774bfd8f920355a1f5b70553639ad165df))
* always show NonNativePreview for non-native formats, even after processing ([abaae18](https://github.com/snapotter-hq/snapotter/commit/abaae18669a281a03aeafebec764f9992659c862))
* **analytics:** harden analytics opt-out and feedback surfaces ([#423](https://github.com/snapotter-hq/snapotter/issues/423)) ([23efce9](https://github.com/snapotter-hq/snapotter/commit/23efce9df0f8cedabd9aab033b896f7f3dffc768))
* **api:** batch user-files delete to eliminate N+1 queries ([e2c5714](https://github.com/snapotter-hq/snapotter/commit/e2c57144dd1f8f9a7de629228967725861cb50c7))
* **api:** decode RAW via LibRaw first so DNG processes at full resolution ([#289](https://github.com/snapotter-hq/snapotter/issues/289)) ([#290](https://github.com/snapotter-hq/snapotter/issues/290)) ([3d9ff1e](https://github.com/snapotter-hq/snapotter/commit/3d9ff1e0d2c60a88fdba03c11f45e1422eacf84d))
* **api:** drop app-logger import from media-input; update stale errors mock ([c483897](https://github.com/snapotter-hq/snapotter/commit/c483897452d0769a3a1fbca8758fdc7eaf1b3cc0))
* **api:** fix batch user-files delete recursive CTE query ([82991b6](https://github.com/snapotter-hq/snapotter/commit/82991b6a412f84dd2d1d7295379da3cb189d1440))
* **api:** isolate the factory validation scratch dir from the worker's ([7a205ee](https://github.com/snapotter-hq/snapotter/commit/7a205eeb1239f6fa0d1e3c84c744325b9e953237))
* **api:** log only genuine processing faults at error level ([965501a](https://github.com/snapotter-hq/snapotter/commit/965501aef95fff1f5924e030434ea2688c4f0e8c))
* **api:** make OpenAPI spec ASCII-only so Schemathesis can load it ([#344](https://github.com/snapotter-hq/snapotter/issues/344)) ([c2ae334](https://github.com/snapotter-hq/snapotter/commit/c2ae334c81e18561931247db8f8e68ab08c1ef74))
* **api:** narrow friendlyError matching to avoid collapsing valid messages ([6220885](https://github.com/snapotter-hq/snapotter/commit/6220885e0cfd61b57186136aba174f0042dc6457))
* **api:** propagate lenient structural-validation flag to batch + pipeline ([e52e0bb](https://github.com/snapotter-hq/snapotter/commit/e52e0bb3d53bed90a58d0daca15c9aef633d7d02)), closes [#244](https://github.com/snapotter-hq/snapotter/issues/244)
* **api:** reject non-PDF inputs in pdf-to-image ([37b9c6d](https://github.com/snapotter-hq/snapotter/commit/37b9c6d7bf0d38ffc48febc324e96288b5f59fd4))
* **api:** respect RATE_LIMIT_PER_MIN for tool routes ([#272](https://github.com/snapotter-hq/snapotter/issues/272)) ([ce02ce1](https://github.com/snapotter-hq/snapotter/commit/ce02ce13486989d51314d2afabbdcaf8e0d2a9f9)), closes [#280](https://github.com/snapotter-hq/snapotter/issues/280)
* **api:** return user-safe processing errors, keep raw stderr in logs ([4af4bfa](https://github.com/snapotter-hq/snapotter/commit/4af4bfa8eba5ba059e804af33581ada7250a7d1c))
* **api:** section override for backwards-compat alias routes (adjust-colors) ([fc205c7](https://github.com/snapotter-hq/snapotter/commit/fc205c7428f3d27d542065a70c4a948e4e9742fd))
* **api:** stop leaking raw ffprobe stderr in media validation errors ([3fc4149](https://github.com/snapotter-hq/snapotter/commit/3fc41491437a2968b2ebfd79447d59e68da7ec1d))
* **api:** support sharp 0.35 types ([6f85b3d](https://github.com/snapotter-hq/snapotter/commit/6f85b3d12acac73caf747313511c49c7bdc6c257))
* **api:** wrap role rename and delete in transactions ([b564932](https://github.com/snapotter-hq/snapotter/commit/b5649320833ad0c5d6c57c887ef8587d74564dcb))
* apply processedFileName fallback everywhere processedFilename is used ([857aa75](https://github.com/snapotter-hq/snapotter/commit/857aa75562816dbcc0827eda93125605c495af7c))
* **audio:** low-samplerate ogg encode + post-2.0 QA hygiene ([19d9ed1](https://github.com/snapotter-hq/snapotter/commit/19d9ed181ae0051e0df6a01585036628dd31700a))
* **benchmark:** use section-prefixed tool URLs for 2.0 route scheme ([76fc695](https://github.com/snapotter-hq/snapotter/commit/76fc695233eae54c803ae1730cefb9acd161db45))
* build script venv handling and lint fixes ([b1e94bd](https://github.com/snapotter-hq/snapotter/commit/b1e94bd98851d3cc6da57b343ac8d2528dfda890))
* cache useSyncExternalStore snapshot to prevent infinite re-render ([f68fcb8](https://github.com/snapotter-hq/snapotter/commit/f68fcb8ca6724be0ca83a42593192608cde1a784))
* **ci:** address spec review findings in verify-bundle.sh ([4b5b351](https://github.com/snapotter-hq/snapotter/commit/4b5b35186d925f95566b7d36c9d3994255fc95e2))
* **ci:** deploy landing from dist, not the stale Next.js out path ([#240](https://github.com/snapotter-hq/snapotter/issues/240)) ([44bfca1](https://github.com/snapotter-hq/snapotter/commit/44bfca105fc4bfa1d5d2bfc0da861ed4e0a1e496))
* **ci:** grant ai-bundles reusable call its required token scopes ([03c1a5e](https://github.com/snapotter-hq/snapotter/commit/03c1a5e36f9dd7f904882b7cb19fc27006a61f5d))
* **ci:** harden smoke tests against set -e and fix parameter issues ([efac88c](https://github.com/snapotter-hq/snapotter/commit/efac88c20517c22b3a18a9cb227350cd10bdd3c1))
* **ci:** resolve pre-existing failures making main red ([#250](https://github.com/snapotter-hq/snapotter/issues/250)) ([622c9f9](https://github.com/snapotter-hq/snapotter/commit/622c9f98a5772eae05343407b8408cd7d7539ef9)), closes [#249](https://github.com/snapotter-hq/snapotter/issues/249) [246/#248](https://github.com/snapotter-hq/snapotter/issues/248)
* **ci:** revert rembg to 2.0.62 (2.0.75 requires numpy>=2.3) ([3b8d529](https://github.com/snapotter-hq/snapotter/commit/3b8d529b4422deb4d0782a5e4d536328563afd1e))
* clean file info cards for non-native video/media formats on tool page ([511e941](https://github.com/snapotter-hq/snapotter/commit/511e941da0516e27237621be1eeaf6beb64b2d89))
* clear file store when navigating between tools ([f32b3bd](https://github.com/snapotter-hq/snapotter/commit/f32b3bd51f2107040c081d0d9bee5ac5b0450157))
* correct SAML idpCert property name for @node-saml/node-saml v5 ([b9dac59](https://github.com/snapotter-hq/snapotter/commit/b9dac597362e2fbdd90447bfd7889f85dddfff90))
* critical first-login soft-lock in usage survey overlay ([#392](https://github.com/snapotter-hq/snapotter/issues/392)) ([ca076f9](https://github.com/snapotter-hq/snapotter/commit/ca076f91fde252fd98d3014a260d8ae7534481f0))
* **deps:** close js-yaml DoS alert + document rembg non-reachability ([#286](https://github.com/snapotter-hq/snapotter/issues/286)) ([5d5117a](https://github.com/snapotter-hq/snapotter/commit/5d5117acf729d3b2c00119eede9ba20f0aa17a28))
* **deps:** drop undici override (broke jsdom@29) ([5662532](https://github.com/snapotter-hq/snapotter/commit/56625325013b6c8ac47e159a4d517f7eef29a056))
* **deps:** patch Dependabot security alerts ([8792080](https://github.com/snapotter-hq/snapotter/commit/87920809820cb0179c029ccb7234370431abff67))
* **doc-engine:** treat qpdf exit code 3 (warnings) as success, not failure ([2a2151d](https://github.com/snapotter-hq/snapotter/commit/2a2151d7dd19faa1e4d43d49540729dab33a8eed))
* **docker:** copy patches/ before pnpm install so cold builds succeed ([#300](https://github.com/snapotter-hq/snapotter/issues/300)) ([f74f648](https://github.com/snapotter-hq/snapotter/commit/f74f648e47fb76a30b9fa34cd6dc84f4c0295972))
* **docker:** make storage writable under non-root/foreign UIDs (TrueNAS, OpenShift) ([#299](https://github.com/snapotter-hq/snapotter/issues/299)) ([1fec971](https://github.com/snapotter-hq/snapotter/commit/1fec97111bf4cf4620131e38651b8e114c7b0566)), closes [#230](https://github.com/snapotter-hq/snapotter/issues/230)
* **docker:** make venv bootstrap upgrade-aware with pip-freeze stamp ([39543d6](https://github.com/snapotter-hq/snapotter/commit/39543d651219d4741868ec7ebe34186aa038a914)), closes [#85](https://github.com/snapotter-hq/snapotter/issues/85)
* **docker:** patch OS + pip image CVEs, document accepted Trivy residuals ([#288](https://github.com/snapotter-hq/snapotter/issues/288)) ([c203267](https://github.com/snapotter-hq/snapotter/commit/c203267866aa87994de80d2214f70deff72b7b5f))
* **docker:** repair copied AI venv paths ([#390](https://github.com/snapotter-hq/snapotter/issues/390)) ([7e01d36](https://github.com/snapotter-hq/snapotter/commit/7e01d3637edec10c4b7c73cd6c9d54c6414972f6)), closes [#127](https://github.com/snapotter-hq/snapotter/issues/127) [#127](https://github.com/snapotter-hq/snapotter/issues/127)
* **docker:** restore Postgres/Redis in GPU compose stack + pause image publishing ([9b64a96](https://github.com/snapotter-hq/snapotter/commit/9b64a96bcd2e60ce8e3e051a9d2b57811e98a223))
* **e2e,landing:** robust path escaping (CodeQL) + unique file-tools card ([a6837b6](https://github.com/snapotter-hq/snapotter/commit/a6837b687a096b754367223b4472481071a450b7))
* **e2e:** disable Astro Dev Toolbar during landing e2e tests ([2927e0d](https://github.com/snapotter-hq/snapotter/commit/2927e0d4be063353abb9d23494158849ac3a191a))
* **e2e:** wait for post-login redirect before forcing navigation ([#341](https://github.com/snapotter-hq/snapotter/issues/341)) ([5b75d81](https://github.com/snapotter-hq/snapotter/commit/5b75d813b8523fd378c731de76c429fe900d9d28)), closes [#340](https://github.com/snapotter-hq/snapotter/issues/340)
* **editor:** apply layer effects + object flip, add Beta badge, repair e2e specs ([3120e67](https://github.com/snapotter-hq/snapotter/commit/3120e6708dd4e0eb39c2d3af01623e8f1e9c4473)), closes [#259](https://github.com/snapotter-hq/snapotter/issues/259)
* **editor:** capture document pixels without the zoom/pan transform ([#259](https://github.com/snapotter-hq/snapotter/issues/259)) ([81e16d7](https://github.com/snapotter-hq/snapotter/commit/81e16d7ce6648e3d7acace0b1915fd42774d1096)), closes [#258](https://github.com/snapotter-hq/snapotter/issues/258)
* **editor:** fill canvas viewport, fix black rulers, add resizable panel ([#258](https://github.com/snapotter-hq/snapotter/issues/258)) ([063a2e4](https://github.com/snapotter-hq/snapotter/commit/063a2e47e298e41d1115f4e6e92a96922a607ce6))
* enforce file type filtering using tool's acceptedInputs ([adfa532](https://github.com/snapotter-hq/snapotter/commit/adfa53246ae228eebe2fdd071f23a83400f1296c))
* **enterprise:** SCIM token generation, GDPR job cancellation, MFA replay, config redaction, encryption validation, SCIM rate limit ([29dd675](https://github.com/snapotter-hq/snapotter/commit/29dd675f4262ac0380df3113ae140b4fc7330d21))
* **enterprise:** ship enterprise package in prod image + S3, analytics, tracing, queue fixes ([#342](https://github.com/snapotter-hq/snapotter/issues/342)) ([8f4235d](https://github.com/snapotter-hq/snapotter/commit/8f4235d2c664337f3b970b1be5acc6f92474aeb6)), closes [#82](https://github.com/snapotter-hq/snapotter/issues/82)
* fetch settings on home page mount so tools are visible ([cf543f6](https://github.com/snapotter-hq/snapotter/commit/cf543f6976166b179deb1e5c0fa993bb9e037f0e))
* file library upload accepts all file types, not just images ([6bcee1e](https://github.com/snapotter-hq/snapotter/commit/6bcee1e0739daaad8c66abcc4a4e1bc00bb40735))
* **files:** record the source tool in toolChain on Save to Files ([#435](https://github.com/snapotter-hq/snapotter/issues/435)) ([47a60e7](https://github.com/snapotter-hq/snapotter/commit/47a60e7fad229a9bb9c8e4f33f152cacb3f3dfb4))
* first-run QA sweep of the single-container image ([#413](https://github.com/snapotter-hq/snapotter/issues/413)) ([bf417a5](https://github.com/snapotter-hq/snapotter/commit/bf417a509e529ee6b39d2d5a13a308172b4d08aa))
* GPU deployment robustness (6 fixes from end-to-end testing on an RTX 4070) ([#334](https://github.com/snapotter-hq/snapotter/issues/334)) ([35e18d8](https://github.com/snapotter-hq/snapotter/commit/35e18d8b79861b4aba46d4cb022be868d4d3e757))
* grey out incompatible files in library instead of hiding them ([3a5d55c](https://github.com/snapotter-hq/snapotter/commit/3a5d55cf268301df158163acbeaeaf50c6625a10))
* handle non-image modalities across uploads, previews, and filenames ([#255](https://github.com/snapotter-hq/snapotter/issues/255)) ([8eee17a](https://github.com/snapotter-hq/snapotter/commit/8eee17aeea41577a55b30ead97ca36224b387c04))
* harden against three production Sentry crashes ([#328](https://github.com/snapotter-hq/snapotter/issues/328)) ([8952e9b](https://github.com/snapotter-hq/snapotter/commit/8952e9ba475000da9d2d8e0959c63f3cf2b4506e))
* harden Docker image and async job responses ([f3342a1](https://github.com/snapotter-hq/snapotter/commit/f3342a1e571db5a12f5d8f659903ffe590fa2044))
* harden install queue/dispatcher lifecycle and repair review-sweep regressions ([#395](https://github.com/snapotter-hq/snapotter/issues/395)) ([b4375e5](https://github.com/snapotter-hq/snapotter/commit/b4375e558dfc5ccf34ee6736b886e90f662b1688)), closes [#388](https://github.com/snapotter-hq/snapotter/issues/388) [#390](https://github.com/snapotter-hq/snapotter/issues/390) [#391](https://github.com/snapotter-hq/snapotter/issues/391) [#392](https://github.com/snapotter-hq/snapotter/issues/392) [#393](https://github.com/snapotter-hq/snapotter/issues/393) [#394](https://github.com/snapotter-hq/snapotter/issues/394) [#392](https://github.com/snapotter-hq/snapotter/issues/392)
* **i18n:** complete and correct Italian translation ([#231](https://github.com/snapotter-hq/snapotter/issues/231)) ([#298](https://github.com/snapotter-hq/snapotter/issues/298)) ([c0a8b36](https://github.com/snapotter-hq/snapotter/commit/c0a8b36dcbf56f49fa2e58c8d040171e9e6b63e3))
* **i18n:** complete the Italian feedback translations ([#426](https://github.com/snapotter-hq/snapotter/issues/426)) ([3ae48cc](https://github.com/snapotter-hq/snapotter/commit/3ae48cc76ad4021854a805fcea486f58b045f595)), closes [#425](https://github.com/snapotter-hq/snapotter/issues/425)
* **i18n:** complete the Italian translation update ([#438](https://github.com/snapotter-hq/snapotter/issues/438)) ([#450](https://github.com/snapotter-hq/snapotter/issues/450)) ([0fafeb2](https://github.com/snapotter-hq/snapotter/commit/0fafeb26766ed49014d13b649f9b43ffc2fffca5))
* **i18n:** restore accents in Italian loading-message arrays ([#322](https://github.com/snapotter-hq/snapotter/issues/322)) ([29fcc87](https://github.com/snapotter-hq/snapotter/commit/29fcc8770887b981e73a17e43bea79a2f13da1e5)), closes [#298](https://github.com/snapotter-hq/snapotter/issues/298)
* **i18n:** translate Arabic (ar) UI strings ([#314](https://github.com/snapotter-hq/snapotter/issues/314)) ([ab37505](https://github.com/snapotter-hq/snapotter/commit/ab37505e681602d67ad447e3ad49588e905d48d9))
* **i18n:** translate Brazilian Portuguese (pt-BR) UI strings ([#307](https://github.com/snapotter-hq/snapotter/issues/307)) ([3900350](https://github.com/snapotter-hq/snapotter/commit/3900350ad56d63e9b8ed119539c94c54faf971e0))
* **i18n:** translate Dutch (nl) UI strings ([#309](https://github.com/snapotter-hq/snapotter/issues/309)) ([d036ff6](https://github.com/snapotter-hq/snapotter/commit/d036ff6d44fa9fd8025d3c38b382127066b248c3))
* **i18n:** translate French (fr) UI strings ([#306](https://github.com/snapotter-hq/snapotter/issues/306)) ([fe5c7c8](https://github.com/snapotter-hq/snapotter/commit/fe5c7c8c8667a24cebcd0af8b68f031ddc01ef15))
* **i18n:** translate German (de) UI strings ([#308](https://github.com/snapotter-hq/snapotter/issues/308)) ([4de24b8](https://github.com/snapotter-hq/snapotter/commit/4de24b8c9e4e703b4fd51965ccb9387e1e09fa59))
* **i18n:** translate Hindi (hi) UI strings ([#316](https://github.com/snapotter-hq/snapotter/issues/316)) ([00c89e4](https://github.com/snapotter-hq/snapotter/commit/00c89e4ae9060c1cc4100340f5db223bfd768e0f))
* **i18n:** translate Indonesian (id) UI strings ([#318](https://github.com/snapotter-hq/snapotter/issues/318)) ([8a8a4f9](https://github.com/snapotter-hq/snapotter/commit/8a8a4f99a431ec10ccfdbb472672e976b5b86db2))
* **i18n:** translate Japanese (ja) UI strings ([#304](https://github.com/snapotter-hq/snapotter/issues/304)) ([d8b037c](https://github.com/snapotter-hq/snapotter/commit/d8b037c8c6e8c6cde9c4c6900c1d5689143f5d5d))
* **i18n:** translate Korean (ko) UI strings ([#305](https://github.com/snapotter-hq/snapotter/issues/305)) ([e7b412f](https://github.com/snapotter-hq/snapotter/commit/e7b412fc097d6c745037781e7478414a33d6db25))
* **i18n:** translate Polish (pl) UI strings ([#312](https://github.com/snapotter-hq/snapotter/issues/312)) ([7ce9c64](https://github.com/snapotter-hq/snapotter/commit/7ce9c64b50c5b1fa1eb153c8635384eb5ae0e03b))
* **i18n:** translate Russian (ru) UI strings ([#311](https://github.com/snapotter-hq/snapotter/issues/311)) ([eb9a14a](https://github.com/snapotter-hq/snapotter/commit/eb9a14a226824047cdf00ac94ef647e2bfdcf23a))
* **i18n:** translate Simplified Chinese (zh-CN) UI strings ([#302](https://github.com/snapotter-hq/snapotter/issues/302)) ([26d8a06](https://github.com/snapotter-hq/snapotter/commit/26d8a0685c6b2a216fd72b9431d18543abfa89ee))
* **i18n:** translate Spanish (es) UI strings ([#301](https://github.com/snapotter-hq/snapotter/issues/301)) ([b3ff8ac](https://github.com/snapotter-hq/snapotter/commit/b3ff8accec5494d2fe97a27355257b3c5fa2f91d))
* **i18n:** translate Swedish (sv) UI strings ([#310](https://github.com/snapotter-hq/snapotter/issues/310)) ([c4ce5f9](https://github.com/snapotter-hq/snapotter/commit/c4ce5f96dfe6daf8e560de34cd748b1795ed12ff))
* **i18n:** translate Thai (th) UI strings ([#319](https://github.com/snapotter-hq/snapotter/issues/319)) ([5a6368d](https://github.com/snapotter-hq/snapotter/commit/5a6368db89df5419885b3f8dc568eeaa16cd8206))
* **i18n:** translate Traditional Chinese (zh-TW) UI strings ([#303](https://github.com/snapotter-hq/snapotter/issues/303)) ([de4d2ed](https://github.com/snapotter-hq/snapotter/commit/de4d2ed166d858530dcbbb0634ddcb9c7536ab07))
* **i18n:** translate Turkish (tr) UI strings ([#315](https://github.com/snapotter-hq/snapotter/issues/315)) ([8c1c2c3](https://github.com/snapotter-hq/snapotter/commit/8c1c2c310eac95d5a75fcfd563b9026dba9a4fae))
* **i18n:** translate Ukrainian (uk) UI strings ([#313](https://github.com/snapotter-hq/snapotter/issues/313)) ([6ee1b0f](https://github.com/snapotter-hq/snapotter/commit/6ee1b0f7a1b58dd7ae113fc4268067e0ac1e0b3c))
* **i18n:** translate Vietnamese (vi) UI strings ([#317](https://github.com/snapotter-hq/snapotter/issues/317)) ([4702721](https://github.com/snapotter-hq/snapotter/commit/470272169d947e27ff826e2c0e24e1553eda0543))
* **image-engine:** support sharp 0.35 types ([2137be4](https://github.com/snapotter-hq/snapotter/commit/2137be479e1a23e163587acd1609e77058e9e134))
* **jobs:** pre-warm QueueEvents to kill first-sync-wait flake ([#285](https://github.com/snapotter-hq/snapotter/issues/285)) ([dba8a85](https://github.com/snapotter-hq/snapotter/commit/dba8a85a8013231945741a8fabd09ed86db0d963))
* **jobs:** strip internal paths from all worker SSE error frames ([fc718c1](https://github.com/snapotter-hq/snapotter/commit/fc718c168487de1213c978797c3fc84288f26513))
* **landing:** add www redirect, noindex JS chunks, and website badge ([47b6984](https://github.com/snapotter-hq/snapotter/commit/47b6984be0c8d8de07e0770a34d61a9795b71eaf))
* **lint:** biome-format tool-factory and json-xml to green apps/api lint ([#252](https://github.com/snapotter-hq/snapotter/issues/252)) ([7865339](https://github.com/snapotter-hq/snapotter/commit/7865339fc8c3b8696af5919212ddba4120c07f23)), closes [#251](https://github.com/snapotter-hq/snapotter/issues/251)
* **lint:** clear remaining biome errors (unused code, optional chains, non-null assertions, effect deps) ([19dc6ba](https://github.com/snapotter-hq/snapotter/commit/19dc6ba554a05f531db01f23ce3e71297f651f81))
* **lint:** make husky hook executable; rename backend useS3 to isS3Enabled (clears 17 false-positive useHookAtTopLevel) ([7561f2a](https://github.com/snapotter-hq/snapotter/commit/7561f2a8c3a92c412f0d38b9f1323aa8bcfcf4a4))
* **lint:** resolve [#280](https://github.com/snapotter-hq/snapotter/issues/280) Lint failures (route formatting + landing import sort) ([6e1b9cd](https://github.com/snapotter-hq/snapotter/commit/6e1b9cd3cc3b33b18724eb071f3ad4023ab1ee80))
* make search bar full-width to align with tabs and grid ([207c1c3](https://github.com/snapotter-hq/snapotter/commit/207c1c348be5af23c793a96bf07b9f7b7c26ce31))
* **media:** encode gif-to-video WebM as yuv420p ([e96c314](https://github.com/snapotter-hq/snapotter/commit/e96c314ab9b049c3b01d49ff2622d2a351962cd9))
* **migrator:** correct and harden the 1.x to 2.0 SQLite import ([#434](https://github.com/snapotter-hq/snapotter/issues/434)) ([dadf766](https://github.com/snapotter-hq/snapotter/commit/dadf76689933faa8208de9730525409e2497518f))
* **nightly:** de-flake matrix timeouts, exclude browser tool from fuzz ([#349](https://github.com/snapotter-hq/snapotter/issues/349)) ([bbad953](https://github.com/snapotter-hq/snapotter/commit/bbad953e79a132007490c17dab2b774c4b8ae697)), closes [#347](https://github.com/snapotter-hq/snapotter/issues/347)
* **nightly:** qpdf in test image, NUL-byte settings, AI sub-path fuzz exclude ([#348](https://github.com/snapotter-hq/snapotter/issues/348)) ([078743d](https://github.com/snapotter-hq/snapotter/commit/078743d6b28aa4078f213cae4c39a3b99e515d8d)), closes [#346](https://github.com/snapotter-hq/snapotter/issues/346) [#346](https://github.com/snapotter-hq/snapotter/issues/346)
* **normalize-audio:** preserve source sample rate after loudnorm ([#248](https://github.com/snapotter-hq/snapotter/issues/248)) ([1548d47](https://github.com/snapotter-hq/snapotter/commit/1548d475ca3d1ace0f14d24ecc5e9a13ca5770a2))
* offline CodeFormer face-enhance (ship RealESRGAN_x2plus in upscale-enhance bundle) ([#433](https://github.com/snapotter-hq/snapotter/issues/433)) ([cf884b5](https://github.com/snapotter-hq/snapotter/commit/cf884b52cdf4e8852e0cd24215b22ed2220230da))
* **passport-photo:** require the face-detection bundle, not just background-removal ([#329](https://github.com/snapotter-hq/snapotter/issues/329)) ([32c1192](https://github.com/snapotter-hq/snapotter/commit/32c1192d635898012af2ff14cdbd68c0acd6a3e1)), closes [#327](https://github.com/snapotter-hq/snapotter/issues/327) [#327](https://github.com/snapotter-hq/snapotter/issues/327)
* PDF tool QA sweep - library auto-save versioning, AI fileId threading, modality polish ([#251](https://github.com/snapotter-hq/snapotter/issues/251)) ([08961fc](https://github.com/snapotter-hq/snapotter/commit/08961fcc8941bada2608e386bfa6d6b12e996f35))
* post-2.0 audit bug fixes (404 route, worker logging, outpaint gate, pandoc path) ([2bd3e23](https://github.com/snapotter-hq/snapotter/commit/2bd3e2302ad11b306971d0f651f8ad1ee1e9b785))
* prevent double scrollbar by locking html/body overflow ([914ff1b](https://github.com/snapotter-hq/snapotter/commit/914ff1b1aab345237f325cd152bd3ebc693bab52))
* preview generation works for processed results too ([b93dc95](https://github.com/snapotter-hq/snapotter/commit/b93dc95bcaa197cfd4b29c030a04decaa7babcf8))
* QA sweep - tool routes, security, i18n, a11y, + AI bundle install hardening ([#393](https://github.com/snapotter-hq/snapotter/issues/393)) ([b37faed](https://github.com/snapotter-hq/snapotter/commit/b37faed95fc3d2f51c78f40954fdbb5c7b94779d)), closes [hi#resolution](https://github.com/hi/issues/resolution) [hi#severity](https://github.com/hi/issues/severity)
* reassign 4 tools to correct display modes ([619f61b](https://github.com/snapotter-hq/snapotter/commit/619f61b4700c9fd3b21f90b7c9512672fae57dab))
* release-acceptance QA follow-ups (upload crash, scipy ABI conflict, rate limit, OCR fallback) ([#458](https://github.com/snapotter-hq/snapotter/issues/458)) ([60d01ab](https://github.com/snapotter-hq/snapotter/commit/60d01ab2ddfad4bf837d30369c2f39e9734cb571)), closes [#413](https://github.com/snapotter-hq/snapotter/issues/413) [#437](https://github.com/snapotter-hq/snapotter/issues/437)
* remove all legacy redirects from routes ([fd26fa3](https://github.com/snapotter-hq/snapotter/commit/fd26fa35868b75ca7fd352115396ec9b23dd4280))
* remove automatic third-party egress of user data + optional strict offline mode (OSM tiles, Scalar fonts, editor fonts, AI model downloads) ([#422](https://github.com/snapotter-hq/snapotter/issues/422)) ([6e3a14e](https://github.com/snapotter-hq/snapotter/commit/6e3a14ec6bfc15f18aef3c7aa20cde6d4823dc29))
* remove double scrollbar on home page ([ae95976](https://github.com/snapotter-hq/snapotter/commit/ae959760e3fec115021e2ada7af579ecd13f181c))
* remove duplicated 1.x migration callout in README ([#456](https://github.com/snapotter-hq/snapotter/issues/456)) ([2a899ef](https://github.com/snapotter-hq/snapotter/commit/2a899ef9041c3c637380a91e532273a3581a19d1)), closes [#448](https://github.com/snapotter-hq/snapotter/issues/448) [#454](https://github.com/snapotter-hq/snapotter/issues/454)
* remove redundant Getting Started section from home page ([287f6f1](https://github.com/snapotter-hq/snapotter/commit/287f6f15ded4b84e9d0f019522915ccac822d083))
* repair docker validation QA tooling, dispatcher crash-accounting, and image-enhancement RAW hang ([#391](https://github.com/snapotter-hq/snapotter/issues/391)) ([bd1838e](https://github.com/snapotter-hq/snapotter/commit/bd1838e40b0d11715eaf9eff6b4152a707a29b5b))
* repair URL import (DNS-pinned fetch on Node 22 + non-image modalities) ([#246](https://github.com/snapotter-hq/snapotter/issues/246)) ([8f6312c](https://github.com/snapotter-hq/snapotter/commit/8f6312c521246215ef1a27c65475aa2005e409e0))
* resolve 18 QA-discovered bugs across tools, previews, and the AI pipeline ([#242](https://github.com/snapotter-hq/snapotter/issues/242)) ([d8cf979](https://github.com/snapotter-hq/snapotter/commit/d8cf979d4ba31b802c254f7eeb5ef50b424a56b7))
* resolve 6 bugs from enterprise audit (SIEM cursor, legal hold join, SCIM role, GDPR self-purge, export OOM, quota check) ([7f62b1b](https://github.com/snapotter-hq/snapotter/commit/7f62b1bf12d2cf1baaf5586b201458eab100a111))
* resolve hardcoded /app paths and loosen mediapipe pin for native installs ([60e3ac2](https://github.com/snapotter-hq/snapotter/commit/60e3ac2210f93a350729246cf2b4bb303ab2ebc7)), closes [community-scripts/ProxmoxVE#14720](https://github.com/community-scripts/ProxmoxVE/issues/14720)
* resolve Sharp 0.35.1 and BullMQ type incompatibilities after dep bumps ([b76dc68](https://github.com/snapotter-hq/snapotter/commit/b76dc68682c664d4c6a22cf921e786d4c010b757))
* Save to Files shows green success state with checkmark after saving ([f4061fe](https://github.com/snapotter-hq/snapotter/commit/f4061fe4b0417ba896de138a791cfc869d3b33f3))
* **security:** basename-sanitize file-preview paths (CodeQL js/path-injection) ([7a3b4e6](https://github.com/snapotter-hq/snapotter/commit/7a3b4e6b3bbdee7c382bd4ad739485b37bb45f46))
* **security:** close file-preview path-injection + tighten subtitle detection ([c1cd871](https://github.com/snapotter-hq/snapotter/commit/c1cd8712f45d9defd5321f2d683cf207ee9d3740))
* **security:** close remaining high-severity CodeQL alerts ([bdadb84](https://github.com/snapotter-hq/snapotter/commit/bdadb843d8238d738e9f849f1754765f5de82411)), closes [hi#severity](https://github.com/hi/issues/severity)
* **security:** explicit per-route rate limits (CodeQL js/missing-rate-limiting) ([ae4fc1d](https://github.com/snapotter-hq/snapotter/commit/ae4fc1decf006b15a2f747cde07d4c1e35c5de13))
* **security:** harden auth and outbound fetches ([c6319cf](https://github.com/snapotter-hq/snapotter/commit/c6319cf8a9efe8745a29339613002c22f82e5393))
* **security:** harden rate limits, Redis auth, resource caps, and error sanitization ([d612264](https://github.com/snapotter-hq/snapotter/commit/d61226496b5745ff7f57ee8138009d4f81826095))
* **security:** numeric CIDR matching for IPv6 SSRF allow/deny ([f75cc32](https://github.com/snapotter-hq/snapotter/commit/f75cc328acd18b4714291400ac348058db6d28d8))
* send auth token with preview generation request ([6090688](https://github.com/snapotter-hq/snapotter/commit/609068870842629e085a77d9d5144c5102beae19))
* set a writable HOME for the app user so PaddleOCR works in non-root deployments ([#430](https://github.com/snapotter-hq/snapotter/issues/430)) ([e0dbf2a](https://github.com/snapotter-hq/snapotter/commit/e0dbf2a5c3cc9622218d31698452697957936e00))
* settings dialog and settings API correctness bugs ([8e9452e](https://github.com/snapotter-hq/snapotter/commit/8e9452e65073c500098fde040ce021e3b1c39639))
* show all tools on All tab, remove Popular and Browse sections ([b166f47](https://github.com/snapotter-hq/snapotter/commit/b166f47de515739d87a14ae408a351f81dd37c00))
* show image viewer for video-to-gif/webp results instead of broken video player ([90acd5b](https://github.com/snapotter-hq/snapotter/commit/90acd5bcd905f461f28a5b511c619d896d4a6724))
* show modality starting points in landing command center ([#387](https://github.com/snapotter-hq/snapotter/issues/387)) ([852f6ce](https://github.com/snapotter-hq/snapotter/commit/852f6cecba106eb9d000f95fc1ae9863157a5d3b))
* show tool-specific accepted formats in dropzone, remove privacy note ([5241ccd](https://github.com/snapotter-hq/snapotter/commit/5241ccd1247bda2d9e634576354f3b14a4077c63))
* sort enterprise exports for Biome lint compliance ([3b7f44e](https://github.com/snapotter-hq/snapotter/commit/3b7f44e50e450bff62560b9f21cb12330b0b2b82))
* stamp SnapOtter as Producer on generated PDFs ([#416](https://github.com/snapotter-hq/snapotter/issues/416)) ([8b3f1e6](https://github.com/snapotter-hq/snapotter/commit/8b3f1e6884361ef080c0165059bd8fdb4a14fd79))
* sync demo theme with app ([f6f7b5a](https://github.com/snapotter-hq/snapotter/commit/f6f7b5a4bc2867f680441a91a9af9e1bd148edf4))
* test server registration gaps, Redis subscriber cleanup, atomic settings upsert ([954cfb0](https://github.com/snapotter-hq/snapotter/commit/954cfb01a657ec49293a4e10e72e23eb69e4d9b2))
* **test:** align analytics-env test with ANALYTICS_ENABLED=true default ([96764ec](https://github.com/snapotter-hq/snapotter/commit/96764ec375189ebec396d0397b116407bfd75e05))
* **test:** mock db/index.js in unit tests that import API modules ([5b3b3c7](https://github.com/snapotter-hq/snapotter/commit/5b3b3c76329d62636c886dfa798b9e14acd7cc90))
* **test:** repair integration suite after analytics column/endpoint removal ([#340](https://github.com/snapotter-hq/snapotter/issues/340)) ([6917a8b](https://github.com/snapotter-hq/snapotter/commit/6917a8b0c7864fc9b244ecda23dcdbcbf02f9733)), closes [#336](https://github.com/snapotter-hq/snapotter/issues/336)
* **test:** resolve CI failures from the overhaul ([34b006d](https://github.com/snapotter-hq/snapotter/commit/34b006ded772b96d7b4336e5ffcc67e1039253c3))
* **tests:** section-prefix tool API URLs across overhauled suite ([d4dc2ea](https://github.com/snapotter-hq/snapotter/commit/d4dc2eae5db66b098d8a4e735ab61053ddb50635)), closes [#280](https://github.com/snapotter-hq/snapotter/issues/280)
* **test:** update import paths for cleanup.test.ts after move to integration ([78679c5](https://github.com/snapotter-hq/snapotter/commit/78679c57f46d11d89dcb384373a63e28e1a75635))
* **tools:** honest content-type for edit-metadata pass-through ([#350](https://github.com/snapotter-hq/snapotter/issues/350)) ([88af8d4](https://github.com/snapotter-hq/snapotter/commit/88af8d46fb001dd019de54e48dd7c73c5feaea73))
* **tools:** surface chars count in pdf-to-text result payload ([3c44335](https://github.com/snapotter-hq/snapotter/commit/3c4433583b836e53ee2a35b79c8d9be07760992e))
* top nav respects dark mode theme ([43b1901](https://github.com/snapotter-hq/snapotter/commit/43b190134e8858301fa3bffd1882260d6928c441))
* **ui:** constrain preview dropzone height in pipeline builder ([931e15a](https://github.com/snapotter-hq/snapotter/commit/931e15a6bd04fc84d236b41dbbd7df0feefe29a9))
* **ui:** show repair UI when AI bundle models are broken ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([edea82b](https://github.com/snapotter-hq/snapotter/commit/edea82ba27cd92aa5188144e525f9889b6ba1b9d))
* update privacy policy to reference PostgreSQL instead of SQLite ([5af1ac4](https://github.com/snapotter-hq/snapotter/commit/5af1ac4dcf0c8ff17bdcc0efc6c179afc8543168))
* use media-player for all video/audio tools that had no-comparison or side-by-side ([69300b5](https://github.com/snapotter-hq/snapotter/commit/69300b5c83f43ebde213473f66d9f255e33cf9dc))
* use processedFileName fallback for non-native format detection after processing ([14ded6f](https://github.com/snapotter-hq/snapotter/commit/14ded6fbd0babb43de8a544527bb2293b9d83b2d))
* validate non-image inputs by modality (batch + pipeline) ([#244](https://github.com/snapotter-hq/snapotter/issues/244)) ([03e7123](https://github.com/snapotter-hq/snapotter/commit/03e71236f93853e28d7ad8428fe8a9b918849773))
* **web:** add modality to fuse search keys, merge docs+files in fullscreen grid ([3114323](https://github.com/snapotter-hq/snapotter/commit/3114323d07a941cfcb261bc245250a8f3f6e8222))
* **web:** point tool keyboard shortcuts at section routes ([0689ae5](https://github.com/snapotter-hq/snapotter/commit/0689ae554fa353a231f01e4dffd3ac362afcb3ba))
* **web:** resolve feature install status sync and mutual exclusivity ([#214](https://github.com/snapotter-hq/snapotter/issues/214)) ([492da82](https://github.com/snapotter-hq/snapotter/commit/492da820f8ce298addd3038dad2f55e91cdb12bd))
* **web:** restore preview panel rendering for all file types ([1181b1f](https://github.com/snapotter-hq/snapotter/commit/1181b1fe22c7f5a998f8954f9e02a184a3513cf8))
* **web:** show modality thumbnails for non-image files in the strip ([#245](https://github.com/snapotter-hq/snapotter/issues/245)) ([aa3ae6e](https://github.com/snapotter-hq/snapotter/commit/aa3ae6ec915821d664cef0c1537e2b64d9a6fcee))
* **web:** update dropzone to accept all file types, not just images ([b8b6b0a](https://github.com/snapotter-hq/snapotter/commit/b8b6b0a44ada1670e4e41bcf6cd22f713d14c512))
* **web:** wrap modality tabs to prevent overflow in narrow sidebar ([dab31d6](https://github.com/snapotter-hq/snapotter/commit/dab31d6e32c7eee95199d7a686d507a98d58138f))
### Features
* add a Keep it free sponsor button to the top nav ([#427](https://github.com/snapotter-hq/snapotter/issues/427)) ([7b04317](https://github.com/snapotter-hq/snapotter/commit/7b04317ed20e062c273fe60a19cdcaac2b50e651))
* add AES-256-GCM encryption at rest for sensitive settings ([2520cdd](https://github.com/snapotter-hq/snapotter/commit/2520cdd556c8a5946b4eb6426aebc8811944e8d9))
* add audio waveform visualization with wavesurfer.js ([d8a8e05](https://github.com/snapotter-hq/snapotter/commit/d8a8e055906eeab9d1f9a048c4f8d5517cff8f80))
* add backup status tracking endpoints ([2aea351](https://github.com/snapotter-hq/snapotter/commit/2aea351f70cfd171befad164bc553e7feb998884))
* add bundle build script for CI ([52b9405](https://github.com/snapotter-hq/snapotter/commit/52b940585afa1788119dc50f6d44e98f32192ad3))
* add CI workflow for building and publishing AI bundles ([7dabfe2](https://github.com/snapotter-hq/snapotter/commit/7dabfe293dd171bb7b7ec6909ced85b178e67961))
* add Cmd+Enter (process) and Cmd+S (download) keyboard shortcuts ([7c9ca85](https://github.com/snapotter-hq/snapotter/commit/7c9ca85952bc155580becc8f95125482875a3ed5))
* add enterprise Phase 1-4 feature flags and new permissions ([86d6f50](https://github.com/snapotter-hq/snapotter/commit/86d6f50ea6696032bed8f24ba0fd58fe54af5887))
* add full-width dropzone state and tool branding to tool page ([f2ac057](https://github.com/snapotter-hq/snapotter/commit/f2ac05747e1f3ffde4f2e3b3bf321237ef699e85))
* add GET /api/v1/tools/popular endpoint ([1107005](https://github.com/snapotter-hq/snapotter/commit/110700520cfaf4c70e54ff11e7cdee7f7cf50f66))
* add landing tool command center ([#386](https://github.com/snapotter-hq/snapotter/issues/386)) ([3b1d484](https://github.com/snapotter-hq/snapotter/commit/3b1d484b4d4cc9e9da843ceeb442c6dbf7c8066c))
* add OpenTelemetry distributed tracing (enterprise) ([#232](https://github.com/snapotter-hq/snapotter/issues/232)) ([3fb8164](https://github.com/snapotter-hq/snapotter/commit/3fb8164fa539ef952fddcef89bcec01097db991e))
* add page-level drop overlay and paste handler on tool page ([6ea515c](https://github.com/snapotter-hq/snapotter/commit/6ea515ccdd7cd35f3727d0cf4137b81e9bdea050))
* add per-tool permission model with category and per-tool modes ([9fa23f4](https://github.com/snapotter-hq/snapotter/commit/9fa23f454322808d8c791b9d26b6bdbd1a5e9e73))
* add per-user rate limiting and concurrent job limits ([239f85f](https://github.com/snapotter-hq/snapotter/commit/239f85f098c5c6d3576531e915f57f6128bec357))
* add PostHog customer feedback ([649e65b](https://github.com/snapotter-hq/snapotter/commit/649e65b035c6efbfbe32e4b1db040aa0f9f6ac81))
* add recent tools tracking via localStorage ([6c61ae4](https://github.com/snapotter-hq/snapotter/commit/6c61ae47f496b1aaf937228fe7c55058b0b0756f))
* add request correlation IDs to audit logs and response headers ([1cf1f47](https://github.com/snapotter-hq/snapotter/commit/1cf1f47d6f0554853a501ae1220dbdc0678820cb))
* add session idle timeout and concurrent session limit ([3cc4ef6](https://github.com/snapotter-hq/snapotter/commit/3cc4ef6895ddfc904252e4e99c48d5df41b4c17e))
* add settings slide-in, review panel with size delta, start-over preserving settings ([45121c1](https://github.com/snapotter-hq/snapotter/commit/45121c1a1e8f8f4ab8cbf9601c50faf4a2237803))
* add Sign PDF tool (draw/type/upload signatures, place on a PDF) ([#370](https://github.com/snapotter-hq/snapotter/issues/370)) ([0cdd560](https://github.com/snapotter-hq/snapotter/commit/0cdd560ac46827f7e103e9f1921aec58d226a7db))
* add storage usage tracking with DB counters and reconciliation ([aaa8a37](https://github.com/snapotter-hq/snapotter/commit/aaa8a37c9b3b490a8455311be89a0bd4b858a897))
* add team-level storage quotas with enforcement on upload and save ([d064286](https://github.com/snapotter-hq/snapotter/commit/d0642865590a56769adbc2d7bc6741a12800af52))
* add TopNav and AvatarDropdown components ([f79958a](https://github.com/snapotter-hq/snapotter/commit/f79958a6229015ad64149dadc1fe27909f314a57))
* add usage onboarding survey overlay ([#388](https://github.com/snapotter-hq/snapotter/issues/388)) ([a0d1c70](https://github.com/snapotter-hq/snapotter/commit/a0d1c70172f24af0d4656b6256fc1bfcb9256e69))
* add webhook delivery module with retry and backoff ([ab88b9a](https://github.com/snapotter-hq/snapotter/commit/ab88b9ad0d9104ae69862309f9d2b35c0251d6bc))
* **ai:** add a Reset AI Environment admin feature for the upgrade gap ([#459](https://github.com/snapotter-hq/snapotter/issues/459)) ([fb96cf8](https://github.com/snapotter-hq/snapotter/commit/fb96cf874364b331f152d414b69f8831d0004d07))
* All tab groups tools by modality with collapsible sections ([e7126f9](https://github.com/snapotter-hq/snapotter/commit/e7126f92931e1c0277aca6c56ef06276d961ef64))
* all-in-one embedded single-container mode ([#377](https://github.com/snapotter-hq/snapotter/issues/377)) ([084a9c9](https://github.com/snapotter-hq/snapotter/commit/084a9c9faa48a0b090b1d74be97297a3d5d6f727))
* **analytics:** build-time bake + telemetry depth ([#336](https://github.com/snapotter-hq/snapotter/issues/336)) ([5d36ac0](https://github.com/snapotter-hq/snapotter/commit/5d36ac06d88fc4ca3dbf48294c132249921207d9))
* **analytics:** inject Sentry DSN + PostHog key from build env ([#367](https://github.com/snapotter-hq/snapotter/issues/367)) ([9819c58](https://github.com/snapotter-hq/snapotter/commit/9819c5885eab3ea9857dc3b4ca4465fb4b0994f9)), closes [#336](https://github.com/snapotter-hq/snapotter/issues/336)
* **analytics:** upload web source maps to Sentry + tie release to build ([#369](https://github.com/snapotter-hq/snapotter/issues/369)) ([1c202c6](https://github.com/snapotter-hq/snapotter/commit/1c202c6ef08943f05d31fd4d83dff817e1c1503b))
* **api:** section-prefix all custom tool route literals ([10bb73f](https://github.com/snapotter-hq/snapotter/commit/10bb73ffc116814f4dc6ba9c33ed32d8d32d912d))
* **api:** section-prefix factory + batch routes via apiToolPath (+section validation) ([68dd7da](https://github.com/snapotter-hq/snapotter/commit/68dd7dabaa7a9e6d87017b257b5c8cb0f34ae90e))
* arrow key navigation in Files list ([52693fc](https://github.com/snapotter-hq/snapotter/commit/52693fc843143b9ac2d788fb9b5321ee3a52409f))
* **audit:** add TOOL_EXECUTED logging with opt-in setting ([36f083b](https://github.com/snapotter-hq/snapotter/commit/36f083ba64bfa2063c724223c3d59ffadb626cb5))
* **audit:** capture IP address, make TRUST_PROXY configurable ([5d2f520](https://github.com/snapotter-hq/snapotter/commit/5d2f520d7823969578945acfd3e6799bfd6ff3f7))
* **audit:** extensible event type system with shared constants ([37b2b9c](https://github.com/snapotter-hq/snapotter/commit/37b2b9c2eef0e2926dbee03f6b24f16eb53f544e))
* **automate:** make the pipeline builder fully multi-modal ([#335](https://github.com/snapotter-hq/snapotter/issues/335)) ([a53038e](https://github.com/snapotter-hq/snapotter/commit/a53038ed9610a964090a98f6973a25449a1e4a9f))
* bump feature manifest to v2 with archive metadata ([a4ac7cf](https://github.com/snapotter-hq/snapotter/commit/a4ac7cf7d66240f64fc7c394711a4ab5b5036056))
* **ci:** add verify job to ai-bundles workflow ([7d09927](https://github.com/snapotter-hq/snapotter/commit/7d099274c120c28845ab40fa8b00754015552901))
* **ci:** add verify-bundle.sh for AI bundle smoke testing ([5ee948d](https://github.com/snapotter-hq/snapotter/commit/5ee948d36a998f8a39b92d31cc9e3def331535e8))
* clean preview button with progress bar, add document preview support ([3decfaa](https://github.com/snapotter-hq/snapotter/commit/3decfaae3ea0180415851cacfc88674b50418c01))
* clean tool page nav, add Import from Files on dropzone ([b5eef64](https://github.com/snapotter-hq/snapotter/commit/b5eef644e3c932b18884141055b65a7904d57665))
* copy-primary for data tools, download-all label for multi-output, batch failure display ([bc3ad2b](https://github.com/snapotter-hq/snapotter/commit/bc3ad2b008e789b92597688923690f28d5cf54ed))
* **db:** add audit integrity/requestId columns, user_preferences table, audit indexes ([cafd2d8](https://github.com/snapotter-hq/snapotter/commit/cafd2d8b6547eccdb9735acf344207534c13aeae))
* **db:** add data lifecycle columns (deleteAfter, legalHold, quotas, retention) ([7e5843c](https://github.com/snapotter-hq/snapotter/commit/7e5843cd403b2d59d844d5a1d8d3a9ccb0618899))
* **db:** add identity columns (lastActivity, toolPermissions, TOTP) ([7ed043e](https://github.com/snapotter-hq/snapotter/commit/7ed043ec5301106ad64ec0accc7ce411d818a469))
* disable auto-save, add Save to Files button, accept all file types in library ([d0795b6](https://github.com/snapotter-hq/snapotter/commit/d0795b69eaecf61cdb65377ee5561fca64c1de26))
* **docs:** Two-Doors home, otter-orange brand, Pagefind search, and enterprise SSO/SCIM/roles guides ([91ac583](https://github.com/snapotter-hq/snapotter/commit/91ac583e873d70fed01ecdb337c60a0234ebdc1d))
* **enterprise:** add audit log archival with crash-safe state machine ([c1dc27f](https://github.com/snapotter-hq/snapotter/commit/c1dc27f2484120f7f4571c8472fccd292e43f259))
* **enterprise:** add audit log export endpoint (CSV/JSON) ([913dd6b](https://github.com/snapotter-hq/snapotter/commit/913dd6bbe1518e7b709dd002329417789e103f49))
* **enterprise:** add configuration export/import with dry-run and dependency validation ([0f883fe](https://github.com/snapotter-hq/snapotter/commit/0f883fe853fb818275bcdb44248f99e24ca33083))
* **enterprise:** add GDPR user data export (async) ([b6a8226](https://github.com/snapotter-hq/snapotter/commit/b6a82268377bc331e38e65dcf80fe60aec6a2ff2))
* **enterprise:** add GDPR user/team data purge with audit redaction ([dd2a507](https://github.com/snapotter-hq/snapotter/commit/dd2a50799a255a05e732de5943a7481b91b2c86d))
* **enterprise:** add IP allowlisting with CIDR matching and Redis cache ([db6f7bf](https://github.com/snapotter-hq/snapotter/commit/db6f7bf38af677f896a69ea75c2cd68ec05bffb7))
* **enterprise:** add legal hold with cleanup bypass ([fa7da7c](https://github.com/snapotter-hq/snapotter/commit/fa7da7ce0c3bf480a59b429c1ad39ab23fe7cf18))
* **enterprise:** add per-team retention overrides with deleteAfter ([b60f550](https://github.com/snapotter-hq/snapotter/commit/b60f550b3fa54c4b10681e6281e989678b6c955a))
* **enterprise:** add SAML 2.0 SSO with SP-initiated login ([54132d1](https://github.com/snapotter-hq/snapotter/commit/54132d1833439425825954c4c55fba7975e24d0a))
* **enterprise:** add SCIM 2.0 provisioning (Users + Groups) ([a1b5c6d](https://github.com/snapotter-hq/snapotter/commit/a1b5c6d2c30c8a195a17b534a18c5fb93733135a))
* **enterprise:** add SIEM webhook forwarding with circuit breaker ([d3f30a2](https://github.com/snapotter-hq/snapotter/commit/d3f30a2f5d1d846bb4d56a3d2f0c208065258ba8))
* **enterprise:** add SSO enforcement mode with break-glass admin ([0c4468a](https://github.com/snapotter-hq/snapotter/commit/0c4468a004c228e860912dd8e3e662d270d3d113))
* **enterprise:** add tamper-resistant audit mode with HMAC integrity ([895e29e](https://github.com/snapotter-hq/snapotter/commit/895e29e93fb141a279dcd090ad0199f248faed2f))
* **enterprise:** add TOTP MFA with enrollment, verification, and recovery codes ([1787be3](https://github.com/snapotter-hq/snapotter/commit/1787be35fe4b6d3b1f313511cc36c2277df64034))
* **enterprise:** add unified webhook system with admin alerts ([d86e458](https://github.com/snapotter-hq/snapotter/commit/d86e4585e4e1069fa95aa49de951827fbdccf8f3))
* **enterprise:** add upgrade management endpoints (version, migrations, readiness) ([03e12e6](https://github.com/snapotter-hq/snapotter/commit/03e12e6f0b92308dc311a33a848cf09cd7e74bfd))
* expand alternatives comparisons ([#384](https://github.com/snapotter-hq/snapotter/issues/384)) ([174001d](https://github.com/snapotter-hq/snapotter/commit/174001d3844172fbc8d7dad8282ef1d83a8e4d7f))
* expand Prometheus metrics with request duration, storage, and auth counters ([fb14f41](https://github.com/snapotter-hq/snapotter/commit/fb14f41512e8d65417b6a7dee129d48f05285459))
* extend crash recovery for pre-built bundle artifacts ([d1e9536](https://github.com/snapotter-hq/snapotter/commit/d1e9536cffb7a53a291627bd36d173d850082a41))
* extend health endpoints with disk space, S3, storage, and backup checks ([6237684](https://github.com/snapotter-hq/snapotter/commit/6237684ec86289fdfab5ed982dd2af6a9a5e37d1))
* extend importBundleArchive for site-packages and fixups ([5d5240e](https://github.com/snapotter-hq/snapotter/commit/5d5240e48131653e3a64917fae312a044326992c))
* **feedback:** always-on nav button with GitHub/email handoff when analytics is off ([#428](https://github.com/snapotter-hq/snapotter/issues/428)) ([5dcc06a](https://github.com/snapotter-hq/snapotter/commit/5dcc06a99ea18a6b5448b3a7a1e54b40158c8b07))
* **feedback:** route failed-run Report issue through the offline handoff ([#429](https://github.com/snapotter-hq/snapotter/issues/429)) ([8cdd85a](https://github.com/snapotter-hq/snapotter/commit/8cdd85a49339c2cce3c916b756e4c6da1fe2abfc))
* filter files by modality when importing from tool page ([826f1ef](https://github.com/snapotter-hq/snapotter/commit/826f1efc087d1708ee1171b145f710e57a9d7ed2))
* **i18n:** add repair UI strings for broken AI bundles ([8e15fe7](https://github.com/snapotter-hq/snapotter/commit/8e15fe7a3f633771ba05e1b4cb2f3eae15b5bed0))
* **i18n:** raise translation coverage across all 20 locales ([#332](https://github.com/snapotter-hq/snapotter/issues/332)) ([ffbf4f9](https://github.com/snapotter-hq/snapotter/commit/ffbf4f9e10f5e8f4fde9be286e0e7a024dde7a15))
* **i18n:** raise translation coverage across all 20 locales (round 2) ([#453](https://github.com/snapotter-hq/snapotter/issues/453)) ([44e1f90](https://github.com/snapotter-hq/snapotter/commit/44e1f90e4a847b7059869cd5750280f472ef3a05)), closes [#428](https://github.com/snapotter-hq/snapotter/issues/428) [425/#426](https://github.com/snapotter-hq/snapotter/issues/426)
* Import from Files works, remove pipeline button from files page ([b8a6b20](https://github.com/snapotter-hq/snapotter/commit/b8a6b2018ed1736ab4f9f234b435bce666c10d90))
* inline error messages with recovery actions ([56cd843](https://github.com/snapotter-hq/snapotter/commit/56cd843482ab93d59f26fc360fa48d11f161c815))
* **landing,docs:** SEO fixes and query-matched tool pages ([#383](https://github.com/snapotter-hq/snapotter/issues/383)) ([ec98dfd](https://github.com/snapotter-hq/snapotter/commit/ec98dfde9a63590f513c1448a18a57f836ad1515))
* **landing:** add animated shadergradient hero background ([#411](https://github.com/snapotter-hq/snapotter/issues/411)) ([5500fac](https://github.com/snapotter-hq/snapotter/commit/5500facc5d8d38437bd976663a10b41ba71bee10))
* **landing:** auto-refresh live GitHub stars and image-pull stats ([#292](https://github.com/snapotter-hq/snapotter/issues/292)) ([33671d2](https://github.com/snapotter-hq/snapotter/commit/33671d2d9227ffbb3580e8b7d40fd260c06d7853))
* **landing:** enterprise-focused hero redesign and section polish ([#239](https://github.com/snapotter-hq/snapotter/issues/239)) ([f622a4f](https://github.com/snapotter-hq/snapotter/commit/f622a4f691dce066adcc31bd8838b1f4014b92e0))
* **landing:** generate 301 redirects for old tool URLs; fix robots sitemap reference ([0051655](https://github.com/snapotter-hq/snapotter/commit/0051655bbf0201642f97436adf5c3130af8131c0))
* **landing:** migrate from Next.js to Astro 5 ([8403222](https://github.com/snapotter-hq/snapotter/commit/8403222d08034362382a902feec509665cb32bcb))
* **landing:** one-command Docker quickstart + live-demo CTA in hero ([#455](https://github.com/snapotter-hq/snapotter/issues/455)) ([aaf39a1](https://github.com/snapotter-hq/snapotter/commit/aaf39a1b7221e6581b681e776513063aed39eed3))
* **landing:** refocus hero on privacy-sensitive teams ([#431](https://github.com/snapotter-hq/snapotter/issues/431)) ([8451f9b](https://github.com/snapotter-hq/snapotter/commit/8451f9be0883dc58ac4413bc00c6e6edd082a896))
* **landing:** section-nested tool routes, section index pages, and section-prefixed links ([f158be6](https://github.com/snapotter-hq/snapotter/commit/f158be6aaa1e4ce907e0abe93a20f6791168b310))
* **landing:** swap Try Demo for Get Started Free CTA in top nav ([#418](https://github.com/snapotter-hq/snapotter/issues/418)) ([ea004a3](https://github.com/snapotter-hq/snapotter/commit/ea004a3308de489efa45fa77585ec4da9da82180))
* **landing:** warm up the contact CTAs ([#412](https://github.com/snapotter-hq/snapotter/issues/412)) ([3d4a84d](https://github.com/snapotter-hq/snapotter/commit/3d4a84d06865f0d790d39fee50809633cc6892c8))
* make password policy configurable via admin settings ([8b349b0](https://github.com/snapotter-hq/snapotter/commit/8b349b0341b8cde518558c8ef83523263a95abae))
* merge PostHog customer feedback ([1d99acf](https://github.com/snapotter-hq/snapotter/commit/1d99acf9ee30e0fe9528b02761a3eed5e808f0b8))
* mobile layout for tool-first flow ([896acda](https://github.com/snapotter-hq/snapotter/commit/896acda7ed033a13817d3556c50cea35ec884c3c))
* modality-aware file preview in Files library ([a70b13a](https://github.com/snapotter-hq/snapotter/commit/a70b13ad3207617c794fd90bf5c5dcd85c4a90ec))
* modality-based URLs (/image/resize, /video/compress-video) ([ea83e1c](https://github.com/snapotter-hq/snapotter/commit/ea83e1c8b4af7e613b4a5184b7b3e816ba1f1376))
* **modality:** rename "file" modality label "Data" -> "Files" ([71fefc0](https://github.com/snapotter-hq/snapotter/commit/71fefc05b08bdfc344de6beb16963b7cc632fac2))
* move theme toggle and language selector to top nav bar ([aff9159](https://github.com/snapotter-hq/snapotter/commit/aff9159ae0ef251a5be46bbae5a8a20ede2c419a))
* on-demand preview generation with progress messages for non-native formats ([d3cd4e4](https://github.com/snapotter-hq/snapotter/commit/d3cd4e41b5c8fab1732c16243c0a6c5c46b0b63e))
* pin frequently-used tools to the top of the dashboard ([#440](https://github.com/snapotter-hq/snapotter/issues/440)) ([3aaaacc](https://github.com/snapotter-hq/snapotter/commit/3aaaacc7a1830d748a3f6602cc6a81efbc9a9f32))
* pipeline templates, analytics opt-out, 83 conversion presets, positioning + e2e modernization ([63a03d2](https://github.com/snapotter-hq/snapotter/commit/63a03d26f2f627578420dc4b7011e1078635651a)), closes [#355](https://github.com/snapotter-hq/snapotter/issues/355) [#354](https://github.com/snapotter-hq/snapotter/issues/354) [#356](https://github.com/snapotter-hq/snapotter/issues/356) [#353](https://github.com/snapotter-hq/snapotter/issues/353) [#351](https://github.com/snapotter-hq/snapotter/issues/351)
* polish home page UI -- card borders, colored icons, 3-col grid, Cmd+K hint ([ade79c5](https://github.com/snapotter-hq/snapotter/commit/ade79c53a59cd3a991224f5e82b9a6e3861457bf))
* redesign review panel action hierarchy ([ed458d4](https://github.com/snapotter-hq/snapotter/commit/ed458d4bbdfaeb7054fa15c1fbaf2616ed19f45f))
* remove /fullscreen route, add dynamic page titles ([f9ebb30](https://github.com/snapotter-hq/snapotter/commit/f9ebb304db1b71ad0e6149d094dd7f6cac8777db))
* replace sidebar with top nav bar across all pages ([71fef43](https://github.com/snapotter-hq/snapotter/commit/71fef439a0d41bce34890d637c40a670fb2ce443))
* request a tool when home search finds nothing ([#385](https://github.com/snapotter-hq/snapotter/issues/385)) ([c68297d](https://github.com/snapotter-hq/snapotter/commit/c68297d5a49e659645b510da245241aa26a40cb6))
* rewrite home page as tool-first browser with search and modality tabs ([0d751b7](https://github.com/snapotter-hq/snapotter/commit/0d751b7d143a9102b3fe24e94c4e49ce616ee310))
* rewrite install_feature.py for pre-built tar bundles ([a4fa3ce](https://github.com/snapotter-hq/snapotter/commit/a4fa3ce2a71930a8b57fd3f17181c51f703a2081))
* **scripts:** add segment-anchored tool-path rewrite transform ([c17a4a4](https://github.com/snapotter-hq/snapotter/commit/c17a4a422582594c6e2127429a7373c2e0ade11c))
* **scripts:** add tool-path codemod CLI ([0691457](https://github.com/snapotter-hq/snapotter/commit/0691457f94dd63a53285107ab56d9ba73c1b3b47))
* server-side preview generation for non-native video/audio formats ([412a21e](https://github.com/snapotter-hq/snapotter/commit/412a21ee4d9a68baadef817509a5cc1a675a5143))
* **shared:** add apiToolPath() and section-prefixed routes; drop MODALITY_URL_SLUG ([9ca901f](https://github.com/snapotter-hq/snapotter/commit/9ca901f8d5b23b0a03060b3384af58c60cfbbaa0))
* **shared:** add Section concept and toolSection() partition ([7907471](https://github.com/snapotter-hq/snapotter/commit/790747188afe4fa0347579d6ce2db80d68bcfd2b))
* tiered processing feedback and upload progress indicator ([433d59c](https://github.com/snapotter-hq/snapotter/commit/433d59c726d196c7b51ea2cc29b0e2d44fa11feb))
* tool-first workflow polish -- fix tests, lint cleanup ([f387e98](https://github.com/snapotter-hq/snapotter/commit/f387e98fff6049a4869cebd4e4d7a717e7c1f28e))
* **tools:** 2.0 phase 5 wave 2 - pdf depth (21 tools) ([#220](https://github.com/snapotter-hq/snapotter/issues/220)) ([2f39e38](https://github.com/snapotter-hq/snapotter/commit/2f39e3816209fe81fac4620dd1233921e5de90d4))
* **tools:** 2.0 phase 5 wave 3a - video depth (22 tools) ([#221](https://github.com/snapotter-hq/snapotter/issues/221)) ([5f98b48](https://github.com/snapotter-hq/snapotter/commit/5f98b485935f07e40c0a6e57548892b2e17fc03b))
* **tools:** 2.0 phase 5 wave 3b - audio depth (14 tools) ([#222](https://github.com/snapotter-hq/snapotter/issues/222)) ([638288e](https://github.com/snapotter-hq/snapotter/commit/638288e196f05d889b5d818c0c8a11b0697ec49c))
* **tools:** 2.0 phase 5 wave 4 - office, ebooks, data, archives (14 tools) ([#224](https://github.com/snapotter-hq/snapotter/issues/224)) ([fc7c1f8](https://github.com/snapotter-hq/snapotter/commit/fc7c1f850e36fd01db9f08caf574f6f48d606b93))
* **tools:** 2.0 phase 5 wave 5a - image gap-fill (11 tools) ([#225](https://github.com/snapotter-hq/snapotter/issues/225)) ([6e1b986](https://github.com/snapotter-hq/snapotter/commit/6e1b9865f10c50badddb693a09ec20557379fe63))
* **tools:** 2.0 phase 5 wave 5b - ai pool: ocr-pdf, transcription, background composites (5 tools) ([#226](https://github.com/snapotter-hq/snapotter/issues/226)) ([51666cd](https://github.com/snapotter-hq/snapotter/commit/51666cdd5fd207ceee4da38b63d998af9a044809))
* **web:** add data retention settings to admin UI ([3016571](https://github.com/snapotter-hq/snapotter/commit/3016571c2b2925e8fc7677d9d2daae2bd8191db1))
* **web:** add MFA login prompt and security settings UI ([d397f57](https://github.com/snapotter-hq/snapotter/commit/d397f576676d127ee23c49a2948b041a6a6a777e))
* **web:** add storage dashboard and team retention settings ([c7e9b1d](https://github.com/snapotter-hq/snapotter/commit/c7e9b1ddc6189f847633399a982ce88cb6ae4a85))
* **web:** apply Otter Orange design system and UI improvements ([bcd59c2](https://github.com/snapotter-hq/snapotter/commit/bcd59c20c7da6208e937cac0a9b9f02ecf73b4f1)), closes [#E07832](https://github.com/snapotter-hq/snapotter/issues/E07832) [#2563eb](https://github.com/snapotter-hq/snapotter/issues/2563eb)
* **web:** complete audit log viewer with IP column and all event types ([c6f9a29](https://github.com/snapotter-hq/snapotter/commit/c6f9a29687562c929d708a110eb0b7145c4dab11))
* **web:** fuzzy search with fuse.js for typo-tolerant tool discovery ([22cccd4](https://github.com/snapotter-hq/snapotter/commit/22cccd46c44c386aed5303efbd608105ddc1b30f))
* **web:** group home grid, tabs, and breadcrumb by section ([8301676](https://github.com/snapotter-hq/snapotter/commit/8301676e139fa0ed1d2423e133b11e0214bfe4cd))
* **web:** icon-only modality tabs, merge documents and files ([cc06c80](https://github.com/snapotter-hq/snapotter/commit/cc06c802c13b4d229fa2a97c3493aef4a555b1e6))
* **web:** in-canvas zoom & pan for the object eraser and split tools ([#320](https://github.com/snapotter-hq/snapotter/issues/320)) ([95d100c](https://github.com/snapotter-hq/snapotter/commit/95d100c20bd9b41cca3190a7791807516d2a17e4))
* **web:** modality filter tabs in sidebar tool panel ([8adceaf](https://github.com/snapotter-hq/snapotter/commit/8adceaf92d3effd8b4a2f15d6f8ecfc0f6c1ab8d))
* **web:** modality tabs on fullscreen grid page ([82fb798](https://github.com/snapotter-hq/snapotter/commit/82fb798142663b22d23bda69bf66d0d8cb56def9))
* **web:** section-prefix all tool API calls ([22b4b5c](https://github.com/snapotter-hq/snapotter/commit/22b4b5c3c17ea28712e2e9bf06ca35b6c5a23bd3))
* **web:** show icon + text labels on modality filter tabs ([888d243](https://github.com/snapotter-hq/snapotter/commit/888d243a653b7ecfab20830be2ea8baa961f8e71))
* **web:** stronger modality section visual hierarchy in tool catalog ([3db1b3b](https://github.com/snapotter-hq/snapotter/commit/3db1b3bafd9bfcde86c9d74037a30114437e4f71))
* wire AI bundle build into release pipeline ([d0732d4](https://github.com/snapotter-hq/snapotter/commit/d0732d4a586be25231be93e51e94db7ae05ae8ca))
### Reverts
* **deps:** keep rembg at 2.0.69 (2.0.75 conflicts with pinned numpy==1.26.4) ([4fdd10f](https://github.com/snapotter-hq/snapotter/commit/4fdd10f488642eabe671aa111796d343d0e2d358))
### BREAKING CHANGES
* SnapOtter 2.0 - the platform re-architecture (Postgres 17 +
Redis 8 + BullMQ durable jobs, 157 tools across five modalities) is the 2.0
release line, replacing the 1.x SQLite single-container architecture.
* SQLite is no longer the runtime database. Deployments now
require Postgres (and Redis, used from phase 2). Existing installs migrate
with SQLITE_MIGRATE_PATH or 'pnpm --filter @snapotter/api migrate:sqlite'.
* fix(ci): postgres service + fresh e2e database per run; ignore unfixable torch CVE-2025-3000
## [1.15.8](https://github.com/snapotter-hq/snapotter/compare/v1.15.7...v1.15.8) (2026-04-17)