* feat: allow multi-file selection for automation pipeline
Add two ways to import server-stored files into the pipeline:
1. Files page: "Pipeline" bulk action button and "Open in Pipeline"
button in file details panel — navigates to /automate with selected
file IDs via React Router state.
2. Automate page: "Import from Library" button opens a modal with
thumbnails, search, and multi-select checkboxes to pick files from
the user's server-stored library.
Both paths download the selected files and load them into the existing
useFileStore, reusing the batch pipeline processing infrastructure.
Closes#35
* fix: resolve 8 pre-existing test failures across unit and integration suites
- file-validation.ts: Return valid:false when Sharp fails to read
metadata for standard formats (PNG, JPEG, BMP) instead of silently
accepting corrupt buffers. CLI-decoded formats already skip Sharp.
- pipeline.ts: Enforce hard cap of 20 steps via .max() instead of
relying on MAX_PIPELINE_STEPS env var (default 0 = unlimited).
Tighten name limit to 100 chars and description to 500 chars to
match test expectations.
- env.ts: Change MAX_LOGO_SIZE_KB default from 2048 to 500 to match
the branding upload size limit the tests verify.
When auth was disabled, the backend middleware attached the first admin
user from the database to every request, and the frontend granted all 12
permissions. This gave every unauthenticated visitor full admin access
to user management, settings, teams, branding, and feature installation.
Now both layers use role "user" with user-level permissions so tools,
files, and pipelines still work without login while admin-only routes
correctly return 403.
Closes#72
Closes#73
AVIF was already supported in the core engine, convert, compress,
optimize-for-web, upscale, erase-object, svg-to-raster, and
pdf-to-image tools. This adds AVIF as an output format option to
the 6 tools that were missing it: split, collage, stitch,
image-to-base64, noise-removal, and red-eye-removal.
For each tool, both the frontend format selector (with quality
slider for AVIF's lossy encoding) and the backend Zod schema +
Sharp .avif() encoding were updated. AVIF defaults: quality from
the user slider, effort 4 (balanced encode speed).
Also fixes pre-existing Biome formatting violations in 5 files
that were blocking a clean lint pass.
The <select> for Default Tool View was an uncontrolled dead control with
no value binding, no onChange handler, and no save mechanism. This wires
it up end-to-end:
- Add defaultToolView to the Zustand settings store
- Load the persisted value from the settings API on mount
- Bind the <select> with value/onChange
- Add Save Settings button mirroring SystemSection's pattern
- Redirect home page to /fullscreen when defaultToolView is "fullscreen"
Closes#75
The connection-monitor.tsx component was referenced in App.tsx but the
file was missing, causing TypeScript compilation failure during Docker
build. This component combines the useConnectionMonitor hook with
the ConnectionBanner UI.
Phase 1 — Docker Artifact Optimization:
- Replace broad `COPY . .` with targeted frontend source copies (API/Python
changes no longer bust the frontend build cache)
- Replace build-essential with gcc/g++ (leaner runtime)
- Fix LOG_LEVEL=debug → info for production
- Harden .dockerignore (exclude worktrees, IDE, CI, test artifacts)
Phase 2 — State & Persistence:
- Add PUID/PGID support in entrypoint.sh for bind mount compatibility
- Guard against PUID=0/PGID=0 to prevent accidental root execution
- Evict conflicting system users (e.g. node:1000) before UID remap
Phase 3 — Security:
- Always register @fastify/rate-limit so login brute-force protection
works even when global rate limit is disabled (RATE_LIMIT_PER_MIN=0)
- Add trustProxy support (TRUST_PROXY env var, default true) so rate
limiting and audit logs use real client IPs behind reverse proxies
- Strip stack traces from 500 error responses in production
- Fix FSTDEP022 deprecation: maxParamLength → routerOptions
- Add multi-file guard on single-file tool endpoint with clear error
message pointing to the /batch endpoint
Phase 4 — Graceful Degradation:
- Add consolidated hardware detection startup banner (GPU, rate limit,
upload limit, proxy status)
- Add ConnectionMonitor component with health polling and reconnecting
overlay that auto-dismisses when the server comes back
Phase 5 — Deployment Docs:
- Rewrite deployment.md with copy-paste CPU and GPU compose templates
- Add hardware requirements table (minimum, recommended, heavy workloads)
- Add PUID/PGID bind mount documentation
- Add complete env var reference table
- Add reverse proxy guides for Nginx, Nginx Proxy Manager, Traefik,
and Cloudflare Tunnels
Extends the platform to handle 7 new image format families alongside
the existing AVIF support gap-fill. Uses the established HEIC decoder
pattern (CLI decode → PNG → Sharp) for formats Sharp can't handle
natively: Camera RAW via dcraw_emu/LibRaw, PSD/TGA/EXR/HDR via
ImageMagick. JXL and ICO are Sharp-native. Adds server-side preview
for non-browser-displayable formats and JXL as a new convert output
target. All 27 validateImageBuffer callers updated with filename for
extension-based format detection.
Restructure the pipeline builder UX from a cramped sidebar to a
spacious two-pane layout:
- Left pane: categorized, searchable Tool Palette (click-to-add)
- Right pane: Pipeline Canvas with sortable steps, inline action bar,
and collapsible preview panel with before/after slider
- Mobile: full-screen canvas with FAB + bottom sheet for tool selection,
image preview, and thumbnail strip (previously hidden entirely)
- Fix nested <button> HTML violation in SortableStep
- Fix stray semicolon rendering in step cards
Guard startPolling in handleOnline to only fire when transitioning from
offline state. Previously, a spurious browser online event while already
connected would start a polling interval that never gets cleared.
When lazyWithRetry exhausts all retry attempts on a chunk error, also
call setDisconnected() so the reconnecting banner appears alongside the
ErrorBoundary's "Update Available" card.
- Add "unable to preload" pattern to isChunkError for Vite CSS preload failures
- Move ConnectionMonitor and ConnectionBanner outside ErrorBoundary so they
remain visible when the error boundary catches a render crash
- Add test for CSS preload error retry
checkHealth previously ignored non-ok responses (e.g. 503), silently
doing nothing when the server reported unhealthy. Add else branch to
transition connected → disconnected on non-ok status. Add tests for
connected → disconnected on fetch failure and offline → reconnected
on health check success.
- Add 8 new E2E specs for AI tools (upscale, enhance-faces, colorize,
restore-photo, erase-object, smart-crop, passport-photo, red-eye-removal)
closing all HIGH/MEDIUM coverage gaps from the test matrix audit
- Fix ensureAiDirs() crash on non-Docker environments by gating on
isDockerEnvironment() — prevents ENOENT when /data doesn't exist
- Bump torch 2.6.0→2.7.0 and torchvision 0.21.0→0.22.0 in feature
manifest for broader Python version compatibility
- Add Python 3.14 version guard warning in install_feature.py
- Remove duplicate torchvision shims from upscale.py and enhance_faces.py
(dispatcher.py already handles this at startup)
- Remove orphaned tools.batch i18n key and dead pipeline-builder filter
- Regenerate 4 visual regression baselines for current UI state
- Add data-testid to passport-photo generate button for E2E testability
The torchvision compatibility shim for basicsr 1.4.2 was missing the
parent-package binding and only proxied a single attribute, causing
upscale and enhance-faces to fail at import time. The fix adds a
__getattr__ proxy for all attributes, binds the shim to the parent
package, and installs it in the dispatcher at startup for defense-in-depth.
Also removes unused anyInstalling variable, redundant `as any` cast,
and applies Biome formatting fixes across the codebase.
- Add tool-specific suffix to output filenames so downloads don't overwrite originals (batch & single-tool routes)
- Skip deleting shared models when uninstalling a bundle that shares models with another installed bundle
- Auto-detect NVIDIA GPU and swap GPU-only pip packages (onnxruntime-gpu, paddlepaddle-gpu) for CPU equivalents
- Refactor docker-compose with YAML anchors and explicit cpu/gpu profiles
- Add libheif-plugin-x265 to Dockerfile
- Fix install-all queue logic to handle concurrent individual installs and clear stale errors
- Unify playwright docker config to use same test dir with API_URL env var
- Fix flaky e2e selectors, rename Strip Metadata → Remove Metadata, handle collage custom dropzone, improve fallback test image generation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The store set an initial 5% optimistically, then SSE sent real progress
starting from 0%, causing the bar to visibly drop. Now progress only
moves forward — both SSE and polling paths use Math.max to never
regress below the current value.
The bottom-right install indicator showed "1/6 installed" even when
installing a single bundle, implying all 6 would be installed. Now the
counter only appears during "Install All" operations.
Replace FeatureInstallPrompt's local SSE/polling with useFeaturesStore
so install progress, errors, and recovery are handled globally — works
across navigation, logout/login, and partial downloads. Shows fun
progress messages and ETA matching the settings page.
Add compose healthcheck and optional GPU profile (--profile gpu).
Replace static "Preview not available" and "Cannot preview this image
format" messages with a loading spinner in ImageViewer and SplitCanvas,
since HEIC files get server-side conversion and the preview appears
after a few seconds. Also default showDetails to true on /fullscreen.
The home page's file-uploaded view rendered its own tool list without
checking AI feature install status, so download icons disappeared after
uploading a file. Now both Quick Actions and All Tools sections show the
download badge consistently with the sidebar ToolPanel.
Uses XMLHttpRequest upload progress to track image upload (0-80%),
then shows "Processing collage..." for the server-side compositing
phase (80-100%). Progress bar with percentage shown in the preview area.