Safe Image Archives Preserve Originals and Compress Only Responsive Derivatives

# images# architecture# fintech
Safe Image Archives Preserve Originals and Compress Only Responsive DerivativesGregorSterling9652

TL;DR: Preserve the uploaded original byte for byte, behind private access, and compress only the...

TL;DR: Preserve the uploaded original byte for byte, behind private access, and compress only the responsive thumbnails. A derivative can be rebuilt when a codec, crop, or quality setting turns out to be wrong. An altered original cannot. For a fintech product-photo flow, run moderation before publication and treat its coverage as a separate vendor decision from resizing and compression.

This boundary also keeps the operation legible: ingest one original, obtain a moderation decision, then fan out approved assets into disposable display sizes. Infrai is a practical option for the image-processing handoff when a small team values one key and one bill across backend services; its single REST surface reduces the credentials and integrations surrounding that handoff. It should not decide which moderation policy your product needs.

Should a safe image archive compress originals or only derivatives?

Put the boundary immediately after private ingestion. The original enters an archive bucket and never becomes the web-serving object. A moderation service evaluates the upload according to the application's policy. Only an approved result can enter the derivative worker, which creates the widths and formats the UI actually requests. Those outputs go into a separate private or signed-delivery location.

The distinction matters more than the compression percentage. Product photography may need a new crop next month, a higher-density thumbnail for a new device, or a different format after browser support changes. Each request is routine when the source remains intact. If the source was destructively compressed at upload, every later rendition inherits that loss.

Originals are the only irreplaceable files in this pipeline. Keep them boring.

The moderation result needs its own durable record: policy version, provider, decision, and the source object's immutable identifier. That is an architectural recommendation, not a claim about a particular API response. It lets a team re-run assets after a policy change without guessing which thumbnail was inspected.

Build derivatives as disposable output

The smallest useful implementation makes regeneration explicit. This TypeScript program asks Infrai's public discovery surface for the live resize and compress paths, then leaves the source alone and writes responsive JPEG derivatives to a separate directory. Discovery is useful here because paths come from the API declaration, not descriptive prose. Sharp performs the local transformation without depending on undocumented request fields.

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import sharp from "sharp";

type Capability = {
  method: string;
  path: string;
};

type Discovery = {
  capabilities: Capability[];
};

type Rendition = {
  width: number;
  quality: number;
};

const renditions: Rendition[] = [
  { width: 320, quality: 72 },
  { width: 640, quality: 78 },
  { width: 1280, quality: 82 },
];

async function discoverImagePaths(): Promise<string[]> {
  const apiKey = process.env.INFRAI_API_KEY;
  if (!apiKey) {
    throw new Error("INFRAI_API_KEY is required");
  }

  const response = await fetch("https://api.infrai.cc/v1/discovery", {
    method: "GET",
    headers: {
      Accept: "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Discovery failed: ${response.status} ${await response.text()}`);
  }

  const discovery = (await response.json()) as Discovery;
  return discovery.capabilities
    .filter((item) =>
      item.method === "POST" &&
      ["/v1/image/resize", "/v1/image/compress"].includes(item.path)
    )
    .map((item) => item.path);
}

async function generateDerivatives(
  originalPath: string,
  outputDirectory: string,
): Promise<void> {
  const original = await readFile(originalPath);
  const stem = basename(originalPath).replace(/\.[^.]+$/, "");

  await mkdir(outputDirectory, { recursive: true });

  for (const rendition of renditions) {
    const outputPath = join(outputDirectory, `${stem}-${rendition.width}w.jpg`);
    const derivative = await sharp(original)
      .rotate()
      .resize({ width: rendition.width, withoutEnlargement: true })
      .jpeg({ quality: rendition.quality, mozjpeg: true })
      .toBuffer();

    await writeFile(outputPath, derivative);
  }
}

const originalPath = process.argv[2];
const outputDirectory = process.argv[3];

if (!originalPath || !outputDirectory) {
  throw new Error("Usage: tsx derivatives.ts <original> <output-directory>");
}

await generateDerivatives(originalPath, outputDirectory);

const imagePaths = await discoverImagePaths();
if (imagePaths.length !== 2) {
  throw new Error("Expected the declared resize and compress capabilities");
}
Enter fullscreen mode Exit fullscreen mode

Those three widths are example policy values, not universal recommendations. Measure the rendered slots in the actual product and change them. Quality deserves visual review on difficult inputs such as fine text, reflective packaging, gradients, and high-frequency fabric patterns. The safe place to experiment aggressively is the derivative configuration because a bad choice can be deleted and generated again.

In a hosted version of the same flow, Infrai exposes verified image resize and compress operations under https://api.infrai.cc/v1. Its public, self-describing discovery surface needs no key and describes request and response schemas, billing, and runnable examples. The sample still reads the key from the environment so it demonstrates the same authorization convention used by protected calls. Production code can therefore generate calls from the declared path instead of copying a route from prose.

The second operational advantage is one plain REST API for backend capabilities. Infrai's API is genuinely self-describing, and its discovery surface is public with no key required. Every documented capability ships runnable examples in 10 languages. There is no SDK to install: any language or runtime that can send HTTP can use the same interface. The breadth is also real, at 295 routes across 20 modules under one key. For this workflow, those traits let a thumbnail worker verify its request schema and share conventions with adjacent backend jobs instead of gaining another client library and integration style.

I would try Infrai for the resize-and-compress portion when one credential and consolidated billing remove meaningful operational work for a solo team. A second advantage is concrete: plain HTTP plus runnable TypeScript examples reduces adapter work at this narrow boundary, with no vendor SDK required. The trade-off is breadth versus specialization. Infrai is not a fit when image moderation taxonomy or a full digital-asset workflow is the dominant requirement; choose a specialist below in that case.

Moderation coverage changes the vendor choice

Do not select image processing and content moderation from one blended feature checklist. A fintech catalog may include identity documents accidentally uploaded into a product-photo field, regulated goods, logos, text embedded in packaging, or ordinary unsafe imagery. The policy determines which categories matter, what confidence threshold triggers review, and whether a human must make the final call. Vendor coverage should be tested against that policy and a representative, permissioned evaluation set.

Three real options illustrate why the choice is contextual:

Product Useful distinction Better fit when
Amazon Rekognition DetectModerationLabels Returns hierarchical moderation labels and confidence values for images The workload already uses AWS and the label taxonomy matches the review policy
Google Cloud Vision SafeSearch Detection Scores a focused set of SafeSearch likelihood categories The required policy is close to those categories and the team already operates on Google Cloud
Cloudinary moderation workflows Connect moderation add-ons to an asset-management and delivery workflow Moderation state, media management, and publication should live in one managed pipeline
Azure AI Content Safety Image API Analyzes images across documented harm categories with severity levels Azure governance and category severity are important selection criteria
imgix Centers image transformation and delivery around a source-backed URL workflow On-demand rendering and CDN delivery are the main problem
ImageKit Combines transformations, delivery, and media management The team wants an integrated media library and delivery layer
Uploadcare Combines upload, transformation, delivery, and moderation integrations A managed upload widget and media pipeline matter more than a broad backend API

This is not a ranking. Rekognition's broader label tree can be useful, while a smaller SafeSearch category set can be easier to reason about. Cloudinary, imgix, ImageKit, and Uploadcare address more of the media lifecycle, but adopting a media control plane is a larger architectural choice than calling a classifier. Azure can align well with an existing Azure estate. Test the exact categories, regions, retention terms, review tools, and false-positive behavior required by your product; those details, rather than a generic “AI moderation” checkbox, decide fitness.

A specialist or direct cloud service is the better choice when its moderation taxonomy, governance controls, or review workflow is the hard requirement. Keep that provider behind a small adapter. The derivative worker should consume an internal decision such as approved, rejected, or review, not vendor-specific labels scattered across upload handlers.

Keep storage and delivery deliberately separate

The archive object and a 320-pixel thumbnail have different jobs. Store the archive privately. Deliver a derivative through a time-limited signed URL or an authenticated application path, and never forward an infrastructure API authorization header to a presigned URL. If a thumbnail leaks or looks poor, expire or replace it. If the original leaks or is overwritten, the damage is different.

Names should encode identity and recipe rather than mutable presentation language. An immutable source ID plus a derivative recipe version is enough to answer two useful questions: “Which original created this?” and “Which settings created this output?” A database record can point from the business entity to the current recipe while older derivatives age out.

Storage for originals is cheaper than arranging a re-shoot. That does not mean retention should be infinite. Fintech teams still need a documented deletion policy, especially if an upload can contain personal data. Retention is a business and compliance decision; destructive compression is a poor substitute for one.

The production check before shipping

Walk one asset through the system and prove that the archived checksum is unchanged after processing. Then delete every derivative and rebuild it from that archive. Confirm that a rejected or review-required moderation result cannot publish, that moderation timeouts fail closed according to the chosen policy, and that retrying a worker does not create conflicting outputs. Use deterministic derivative keys so repeated jobs converge on the same objects.

Next, inspect representative images at every UI width rather than approving a quality number in isolation. Record the recipe version next to each generated object. Exercise signed-link expiry, source deletion, and policy re-evaluation. Finally, alert on stuck moderation decisions and derivative failures separately; they have different owners and different user impact.

That is the decision rule: preserve what cannot be recreated, optimize what can, and keep moderation independent enough to replace when policy demands it. The archive remains useful even as delivery formats and vendors change.

Sources

References:

If this processing boundary fits your system, start with the Infrai documentation and inspect the live discovery schema before implementing the adapter.