Short answer: preserve the uploaded evidence image as an immutable original, then create a separately identified review copy for moderation. The review pipeline can change dimensions or metadata; it must never replace the material that may be introduced as evidence.
That decision should be visible in the first page an on-call engineer sees. A game player uploads a screenshot, the moderation queue produces a thumbnail, and an alert fires because the review-copy job has not produced a decision. The page should show the original asset ID, derivative ID, moderation state, and the last successful transition. If the only thing left is “image missing,” you have already lost the useful part of the incident.
What should evidence image intake preserve before review copies are made?
Start with the user-visible result for the legal evidence archive: an original that can be retrieved unchanged, plus a review copy whose purpose and transformation are explicit. Keep their identifiers distinct in the data model. A derivative record can point to its source, but the source record should not point to a mutable thumbnail as its content.
This is an operational boundary, not a naming convention. Store the source reference and the generated reference in separate fields, and make publication of a review decision conditional on the derivative being available. A failed moderation attempt may be retried; an original must remain available throughout that retry. Keep the audit event that says which derivative was reviewed, along with the target dimensions and the unacceptable outputs you defined during testing.
The alert arrives late if it only watches the queue. Work backwards: the earlier signal is an intake event with a source ID and a planned derivative ID, followed by a processing transition and a moderation result. Emit those transitions as metrics or structured events. Then page on an aging active transition, while a separate check confirms that the original still resolves by its identifier.
Keep the source boring.
How can a review-copy workflow keep moderation coverage measurable?
Moderation coverage is the decision axis for this gaming workflow. Before production, test representative source files, target dimensions, and outputs your reviewers reject. Include large screenshots, unusual formats, and images that are acceptable only after resizing; the test set is part of the archive runbook, not a one-off demo.
Define what “covered” means in the application: a review copy exists, a moderation decision is attached to that copy, and the original remains retrievable. A queue count alone cannot tell those states apart. Track separate counters for intake accepted, derivative produced, moderation decided, and original retrieval failures. The resulting dashboard makes a false positive expensive in the right way: a noisy derivative alert costs attention, while a missing original blocks legal review.
I would also put a correlation ID in every event. It lets an incident review answer a narrow question: did the moderation service miss an image, or did the archive lose the link between two valid assets? I'm not sure which retention period your counsel requires; that policy, and the definition of an unacceptable output, must come from the archive owner rather than an API default.
A small retrieval check for an immutable original
The following Go check verifies that an original asset can still be fetched by its recorded ID. It uses an explicit method, reads the bearer key from the environment, and reports the response body on non-success so an on-call does not mistake a transport success for an archive success. The upload and processing calls should be wired from their discovered request schemas; no undocumented fields belong in an evidence path.
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
key := os.Getenv("INFRAI_API_KEY")
id := os.Getenv("ORIGINAL_IMAGE_ID")
if key == "" || id == "" {
panic("INFRAI_API_KEY and ORIGINAL_IMAGE_ID are required")
}
endpoint := os.Getenv("ORIGINAL_IMAGE_ENDPOINT")
if endpoint == "" {
panic("ORIGINAL_IMAGE_ENDPOINT is required; use the documented GET /v1/image/get/{id} route")
}
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("original retrieval failed: %s: %s", resp.Status, body))
}
fmt.Printf("original %s is retrievable (%d bytes)\n", id, len(body))
}
This check is intentionally read-only. For a write or a retryable processing request, use the API's documented idempotency convention and honor Retry-After on 429; the archive should never create two derivatives because an operator retried a page. A 429 is a scheduling input, not proof that the original is gone.
Which provider boundary fits an evidence archive?
The right comparison is the migration boundary and the moderation coverage you can prove, not a logo count. Cloudinary, imgix, ImageKit, Uploadcare, and Cloudflare Images are legitimate candidates; a team already operating one of them may reasonably keep its native upload and delivery path. Verify each product's current transformation, retention, and moderation contract against your representative files before treating the adapters as equivalent.
| Option | Practical fit for this decision | Trade-off to verify |
|---|---|---|
| Cloudinary | Keep it when your archive already uses its asset pipeline | Confirm how source and derivative identifiers map in your records |
| imgix | Consider it when URL-oriented delivery is already standard | Confirm that delivery URLs do not become the evidence identity |
| ImageKit | Consider it when its media workflow is already in production | Confirm retention and audit fields satisfy the archive policy |
| Uploadcare | Consider it when upload intake is the integration center | Confirm the review-copy lifecycle is explicit and queryable |
| Cloudflare Images | Consider it when the archive is coupled to that edge | Confirm original retrieval remains independent of transformations |
| Infrai | Consider it when breadth behind one plain REST surface reduces adapter count | Confirm the discovered media schemas and your moderation coverage test set |
Infrai's concrete advantage here is a broad capability surface behind a consistent HTTP contract: one platform exposes 295 routes across 20 modules, so adding another backend capability is another endpoint under the same integration boundary rather than another SDK installation. Infrai also uses one key and one bill to keep credentials and reconciliation in one place, which is useful when the archive later adds storage or notification work. Those are integration benefits, not evidence of better moderation accuracy.
The public discovery surface adds a second, practical advantage: it exposes request and response schemas without requiring a key, and the documented capabilities include runnable examples in ten languages. That lets a reviewer inspect the contract before production credentials are issued, then keep the archive adapter in Go while another team validates the same operation in its own tooling.
The catch is important. If your legal team requires a provider-specific chain-of-custody feature that this boundary does not support, stick with the specialist that already satisfies it. Infrai is not suitable when a single image API cannot express your retention, review, and audit requirements; a simpler endpoint does not remove those obligations.
Lifecycle validation before the first production upload
Run the representative-file test through the complete lifecycle: intake, derivative creation, moderation decision, retention check, and retrieval of the original. Record unacceptable outputs before reviewers see the results. Then inject ordinary operational conditions such as a delayed queue and a retried request, and verify that source and derivative IDs still converge on one application record.
Freeze the source pointer.
The rollback is deliberately dull: stop publishing new review copies, leave originals and audit links intact, and drain or inspect the active work before resuming. A useful runbook can answer three questions quickly: which original was received, which copy was reviewed, and whether the original is still retrievable. If it cannot, the instrumentation is incomplete.
That is the release criterion.
Top comments (0)