* feat: add resolveOutputFormat utility for input format preservation
* fix: preserve file order in batch processing with X-File-Results header
Collect all results before streaming the ZIP to guarantee upload order.
Replace X-File-Order with index-based X-File-Results header that maps
each upload index to its processed filename, handling failures and
duplicate filenames correctly.
Closes#13
* fix: use X-File-Results for index-based batch file matching
The frontend now matches processed files to entries by upload index
instead of fragile name/position matching.
* feat: preserve input format in smart-crop with quality control
Smart crop now outputs in the same format as the input (JPG in, JPG out)
instead of always converting to PNG. Adds an optional quality setting
(default 95) for lossy formats.
Closes#14
* feat: add output quality slider to smart crop settings UI
* feat: preserve input format in crop tool
* feat: preserve input format in color adjustment tools
Applies to brightness-contrast, saturation, color-channels, and
color-effects tool routes.
* refactor: avoid double encode in smart-crop content mode
For the simple trim path (no pad-to-square), chain .toFormat() on the
trim pipeline directly instead of creating a second Sharp instance.
This eliminates a redundant intermediate encode that degraded quality
for lossy formats. Also use trimmed.info dimensions instead of a
separate metadata() call for the pad-to-square path.
---------
Co-authored-by: Siddharth Kumar Sah <siddharth123sk@gmail.com>
Adds a new mode that trims uniform-color borders around the subject,
like GIMP's "Crop to Content." Includes configurable tolerance threshold
and optional pad-to-square with target size for e-commerce workflows.
The original attention-based crop is preserved as "Focus Crop" mode.
Closes#7
- Health endpoint returns "healthy" instead of "ok" for consistency
- MAX_USERS now configurable via env var (default 5)
- People API returns team names instead of UUIDs in register/list
- PUT user update accepts team names (name-first lookup, fallback to ID)
- Login rate limit follows global rate limit when RATE_LIMIT_PER_MIN > 1000
- Strip-metadata preserves original format encoding instead of always PNG
- Fix e2e tests: rotate/crop/border button selectors match actual UI
- Fix e2e tests: create Engineering/Design teams in people test setup
- Fix e2e tests: people UI uses select for team field, not text input
- Update visual regression baseline for tablet home page
Worker thread initialization imports the tool registry which reads SQLite.
Under Docker volume filesystems, this can deadlock silently on SQLITE_BUSY,
causing APPLY to spin at 0% forever. Sharp operations complete in milliseconds
and don't need worker offloading. Added 30s AbortSignal timeout as defense
in depth for future re-enablement.
SVG files were rejected by the convert endpoint because
validateImageBuffer only recognized raster magic bytes. This adds
text-based SVG detection, sanitization in the tool factory, and
proper Sharp density handling so SVG-to-raster conversion works
through the standard convert route.
Validation now runs on all entries before any database writes.
Previously, clean entries could be written before a later malicious
entry triggered a 400 response.
PUT /api/v1/settings now returns 400 if any key or value contains HTML
tags. Settings are configuration values - there is no legitimate use
case for HTML in them.
Register remove-background, upscale, and blur-faces in the pipeline
tool registry via registerToolProcessFn(). These tools keep their
custom HTTP routes (with progress callbacks) for direct use, but now
also provide a simple process function for pipeline/batch execution.
Add a search bar to the pipeline tool picker so users can quickly
find tools by name or description. Uses the existing SearchBar
component and the same filtering pattern as the main tool panel.
Update tests to reflect that these 3 AI tools are now pipeline-
compatible (moved from excluded to included assertions).
The pipeline tool picker was showing all tools, but only tools
registered via createToolRoute() support pipeline execution. Tools
with custom routes (remove-background, upscale, ocr, etc.) would
silently fail with "Tool not found" and the empty catch block hid
the error from users.
Add GET /api/v1/pipeline/tools endpoint that returns the IDs of
pipeline-compatible tools. The frontend fetches this list and filters
the tool picker accordingly. Also surface pipeline execution errors
in the UI instead of swallowing them.
Remove hardcoded --platform=linux/amd64 from Dockerfile so buildx produces
native arm64 images for Apple Silicon and Raspberry Pi. Add audit logging
for auth events, harden file storage with extension whitelists and
double-extension attack prevention, reject null-byte buffers in validation,
add data-testid attributes to all tool settings components, update
deployment docs with architecture notes and correct CI workflow references,
and fix unit test mock to match throwWithMessage error extraction.
Fix face detection failure caused by MediaPipe 0.10.33 removing the
mp.solutions API. Replace with OpenCV Haar cascade which works reliably
in headless Docker. Add autoOrient() call before detection to handle
EXIF-rotated phone photos. Remove technical jargon from UI.
Fix rotated output by calling autoOrient() before passing images to
the Python upscaler, correcting EXIF orientation metadata. Replace
2x/4x buttons with 2x-8x slider plus quick-select buttons (2x, 3x,
4x, 6x, 8x). Remove technical jargon about Real-ESRGAN/Lanczos from
the UI and progress bar.
Remove docs/superpowers/, .claude/ config, and PRD.md from version
control (kept locally via .gitignore). Update README, CHANGELOG,
VitePress docs, and .env.example to reflect recent features: Files
page, teams, admin settings, persistent storage, and various API
improvements.
Add feature flag support to skip disabled/experimental tools at startup
by reading disabledTools and enableExperimentalTools from the settings
table. Refactor cleanup.ts to read tempFileMaxAgeHours from DB settings
(with env var fallback) and respect the startupCleanup setting.
Adds optional fileId multipart field; when present, inserts a new versioned
userFiles record after successful processing and returns savedFileId in the
response. Non-fatal — tool processing succeeds even if the save fails.
Implements all 7 routes for the persistent file library:
list with pagination/search, upload (multi-file), details with recursive
version chain CTE, download stream, on-the-fly Sharp thumbnail, bulk delete
of entire version chains, and save-result for tool output versioning.
Registered in index.ts after fileRoutes.
Extract EXIF auto-orientation logic into a shared auto-orient module
used by both single-tool and batch routes. This ensures camera photos
display correctly after processing regardless of entry point.
Also expands e2e and integration tests significantly.
- Remove @fastify/swagger and @fastify/swagger-ui (API docs live on GitHub Pages)
- Run typecheck, build, and docker CI jobs in parallel instead of sequentially
Samsung Galaxy phones (and others) can have GPS EXIF tags with null
coordinate values when location is disabled. The server returned
_latitude: null, and the client guard used !== undefined which passed
for null, causing null.toFixed() to crash React with no ErrorBoundary.
- Server: validate GPS array values are actual numbers before computing
- Client: use != null guard (catches both null and undefined)
- App: add ErrorBoundary to prevent white screens from any future crash
Integrates feature/multi-image-ux branch with 20 commits including:
- Multi-image viewer with arrow navigation and filmstrip thumbnails
- Batch processing across all tool settings components
- File store rewrite with FileEntry model for multi-image support
- Resize settings redesigned with tab-based UI (presets, custom, scale)
- Side-by-side comparison for resize results
- Per-file metadata caching in strip-metadata
- Client-side ZIP extraction via fflate
- SSE progress correlation via clientJobId
Consolidate all access to localhost:1349 — Vite dev server serves on 1349
and proxies API calls to an internal dev port (13490). Production API
defaults to 1349. Also includes strip-metadata improvements, UI component
updates, and compress operation fixes.
Extract clientJobId from multipart form data in all 5 AI route handlers
(remove-background, upscale, blur-faces, erase-object, ocr) and forward
progress callbacks to the SSE system via updateSingleFileProgress.
- Set up semantic-release with zero-touch CI pipeline on push to main
- Add version sync script to keep all package.json files and APP_VERSION
constant in sync automatically
- Consolidate Docker publishing into single tag-triggered workflow that
pushes to both Docker Hub and ghcr.io with semver tags
- Add help dialog with keyboard shortcuts, getting started guide, and
resource links
- Sync all versions to 0.2.1 to match Docker Hub latest
- Add user management endpoints (register, list, delete, change password)
- Add API key management (create, list, delete)
- Add settings persistence endpoints (get, put)
- Wire settings dialog to real backend (People, API Keys, System, Security)
- Fix login auth flow (window.location.href for full reload)
- Fix download URLs returning 401 (make public since UUIDs are unguessable)
- Fix border tool shadowColor validation (accept 6-8 hex digits)
- Fix remove-bg alpha matting fallback (retry without on failure)
- Fix AI tool silent fallbacks (report errors instead of no-ops)
- Add checkerboard background to before/after slider for transparency
- Add progress bars to all AI tool components
- Add Playwright E2E test suite (131 tests across 9 test files)
- Rewrite Dockerfile for production (tsx runtime, pre-baked AI models)
- Add .dockerignore for faster builds
- Add proper accessible labels to login form
Add pipelines table to SQLite schema with Drizzle migration.
Implement POST /api/v1/pipeline/execute (sequential multi-tool processing),
POST /api/v1/pipeline/save, GET /api/v1/pipeline/list,
DELETE /api/v1/pipeline/:id. Pipeline execution validates all tool IDs
and settings before processing, chains output of each step as input
to the next.
- Add replace-color tool with pixel-level color replacement and tolerance
- Register all 19 new Phase 3 tools in routes/tools/index.ts
- Map all new tool IDs to settings components in tool-page.tsx
- Add PDF, ZIP, ICO, JSON content types to download route
- Install qrcode, jsqr, potrace, pdfkit dependencies
Add 6 tools for format conversion and optimization extras:
- svg-to-raster: SVG to PNG/JPG/WebP at custom resolution
- vectorize: raster to SVG via potrace (B&W and color modes)
- gif-tools: animated GIF resize, frame extraction, optimization
- bulk-rename: pattern-based file renaming with ZIP output
- favicon: generate all favicon/app icon sizes with manifest.json
- image-to-pdf: combine images into PDF using pdfkit
Add 3 layout and composition tools with API routes and frontend settings:
- collage: multi-image grid layout with configurable gap and background
- split: image grid splitting with ZIP output (reuses archiver pattern)
- border: borders, rounded corners via SVG mask, padding, and shadows
Add 4 watermark/overlay tools with API routes and frontend settings:
- watermark-text: SVG text overlay with tiling, position, opacity, rotation
- watermark-image: logo/image watermark with position, opacity, scale
- text-overlay: styled text on images with shadow and background box
- compose: layer images with position, opacity, and blend modes
Backend: POST /api/v1/tools/:toolId/batch accepts multiple files +
settings, processes via p-queue with CONCURRENT_JOBS concurrency limit,
streams ZIP response using archiver. Tool registry in tool-factory
enables batch to reuse any registered tool's process function. SSE
endpoint at GET /api/v1/jobs/:jobId/progress provides real-time updates.
Handles partial failures gracefully, preserves filenames, deduplicates
collisions. Frontend: use-batch-processor hook handles upload, SSE
progress tracking, and automatic ZIP download.
Seven tool route files using the createToolRoute factory, registering 10 API
endpoints total (color adjustments covers 4 tool IDs). Also fixes the tool
factory generic to properly infer Zod output types and clamps the compress
binary-search quality to 1-100.
- createToolRoute<T> factory: handles multipart parsing, file validation,
Zod settings validation, workspace management, and error handling
- Each tool only needs to provide toolId, settingsSchema, and process function
- Registers POST /api/v1/tools/:toolId routes automatically
- Tool registry stub at routes/tools/index.ts ready for tool implementations
- Catches Sharp errors and returns clean API error envelopes (422)