docs(media): note the server now enforces the 90-second video limit

This commit is contained in:
Alexandre Brandizzi 2026-09-24 21:39:07 -03:00
parent b5da537c93
commit 11a753a2e9
4 changed files with 6 additions and 4 deletions

View file

@ -45,7 +45,7 @@ const VIDEO_DURATION_MESSAGE = `Videos must be ${MAX_VIDEO_DURATION_SECONDS} sec
async function isWithinContract(file: File, kind: WorkOrderUploadKind): Promise<boolean> { async function isWithinContract(file: File, kind: WorkOrderUploadKind): Promise<boolean> {
if (kind === "video") { if (kind === "video") {
// SH-116: duration is checked client-side only; unreadable metadata never blocks. // SH-116: pre-check only; the server enforces it too. Unreadable metadata never blocks.
const duration = await probeVideoDurationSeconds(file); const duration = await probeVideoDurationSeconds(file);
if (duration != null && duration > MAX_VIDEO_DURATION_SECONDS) { if (duration != null && duration > MAX_VIDEO_DURATION_SECONDS) {
toast.error(VIDEO_DURATION_MESSAGE); toast.error(VIDEO_DURATION_MESSAGE);

View file

@ -56,7 +56,7 @@ export async function validateVendorDocument(file: File): Promise<string | undef
if (file.size > MAX_VIDEO_BYTES) { if (file.size > MAX_VIDEO_BYTES) {
return "Videos must be 100 MB or smaller."; return "Videos must be 100 MB or smaller.";
} }
// Duration is checked client-side only; unreadable metadata never blocks. // Pre-check; the server enforces it too. Unreadable metadata never blocks.
const duration = await probeVideoDurationSeconds(file); const duration = await probeVideoDurationSeconds(file);
if (duration != null && duration > MAX_VIDEO_DURATION_SECONDS) { if (duration != null && duration > MAX_VIDEO_DURATION_SECONDS) {
return `Videos must be ${MAX_VIDEO_DURATION_SECONDS} seconds or shorter.`; return `Videos must be ${MAX_VIDEO_DURATION_SECONDS} seconds or shorter.`;

View file

@ -5,7 +5,8 @@ import { isWorkOrderCompletionSurfaceReadOnly } from "@/domain/work-orders/utils
* (JPEG/PNG/HEIC), videos up to 100 MB and 90 seconds (MP4/MOV), at most * (JPEG/PNG/HEIC), videos up to 100 MB and 90 seconds (MP4/MOV), at most
* 10 photos and 3 videos per work order. Applies to the Photos & Videos modal, * 10 photos and 3 videos per work order. Applies to the Photos & Videos modal,
* the Completion Doc → Media tab and the vendor portal upload. Duration is * the Completion Doc → Media tab and the vendor portal upload. Duration is
* checked client-side only (the server cannot probe it cheaply). Documents * pre-checked here and enforced by the server from the MP4/MOV header;
* unreadable metadata never blocks. Documents
* keep the 50 MB document cap; the signed completion PDF keeps its own cap. * keep the 50 MB document cap; the signed completion PDF keeps its own cap.
*/ */
export const MAX_WORK_ORDER_PHOTO_BYTES = 10_000_000; export const MAX_WORK_ORDER_PHOTO_BYTES = 10_000_000;

View file

@ -1,7 +1,8 @@
/** /**
* Best-effort client-side video duration probe. Resolves null when the browser * Best-effort client-side video duration probe. Resolves null when the browser
* cannot decode the container's metadata — callers must not block the upload in * cannot decode the container's metadata — callers must not block the upload in
* that case (SH-116: duration is a client-side check only). * that case (SH-116: the server enforces the limit from the MP4/MOV header and
* also lets unreadable metadata through).
*/ */
export const VIDEO_DURATION_PROBE_TIMEOUT_MS = 10_000; export const VIDEO_DURATION_PROBE_TIMEOUT_MS = 10_000;