These are internal Convex actions. They are called automatically by the system and are not accessible from client code. They are documented here for observability and debugging purposes.
NEXTCLOUD_WEBDAV_BASE_URL— WebDAV base URL (e.g.https://cloud.example.com/remote.php/dav/files/user)NEXTCLOUD_WEBDAV_USER— NextCloud usernameNEXTCLOUD_WEBDAV_APP_PASSWORD— NextCloud app passwordNEXTCLOUD_UPLOAD_PREFIX— Storage path prefix (default:pindeck/media-uploads)
MEDIA_GATEWAY_URL / MEDIA_GATEWAY_TOKEN can be configured to route uploads through an external media processing service instead of processing images directly.
Derivative URL structure
Every persisted image produces four variants stored under a dated directory path:derivativeUrls object returned by storage actions maps these to public URLs:
NextCloud persistence status flow
ThenextcloudPersistStatus field on an image record tracks the upload lifecycle:
Images created via uploadMultiple start with nextcloudPersistStatus: "pending". Once finalizeUploadedImage completes successfully, the status transitions to "succeeded" and the temporary Convex storage file is deleted.
Actions
internal.mediaStorage.finalizeUploadedImage
Called automatically after api.images.uploadMultiple. Retrieves the image from temporary Convex storage, uploads it to NextCloud (generating preview and derivative variants), updates the image record with the persisted URLs, deletes the temporary Convex file, and schedules VLM smart analysis.
ID of the draft image record to finalize.
ID of the uploading user, passed through to the VLM analysis job.
Convex storage ID of the uploaded file.
Image title, used for file naming and VLM context.
Tags passed to the VLM analysis job.
Category passed to the VLM analysis job.
Description passed to the VLM analysis job.
Source attribution passed to the VLM analysis job.
Style reference string passed to the VLM analysis job.
Project group passed to the VLM analysis job.
Project name passed to the VLM analysis job.
Moodboard name passed to the VLM analysis job.
Number of variations to auto-generate after analysis. Clamped to 0–12. Defaults to 0.
One of
upload, discord, pinterest, ai.{ ok: true, imageUrl: string } | { ok: false, error: string }
On failure, the image record’s nextcloudPersistStatus is set to "failed" and aiStatus is set to "failed".
internal.mediaStorage.persistExternalImageFromUrl
Downloads an image from an external URL, generates a preview and three derivative sizes, and uploads all files to NextCloud. Used during Discord and Pinterest imports.
Public URL of the image to download and persist.
Optional title, used for the NextCloud file name.
Public NextCloud URL of the stored original.
Public URL of the 640×360 WebP preview.
Relative WebDAV path of the original file.
Relative WebDAV path of the preview file.
Public URLs for the three derivative sizes.
WebDAV paths for the three derivative files.
internal.mediaStorage.persistGeneratedImageFromUrl
Same behavior as persistExternalImageFromUrl, but designed for AI-generated image URLs from fal.ai. Returns a discriminated union to allow graceful error handling when NextCloud is unavailable.
URL of the AI-generated image to persist.
Optional title for file naming.
{ ok: true, imageUrl, previewUrl, storagePath, previewStoragePath, derivativeUrls, derivativeStoragePaths } | { ok: false, error: string }
When NextCloud is not configured (ok: false), error is "Nextcloud not configured". The caller (internalGenerateRelatedImages) treats this as a non-fatal condition and continues.
internal.mediaStorage.publishStoredImagePaths
Derives public NextCloud share URLs from already-stored WebDAV paths. Used by the backfill migration to publish images that were uploaded privately without a public share link.
Relative WebDAV path of the stored original.
Relative WebDAV path of the preview file.
Relative WebDAV paths for derivative files.
Public URL for the original.
Public URL for the preview (if
previewStoragePath was provided).Public URLs for derivatives (if
derivativeStoragePaths was provided).internal.mediaStorage.reprocessStoredImagePaths
Re-downloads the stored original from NextCloud and regenerates all preview and derivative variants. Used by the backfill migration when derivatives are missing or stale.
Relative WebDAV path of the stored original to reprocess.
Optional title for file naming of regenerated derivatives.
UploadedImage object: { imageUrl, previewUrl, storagePath, previewStoragePath, derivativeUrls, derivativeStoragePaths }.
internal.mediaStorage.cleanupNextcloudPaths
Deletes a list of files from NextCloud. Called automatically when an image is rejected via api.images.rejectImage or deleted via api.images.remove.
Relative WebDAV paths to delete. Duplicates are deduplicated before deletion. Empty or blank strings are skipped.
Number of files successfully deleted.
Number of files that could not be deleted. Failures are logged as warnings but do not throw.