Commit Graph
100 Commits
Author SHA1 Message Date
ashim-hq 7275e4bfaa fix: AuthGuard checks analytics store for real-time consent state 2026-04-23 10:06:46 +08:00
ashim-hq 9724e5229c test: add comprehensive E2E Playwright tests for analytics feature
Covers consent flow, API endpoints, privacy/no-data-leak verification,
disabled-server behavior, settings toggle, and privacy policy page.
2026-04-23 09:59:41 +08:00
ashim-hq 3ef52d0aa9 feat: set PostHog and Sentry default keys for analytics 2026-04-23 00:29:22 +08:00
ashim-hq 9ad94f3d54 docs: update README analytics statement 2026-04-22 19:16:01 +08:00
ashim-hq c2130148c4 fix: add statement-breakpoint separators to analytics migration 2026-04-22 19:15:38 +08:00
ashim-hq 6e319efadd feat: add analytics init, identify, search tracking, consent header, settings toggle 2026-04-22 19:14:16 +08:00
ashim-hq f115275796 feat: add analytics consent page and auth flow integration 2026-04-22 19:10:52 +08:00
ashim-hq 9f66ad85bf feat: add Sentry error tracking with PII scrubbing 2026-04-22 19:10:28 +08:00
ashim-hq 544f81c48d feat: add frontend analytics wrapper and consent store 2026-04-22 19:07:50 +08:00
ashim-hq a3f707a361 feat: instrument tool_used, pipeline_executed, ai_bundle_action events 2026-04-22 19:07:17 +08:00
ashim-hq 39b011eccb docs: update privacy policy to reflect analytics 2026-04-22 19:06:01 +08:00
ashim-hq 075f017dbf feat: add backend analytics wrapper, config/consent API routes 2026-04-22 19:03:23 +08:00
ashim-hq 4904e8d140 feat: add analytics env vars, DB schema columns, instance ID generation 2026-04-22 19:00:15 +08:00
ashim-hq 03df555e10 feat: add shared analytics types, events, consent logic, and i18n strings 2026-04-22 18:58:16 +08:00
AshimandGitHub 5a45bcbc8f feat: production-grade RBAC with editor role, custom roles, API key scoping, and audit log (#89)
* feat(rbac): add editor role, 3 new permissions, ownership helper

* feat(rbac): add audit_log table, apiKeys.permissions column, editor role to schema

* feat(rbac): wire requirePermission into all routes, add editor role support

* refactor(rbac): replace ad-hoc role checks with permission-based ownership

* feat(rbac): add audit log DB writes + query endpoint

Dual-write audit events to stdout (existing) and SQLite audit_log table.
Add GET /api/v1/audit-log with pagination, action filter, and date range
filtering, gated behind audit:read permission.

* feat(rbac): add API key permission scoping with ceiling enforcement

* feat(rbac): add escalation prevention and last-admin protection

* feat(rbac): add editor role to UI, API key permission scoping in settings

* test(rbac): add full permission matrix integration test

* test(rbac): add editor role E2E tests

* feat(rbac): add custom roles with CRUD API and DB-backed permission lookup

* feat(rbac): add API key expiration

* feat(rbac): add roles management UI and API key expiration to settings

* feat(rbac): add audit log UI to settings

* fix: remove any cast in API key permission validation

* test(rbac): add unit tests for username validation rules

* test(rbac): add unit tests for effective permissions and ownership

* test(rbac): add comprehensive route permission matrix (all routes × all roles)

* test(rbac): add auth route edge case tests (login failures, session expiry, password side effects)

* test(rbac): add escalation prevention tests (register, update, self-demote, last-admin)

* test(rbac): add ownership enforcement tests (files, pipelines, editor access, cross-user isolation)

* test(rbac): add API key edge cases (name validation, delete behavior, key revocation)

* test(rbac): add audit log edge cases (all events, pagination clamping, structure)

* test(rbac): add custom roles edge case tests (validation, CRUD, functional permissions)

* test(rbac): add comprehensive E2E tests (roles UI, audit log, custom role, API key scoping)
2026-04-22 18:10:04 +08:00
AshimandGitHub 2d7a61c18f feat: allow multi-file selection for automation pipeline (#88)
* 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.
2026-04-22 00:02:00 +08:00
ashim-hq 9a015c8501 fix: AVIF sidecar crash, edit-metadata silent no-op, passport batch blank images, color-palette hex overflow, OCR log noise
- Convert all AI bridge inputs to PNG before writing to disk so PIL can
  read AVIF/WebP/TIFF (7 bridge files; face-detection and OCR already
  had this pattern)
- Add title/author aliases to edit-metadata schema so common field names
  actually write EXIF tags instead of being silently stripped by Zod
- Port extend/pad crop logic from passport-photo single endpoint to the
  batch pipeline so crop regions extending beyond the image get filled
  with background color instead of producing all-white output
- Clamp quantized color channels to 255 in color-palette to prevent
  Math.round(255/16)*16=256 from producing invalid hex like #100100100
- Compare OCR fallback warning against expected engine name per tier
  instead of comparing engine name against tier name (always mismatch)
2026-04-21 23:54:25 +08:00
AshimandGitHub 0b8e0bf774 fix: auto-fallback from CodeFormer to GFPGAN in face enhancement (#87)
When model is set to "auto", CodeFormer failure previously threw an
error telling users to manually switch to GFPGAN. Now it falls back
to GFPGAN automatically, matching the graceful degradation pattern
already used in OCR.
2026-04-21 23:51:11 +08:00
AshimandGitHub 6fcf43016d Merge pull request #86 from ashim-hq/fix/issue-72-auth-false-admin
fix: prevent admin escalation when AUTH_ENABLED=false
2026-04-21 23:42:18 +08:00
ashim-hq bf73150301 fix: prevent admin escalation when AUTH_ENABLED=false
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
2026-04-21 23:38:42 +08:00
AshimandGitHub ba26ea4bc7 feat: add AVIF output format support across 6 remaining tools (#85)
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.
2026-04-21 23:34:48 +08:00
AshimandGitHub 7d422c2fd0 Merge pull request #84 from ashim-hq/fix/settings-default-tool-view
fix: wire up Default Tool View save in General settings
2026-04-21 23:27:04 +08:00
ashim-hq 7920fbfd20 chore: fix pre-existing biome formatting issues 2026-04-21 23:25:41 +08:00
ashim-hq afac4b9870 fix: wire up Default Tool View save in General settings
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
2026-04-21 23:25:34 +08:00
ashim-hq 77a60b24cc fix: resolve 5 bugs found during comprehensive tool testing
1. split batch 404: register split tool in batch registry via
   registerToolProcessFn() so /api/v1/tools/split/batch works

2. CodeFormer crash: inference_app() expects a file path, not a numpy
   array. Save to temp file before calling, read result back.

3. OCR fallback chain: fix case-sensitive "Segmentation fault" match
   that prevented PaddleOCR crash from triggering Tesseract fallback.
   Also add "process crashed" check. Upgrade ARM paddlepaddle to >=3.2.1.

4. blur-faces large images: downscale to 1920px max before MediaPipe
   detection, scale coordinates back. Also add rotation retry for
   portrait-oriented images where BlazeFace misses faces. Applied to
   detect_faces.py, enhance_faces.py, and restore.py.

5. color-adjustments tool ID: fix mismatch in index.ts registration
   array (was "color-adjustments", should be "adjust-colors").
2026-04-21 22:25:06 +08:00
ashim-hq c17caa42e0 fix: add missing ConnectionMonitor component
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.
2026-04-21 21:25:39 +08:00
ashim-hq 26506ba41b Merge remote-tracking branch 'origin/feat/docker-hardening-v1' into merge-work-on-demand 2026-04-21 21:23:52 +08:00
AshimandGitHub 8f6dbeca32 Merge pull request #83 from ashim-hq/feat/extended-format-support
feat: extended image format support (JXL, RAW, ICO, TGA, PSD, EXR, HDR)
2026-04-21 10:55:32 +08:00
ashim-hq b966d81b10 chore: remove test-only compose file 2026-04-21 10:45:17 +08:00
ashim-hq 4ccde70dad fix: info tool fails for CLI-decoded formats (PSD, TGA, EXR, HDR, ICO)
The info tool reads metadata directly via Sharp without going through
the format decoder pipeline. Added CLI format detection and decoding
before metadata read, matching the pattern used by all other tools.
2026-04-21 10:34:10 +08:00
ashim-hq 966d7abaf0 fix: AVIF compress fails because Sharp metadata reports heif not avif
Sharp's metadata() returns format:"heif" for AVIF files. The compress
function was using this raw value without normalizing through FORMAT_MAP,
so toFormat("heif",...) was called which requires a compression option.
Now both explicit and detected formats go through FORMAT_MAP, mapping
heif→avif correctly.
2026-04-21 10:27:02 +08:00
ashim-hq dc9160746e fix: ICO needs CLI decode, AVIF compress missing options, remove JXL output
- ICO: Sharp cannot decode ICO files. Added ImageMagick-based ICO decoder
  that extracts the largest embedded image. Added ICO to CLI_DECODED_FORMATS
  and SERVER_PREVIEW_EXTENSIONS. Removed from BROWSER_PREVIEWABLE sets.
- AVIF compress: Sharp's AVIF encoder requires effort option. Added
  formatOpts() helper that supplies effort:4 for AVIF format.
- JXL output: Docker's bundled libvips lacks the JXL encoder plugin.
  Removed JXL as a convert output target to avoid guaranteed failures.
  JXL remains fully supported as an input format.
2026-04-21 10:20:08 +08:00
AshimandGitHub 4c9dc6e38e fix: Docker hardening, security, and deployment readiness for V1 (#82)
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
2026-04-21 10:19:08 +08:00
ashim-hq 1dc3adbdba fix: Docker hardening, security, and deployment readiness for V1
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
2026-04-21 10:18:57 +08:00
ashim-hq 2df0fe026e fix: use ImageMagick for RAW decoding instead of dcraw_emu
dcraw_emu is not included in libraw-dev (only libraries). ImageMagick
already delegates to LibRaw for all major RAW formats (DNG, CR2, NEF,
ARW, ORF, RW2). Moved ImageMagick helpers above RAW decoder to fix
declaration order.
2026-04-21 10:03:18 +08:00
ashim-hq 2aadb66031 feat: add support for JXL, Camera RAW, ICO, TGA, PSD, EXR, HDR image formats
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.
2026-04-21 09:59:57 +08:00
AshimandGitHub fa35f57813 Merge pull request #81 from ashim-hq/worktree-automate-ui-redesign
feat: redesign Automate page — tool palette + pipeline canvas
2026-04-21 09:27:47 +08:00
ashim-hq 2502239d79 feat: redesign Automate page layout — tool palette + pipeline canvas
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
2026-04-21 09:27:17 +08:00
ashim-hq e94ac945bb fix: exclude worktree directories from vitest test discovery
.worktrees/ and .claude/ contain git worktrees from other developers
which have their own test files. Without exclusion, vitest picks them
up and fails due to mismatched React/module resolution.
2026-04-21 09:26:22 +08:00
ashim-hq a682380f6f Merge branch 'feat/graceful-degradation' into feat/on-demand-ai-features 2026-04-21 09:24:37 +08:00
ashim-hq 1f9fa08002 fix: prevent polling leak when online event fires from connected state
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.
2026-04-21 09:24:10 +08:00
ashim-hq a145ffdc68 fix: trigger disconnected state when chunk loads exhaust retries
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.
2026-04-21 00:06:46 +08:00
AshimandGitHub 502d6b1c56 Merge pull request #80 from ashim-hq/feat/unlimited-by-default
feat: Unlimited by Default — remove all artificial limits
2026-04-21 00:05:41 +08:00
ashim-hq 39078f8e7f fix: add torchvision shim to upscale.py and enhance_faces.py
When the Python dispatcher crashes and bridge.ts retries via per-request
spawning, the shim from dispatcher.py isn't loaded. basicsr then fails
importing torchvision.transforms.functional_tensor (removed in v0.17).

Adding the shim directly to both scripts ensures they work regardless
of whether they run through the dispatcher or standalone.
2026-04-21 00:02:31 +08:00
ashim-hq 70f9f3d51d fix: detect CSS preload errors and keep banner visible during error states
- 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
2026-04-21 00:01:59 +08:00
ashim-hq 1807a4ddfd fix: raise maxParamLength to 500 for long filenames
Fastify's find-my-way router defaults maxParamLength to 100 chars.
Files with long names (e.g., stock photo filenames >100 chars) would
return 404 on download because the :filename param exceeded the limit.
2026-04-20 23:43:29 +08:00
ashim-hq da52088e39 fix: address code review — complete fetch coverage, refresh timing, dedupe chunk detection 2026-04-20 22:18:27 +08:00
AshimandGitHub 9440879f5c Merge pull request #79 from ashim-hq/fix/state-bleed-on-tool-switch
fix: state bleed on tool switch, AVIF compress, OCR segfault, long filenames
2026-04-20 22:17:45 +08:00
ashim-hq 795965ed43 fix: truncate long filenames to prevent filesystem ENAMETOOLONG errors 2026-04-20 22:14:14 +08:00
ashim-hq c738f16107 fix: support AVIF compress and fix hardcoded content type 2026-04-20 22:13:53 +08:00
ashim-hq 491e6fb554 fix: prevent PaddleOCR segfault on CPU-only Docker by setting CUDA env vars 2026-04-20 22:13:07 +08:00
ashim-hq 5e1159fa75 feat: offset layout padding when connection banner is visible 2026-04-20 22:11:08 +08:00
ashim-hq 4593c3c13d fix: improve error message for interrupted tool processing 2026-04-20 22:07:58 +08:00
ashim-hq 62f028eb3e fix: stop granting admin access when API is unreachable 2026-04-20 22:07:39 +08:00
ashim-hq ec991c4a37 feat: detect network errors in API client and trigger disconnected state 2026-04-20 22:06:39 +08:00
ashim-hq 4cb1a35f10 feat: wire connection banner, monitor, and lazyWithRetry into App 2026-04-20 22:03:58 +08:00
ashim-hq 6602818cdf feat: add connection monitor hook for reactive failure detection 2026-04-20 22:02:17 +08:00
ashim-hq 1e9453366b feat: add connection status banner component 2026-04-20 22:00:27 +08:00
ashim-hq d40d7b3847 feat: add lazyWithRetry for chunk load failure recovery 2026-04-20 21:56:08 +08:00
ashim-hq 1ad916448a test: add checkHealth non-ok HTTP response coverage
The checkHealth method handles non-ok responses (e.g. 503) but only
network-level errors had test coverage. Add nonOkHealth helper and
test to verify connected → disconnected transition on HTTP 503.
2026-04-20 21:53:46 +08:00
ashim-hq 7dd6023b8e feat: frontend unlimited — raise all client-side caps and timeouts
- XHR timeouts: doubled across all tool categories (120s/300s/600s)
- Pipeline timeout: 180s → 600s
- Favicon/PDF/barcode timeouts raised to 300s
- Files page: fetch 200 per page
- Split grid: 20 → 100 max columns/rows
- Image viewer zoom: 25-300% → 10-1000%
- Collage zoom: 3x → 10x, pan: ±100 → ±200
- Passport photo: face adjust ±15% → ±30%, zoom 3x → 5x
2026-04-20 21:52:41 +08:00
ashim-hq ee8e9861a7 feat: docker unlimited defaults + i18n strings for admin UI
- docker-compose: log rotation 10m×3 → 50m×5 for power users
- docker-compose: add shm_size 2gb for AI workloads
- i18n: add strings for Limits & Resources admin panel
2026-04-20 21:52:07 +08:00
ashim-hq 6746989aa1 feat: make all hardcoded limits configurable via env vars
- bodyLimit: conditional on MAX_UPLOAD_SIZE_MB (0 = 1GB practical max)
- rate limiting: disabled when RATE_LIMIT_PER_MIN=0
- shutdown timeout: 8s → 30s
- upload plugin: no fileSize/files cap when env=0
- session duration: configurable via SESSION_DURATION_HOURS (default 168h)
- login attempts: configurable via LOGIN_ATTEMPT_LIMIT
- batch/pipeline/svg-to-raster: skip guard when MAX_BATCH_SIZE=0
- pipeline steps: configurable via MAX_PIPELINE_STEPS (0 = unlimited)
- user-files: remove 200 hard cap
- stitch canvas: configurable via MAX_CANVAS_PIXELS (0 = unlimited)
- PDF pages: configurable via MAX_PDF_PAGES (0 = unlimited)
- SVG size: configurable via MAX_SVG_SIZE_MB (0 = unlimited)
- logo size: configurable via MAX_LOGO_SIZE_KB (default 2048)
- worker threads: auto-detect via resolveWorkerThreads (0 = auto)
- megapixels: skip validation when MAX_MEGAPIXELS=0
- seam carving: remove 1200px dimension cap
- concurrency: auto-detect via resolveConcurrency (0 = auto)
2026-04-20 21:50:17 +08:00
ashim-hq 2ba7520dd4 fix: handle non-ok HTTP responses in connection store checkHealth
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.
2026-04-20 21:49:22 +08:00
ashim-hq c4dd55ace0 feat: add connection state store with health polling 2026-04-20 21:46:46 +08:00
ashim-hq be254f9ca6 feat: dynamic timeouts — scale with image size, respect PROCESSING_TIMEOUT_S
Create timeout.ts utility for dynamic timeout computation.
Replace hardcoded timeouts across the stack:
- tool-factory worker: 30s → dynamic based on megapixels
- Python bridge default: 300s → 600s (or env override)
- background-removal: fixed → dynamic based on image size
- OCR: fixed 600s → dynamic based on image size
- seam-carving: 120s → dynamic based on image size
- ExifTool: 30s → 60s
- HEIC converter: 30s → 120s
- SQLite busy_timeout: 5s → 10s
2026-04-20 21:46:07 +08:00
ashim-hq 00041d535d feat: kill all silent fallbacks — fail clearly, never degrade silently
Remove 9 silent fallback chains in the Python sidecar:
- upscale: RealESRGAN→Lanczos (now errors with install guidance)
- upscale: GFPGAN skip (now errors with install guidance)
- gpu: GPU→CPU (now reports device in response, never silent)
- remove_bg: alpha matting fallback (now errors with retry guidance)
- remove_bg: GPU→CPU session (now reports device)
- colorize: DDColor→OpenCV (now errors with install guidance)
- enhance_faces: CodeFormer→GFPGAN (now errors with install guidance)
- ocr: quality cascade (now errors at requested level)
- bridge: dispatcher crash retry (now reports retry in stderr)

Also: raise red_eye max_faces 10→50, face_landmarks max_num_faces configurable,
restore.py min face size 48→24px.
2026-04-20 21:42:19 +08:00
ashim-hq ce477a0dbf feat: widen all Zod schema constraints for power users
Raise all artificially low max values on tool settings:
- stitch: grid→100, gap→1000, border/radius→500
- split: grid→100x100
- collage: zoom→10, gap→500, radius→500
- watermark: fontSize→1000
- border: width→2000, radius→2000, shadow→200
- qr: size→10000
- gif: dimensions→16384
- passport: dpi→1200
- sharpening: amount→1000
- pdf/svg: dpi→2400, dimensions→65536
- vectorize: precision→16
- bulk-rename: pattern→1000
- image-to-pdf: margin→500
- pipeline: name→255, description→2000
2026-04-20 21:40:06 +08:00
ashim-hq 2ccd01178b test: add 8 state-bleed regression tests for tool navigation 2026-04-20 21:39:56 +08:00
ashim-hq 335e35c96a fix: reset processed state and tool-specific stores on tool navigation 2026-04-20 21:36:14 +08:00
ashim-hq 7daf2377f0 feat: unlimited by default — env vars default to 0 (unlimited)
Add 10 new configurable env vars (MAX_WORKER_THREADS, PROCESSING_TIMEOUT_S,
MAX_PIPELINE_STEPS, MAX_CANVAS_PIXELS, MAX_SVG_SIZE_MB, MAX_LOGO_SIZE_KB,
MAX_SPLIT_GRID, MAX_PDF_PAGES, SESSION_DURATION_HOURS, LOGIN_ATTEMPT_LIMIT).

Change existing defaults: MAX_UPLOAD_SIZE_MB=0, MAX_BATCH_SIZE=0,
MAX_MEGAPIXELS=0, RATE_LIMIT_PER_MIN=0, MAX_USERS=0, CONCURRENT_JOBS=0.

Zero means unlimited/auto-detect throughout the application.
2026-04-20 21:35:15 +08:00
ashim-hq 0eeb5b07a9 fix: clear batch zip and processing flag in undoProcessing() 2026-04-20 21:33:24 +08:00
ashim-hq 37277e5c09 fix: resolve ONNX CUDA fallback, Docker e2e infrastructure, and all test failures
- Add safe_onnx_session() to gpu.py with graceful CUDA EP → CPU fallback
- Replace bare ort.InferenceSession() calls across colorize, restore, inpaint, remove_bg
- Add libcublas-12-6 to production Dockerfile for ONNX Runtime CUDA EP
- Add skipIfFeatureNotInstalled guards to remove-bg, blur-faces, smart-crop, ocr, noise-removal e2e specs
- Add AI tool install prompt detection in tools-all.spec.ts
- Add smart-crop to PYTHON_SIDECAR_TOOLS so frontend shows install prompt correctly
- Create Dockerfile.test.dockerignore to include tests/ in test image builds
- Add libheif-examples and exiftool to Dockerfile.test for HEIC and metadata tests
- Regenerate visual regression baselines for Docker/Linux and skip on non-Docker platforms
2026-04-20 20:53:54 +08:00
ashim-hq f67a03bb36 fix: resolve all audit findings — e2e coverage, feature system hardening, visual baselines
- 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
2026-04-20 18:47:59 +08:00
ashim-hq e7eea34080 fix: resolve basicsr/torchvision shim bug, lint warnings, and code formatting
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.
2026-04-20 17:03:17 +08:00
AshimandClaude Opus 4.6 39e27635c8 fix: audit fixes for cross-platform correctness
- Fix NameError in restore.py: face enhancement loop used undefined
  variable `i`, now uses enumerate()
- Fix gpu.py ONNX fallback: previous smoke-test with empty bytes
  always raised, making GPU detection unreachable via the ONNX path.
  Now uses nvidia-smi hardware check after confirming CUDA EP is
  compiled in — works on Linux, Windows, and gracefully fails on macOS
- Fix cpu_fallback_packages stripping CUDA-specific index URLs when
  replacing paddlepaddle-gpu with paddlepaddle for CPU-only systems

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:28:35 +08:00
AshimandClaude Opus 4.6 01d30cfb61 fix: pin torch cu126 for GPU compatibility and fix cross-platform bugs
- Pin torch==2.6.0+cu126 and torchvision==0.21.0+cu126 in feature
  manifest to prevent NCCL symbol mismatch on CUDA 12.6 base images
- Move lpips after torch in install order to prevent wrong version
  resolution from PyPI
- Add einops to upscale-enhance common deps (required by SCUNet)
- Update cpu_fallback_packages to handle multi-package CUDA torch
  entries on amd64 without GPU
- Fix gpu.py ONNX CUDA detection: replace hardcoded .so path with
  cross-platform session smoke-test
- Fix os.dup(1) crashes on Windows in upscale, enhance_faces, and
  noise_removal by wrapping in try/except with sys.stderr fallback
- Guard top-level numpy/cv2 imports in colorize.py and restore.py
  with helpful error messages
- Add weights_only=False fallback for torch.load in noise_removal
- Fix integration tests to accept 501 for uninstalled AI features
  and 422 for missing system tools (exiftool, libheif)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:17:08 +08:00
ashim-hq ac5fdfb841 fix: update e2e tests for current UI, increase timeouts for CPU environments, and fix auth bypass bug
- Fix SKIP_MUST_CHANGE_PASSWORD not affecting login/session API responses,
  causing frontend redirect even when the env var was set after user creation
- Increase Docker Playwright timeouts (test: 600s, expect: 60s, AI processing: 300s)
  to support CPU-only self-hosted environments
- Increase default rate limit from 100 to 50000 req/min for self-hosted deployments
- Fix OCR tests: use filechooser pattern (Dropzone has no static file input),
  correct enhance checkbox default, rewrite for actual fixture behavior
- Fix remove-bg tests: update quality labels (Balanced→HD, Best→Max)
- Fix noise-removal skip guard: use waitFor() instead of instant isVisible()
- Fix automate pipeline save test: clean up stale E2E pipelines before assertion
2026-04-20 15:03:56 +08:00
ashim-hq e20418c3e1 feat: enhance noise removal tool tests and update Docker configurations for GPU support 2026-04-20 12:27:07 +08:00
ashim-hq d3c3ce0e32 feat: update Docker configuration for improved GPU support and streamline service definitions 2026-04-20 11:11:40 +08:00
AshimandClaude Opus 4.6 6edb92c242 feat: add output filename suffixes, CPU fallback for GPU packages, and fix e2e tests
- 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>
2026-04-20 10:56:47 +08:00
ashim-hq 92c0579a49 fix: resolve all a11y lint warnings in collage preview
Add proper ARIA roles and keyboard handlers to interactive overlays,
replace drag handle div with semantic button element.
2026-04-19 21:21:54 +08:00
ashim-hq 6202f9f69e fix: prevent progress bar from jumping backwards during install
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.
2026-04-19 21:20:01 +08:00
ashim-hq e4a73210ac chore: set compose project name to ashim
Shows as "ashim" in Docker Desktop instead of the directory name "docker".
2026-04-19 21:16:59 +08:00
ashim-hq b78e0741b3 fix: only show bundle counter in install indicator during batch install
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.
2026-04-19 21:15:17 +08:00
ashim-hq 62dd1ae211 refactor: unify feature install UI with global store, add healthcheck and GPU profile to compose
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).
2026-04-19 21:00:19 +08:00
ashim-hq fc98037eb1 fix: show loading spinner instead of error for HEIC preview, default fullscreen details to visible
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.
2026-04-19 20:38:51 +08:00
ashim-hq 5c897f3c1d fix: show download badge on home page inline tool list
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.
2026-04-19 20:20:53 +08:00
ashim-hq 8c83d7efcd fix: handle HEIC images in blur-faces and red-eye-removal, show warning when no faces detected 2026-04-19 19:52:23 +08:00
ashim-hq 10bdc24a4a feat: on-demand AI feature install with progress indicators 2026-04-19 19:52:14 +08:00
ashim-hq 771f786528 fix: ensure progress bar is visible for at least 800ms 2026-04-19 17:25:55 +08:00
ashim-hq 8495a0de2d feat: add progress bar to collage processing
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.
2026-04-19 17:12:12 +08:00
ashim-hq 889ce1dd26 fix: make fit/fill toggle prominent with label, enlarge zoom controls 2026-04-19 17:04:11 +08:00
ashim-hq bc73078264 fix: fill cell background color when using contain fit mode 2026-04-19 16:52:29 +08:00
ashim-hq efede1ae4a fix: include objectFit in default cell transform fallback 2026-04-19 16:47:24 +08:00
ashim-hq bb241d6044 feat: add per-cell fit/fill toggle to collage tool
Adds objectFit property to CellTransform (cover/contain). When set to
"contain", the entire image is shown within the cell with background
color fill. Toggle button in the cell controls toolbar switches between
modes. Server-side rendering handles both modes via Sharp.
2026-04-19 16:41:35 +08:00
ashim-hq a7094f3fa4 fix: resolve collage UX bugs - broken pan, scroll zoom, control visibility
- Fix pan: use `movement` (cumulative) instead of `delta` (per-frame)
  in useDrag — delta accumulation against static memo was wrong
- Fix wheel zoom: replace useWheel with direct DOM addEventListener
  using { passive: false } so preventDefault() works and page doesn't
  scroll while zooming
- Fix controls: remove auto-hide timer, keep zoom slider and reset
  button visible while cell is selected
2026-04-19 16:27:45 +08:00
ashim-hq aaa807dae9 fix: address code review feedback on collage-preview
- Import CellTransform type instead of inline duplicate
- Remove unnecessary MutableRefObject cast (React 19)
- Restore biome-ignore for useSemanticElements on cell div
- Add role/aria-label to drag handle and zoom controls
- Remove fragile onPointerDown stopPropagation on drag handle
- Remove unused containerRef
2026-04-19 16:01:19 +08:00
ashim-hq e510708e16 feat: add use-gesture pan/zoom/pinch, dnd-kit reorder, visible controls, and HEIC spinner to collage 2026-04-19 15:56:02 +08:00
ashim-hq a8dd2d7422 feat: add HEIC preview support to collage store 2026-04-19 15:50:18 +08:00