# PortalFit - Architecture Decision Log (DECISIONS.md)

## ADR-001: Zero-Dependency Architecture & Pure Browser Execution
- **Context:** Online photo resizers frequently compromise user privacy by uploading sensitive identity photos (passports, visas) to remote servers, or loading heavy analytics/tracking trackers.
- **Decision:** Build PortalFit with zero external dependencies, frameworks, or remote build steps. Use vanilla HTML5, CSS3, and JavaScript APIs (`CanvasRenderingContext2D`, `FileReader`, `ArrayBuffer`, `toBlob`).
- **Consequences:** Guaranteed 100% privacy, verifiable via DevTools Network audit, sub-100ms processing speed, zero server runtime costs.

## ADR-002: EXIF Orientation Resolution on Canvas
- **Context:** Mobile photos (especially iOS/Android camera photos) rely on EXIF orientation tags (1-8). CSS-based rotation (`image-orientation: from-image`) only affects visual display, leaving the exported canvas image incorrectly oriented.
- **Decision:** Implement a lightweight binary EXIF parser (`exif-parser.js`) to read APP1 markers (`0xFFE1`) from the file's ArrayBuffer. Apply exact 2D transformation matrices on `CanvasRenderingContext2D` before resizing.
- **Consequences:** Eliminates rotated photo export bugs across all operating systems and browsers.

## ADR-003: Binary Search for KB Target Compression
- **Context:** Visa and passport portals mandate strict file size bounds (e.g. 20 KB to 240 KB for US Visa DS-160, 20 KB to 100 KB for Indian Passport). Linear quality adjustments are slow and inaccurate.
- **Decision:** Use a binary search algorithm on JPEG quality (`quality ∈ [0.1, 1.0]`) capped at a maximum of 15 iterations with ±1 KB tolerance.
- **Consequences:** Hits target KB range in ~3 to 6 iterations (<200ms) with high precision.

## ADR-004: Memory & Performance Guardrails
- **Context:** High-resolution smartphone cameras produce 48MP+ photos (8000×6000px). Instantiating multiple large canvas instances causes browser tab crashes, especially on mobile devices.
- **Decision:**
  1. Downscale any source image > 4096px to a maximum 4096px bounding box before running binary search iterations.
  2. Reuse a single shared canvas instance during binary search.
  3. Immediately invoke `URL.revokeObjectURL()` on stale blob URLs.
- **Consequences:** Stable memory consumption (<10MB heap delta) even after processing dozens of large images sequentially.
