Context
Follow-up from #199 (YouTube Shorts max duration raised to 3 minutes in the dashboard).
Today, duration / aspect ratio / file-size limits live only in the frontend (useMediaRules.ts → useMedia.ts). API and MCP share ContentTypeCompatibleWithMedia, which only checks media type (image/video/document, requires media, mixed media) — not duration, dimensions, or bytes.
Media is post-level and shared across platforms (one posts.media array). Validation must stay per content_type against that shared set, not a single global limit on the file.
Goals
1. Reliable video meta on upload
Chunked uploads often store videos with empty meta. Duration/width/height used by the editor are client-supplied (or missing). Without a server probe (e.g. ffprobe), backend duration/aspect checks are forgeable or skipped.
- Extract
duration, width, height (and maybe size) when media is finalized on the server
- Persist on asset /
post.media[].meta so web, API, and MCP see the same values
2. Backend validation (web + API + MCP)
Extend ContentTypeCompatibleWithMedia (or a sibling rule) to enforce the same constraints as CONTENT_TYPE_RULES in useMediaRules.ts:
- max duration (
maxVideoDurationSec)
- aspect ratio range (
aspectRatioMin / aspectRatioMax)
- max file size (
maxVideoBytes / maxImageBytes / …)
- file count / requires-media (where not already covered)
Apply on schedule/publish paths for:
- Web (
UpdatePostRequest)
- Public API
- MCP (
Create/Update/Publish post tools)
Shared-upload model: evaluate each enabled platform’s content_type independently against the shared media (same as usePostCompliance on the frontend). Reject the failing platform(s) / block schedule when any selected platform is incompatible — do not invent per-platform media attachments.
Prefer a single source of truth for the numeric rules (PHP mirror of useMediaRules, or a shared definition both sides read) so dashboard and API/MCP don’t drift again.
TikTok: max duration is account-dynamic via creator_info.max_video_post_duration_sec — needs a deliberate approach (fetch at validate time vs leave TikTok frontend-only for now).
Missing meta: decide fail-open vs fail-closed once probe exists; until then, don’t rely on client-only duration.
3. Square YouTube Shorts
YouTube accepts Shorts that are square or vertical up to 3 minutes. Our dashboard still only allows ~9:16 (aspectRatioMin/Max ≈ 0.5–0.6) for youtube_short.
- Widen allowed aspect ratio for
youtube_short to include 1:1 (and confirm against current YouTube Shorts rules)
- Update content-type copy / docs if needed
- Keep backend rules in sync once (2) exists
Out of scope for this issue
Acceptance ideas
References
Context
Follow-up from #199 (YouTube Shorts max duration raised to 3 minutes in the dashboard).
Today, duration / aspect ratio / file-size limits live only in the frontend (
useMediaRules.ts→useMedia.ts). API and MCP shareContentTypeCompatibleWithMedia, which only checks media type (image/video/document, requires media, mixed media) — not duration, dimensions, or bytes.Media is post-level and shared across platforms (one
posts.mediaarray). Validation must stay percontent_typeagainst that shared set, not a single global limit on the file.Goals
1. Reliable video meta on upload
Chunked uploads often store videos with empty
meta. Duration/width/height used by the editor are client-supplied (or missing). Without a server probe (e.g. ffprobe), backend duration/aspect checks are forgeable or skipped.duration,width,height(and maybe size) when media is finalized on the serverpost.media[].metaso web, API, and MCP see the same values2. Backend validation (web + API + MCP)
Extend
ContentTypeCompatibleWithMedia(or a sibling rule) to enforce the same constraints asCONTENT_TYPE_RULESinuseMediaRules.ts:maxVideoDurationSec)aspectRatioMin/aspectRatioMax)maxVideoBytes/maxImageBytes/ …)Apply on schedule/publish paths for:
UpdatePostRequest)Create/Update/Publishpost tools)Shared-upload model: evaluate each enabled platform’s
content_typeindependently against the shared media (same asusePostComplianceon the frontend). Reject the failing platform(s) / block schedule when any selected platform is incompatible — do not invent per-platform media attachments.Prefer a single source of truth for the numeric rules (PHP mirror of
useMediaRules, or a shared definition both sides read) so dashboard and API/MCP don’t drift again.TikTok: max duration is account-dynamic via
creator_info.max_video_post_duration_sec— needs a deliberate approach (fetch at validate time vs leave TikTok frontend-only for now).Missing meta: decide fail-open vs fail-closed once probe exists; until then, don’t rely on client-only duration.
3. Square YouTube Shorts
YouTube accepts Shorts that are square or vertical up to 3 minutes. Our dashboard still only allows ~9:16 (
aspectRatioMin/Max≈ 0.5–0.6) foryoutube_short.youtube_shortto include 1:1 (and confirm against current YouTube Shorts rules)Out of scope for this issue
Acceptance ideas
meta.duration/ dimensions after uploadyoutube_shortaccepts square (1:1) videos within the 3-minute capReferences
resources/js/composables/useMediaRules.tsresources/js/composables/useMedia.ts,usePostCompliance.tsapp/Rules/ContentTypeCompatibleWithMedia.php