Skip to content

Presigned Upload Flow for Dashboard API - #136

Merged
yash-pouranik merged 5 commits into
geturbackend:mainfrom
Nitin-kumar-yadav1307:feature/presigned-upload-dashboard
Apr 26, 2026
Merged

Presigned Upload Flow for Dashboard API#136
yash-pouranik merged 5 commits into
geturbackend:mainfrom
Nitin-kumar-yadav1307:feature/presigned-upload-dashboard

Conversation

@Nitin-kumar-yadav1307

@Nitin-kumar-yadav1307 Nitin-kumar-yadav1307 commented Apr 25, 2026

Copy link
Copy Markdown
Collaborator

Presigned Upload Flow for Dashboard API

Issue: #131

Description

Implements a three-step presigned URL upload architecture for the dashboard API, enabling large file uploads directly to S3/R2 without proxying bytes through Node.js. This mirrors the implementation in PR #129 for the public API but uses dashboard-appropriate auth (JWT/session via loadProjectForAdmin middleware).

Changes

Files Modified

apps/dashboard-api/src/routes/projects.js

  • POST /:projectId/storage/upload-request - Generate presigned URL with quota validation
  • POST /:projectId/storage/upload-confirm - Verify upload completion and charge quota atomically
  • Auth chain: authMiddleware → verifyEmail → loadProjectForAdmin

apps/dashboard-api/src/controllers/project.controller.js

New handlers:

  • requestUpload() - Validates size, peeks at quota (no charge yet), returns signed URL and token
  • confirmUpload() - Verifies file exists, compares size, atomically charges quota, cleans up on failure

New helpers:

  • parsePositiveSize() - Validates positive finite numbers for file size
  • normalizeProjectPath() - Prevents path traversal; validates projectId prefix
  • bestEffortDeleteUploadedObject() - Non-fatal cleanup helper for failed confirmations

docs-legacy/storage.md

  • Added presigned upload flow documentation (4-step process)
  • Added bucket CORS configuration requirements (PUT, OPTIONS, GET, HEAD methods)
  • Documented required headers and flow sequence

Files Created

apps/dashboard-api/src/__tests__/storage.presigned.controller.test.js

  • 8 tests for requestUpload and confirmUpload handlers
  • Coverage: internal storage, external storage, quota enforcement, size validation, retryable states

apps/dashboard-api/src/__tests__/routes.projects.storage.test.js

  • 2 route wiring tests
  • Confirms both endpoints are protected by auth middleware chain

Key Features

Quota Management

  • requestUpload: Peeks at quota without charging
  • confirmUpload: Charges quota atomically only after file verification
  • External storage skips all quota operations

Security

  • Auth protection via dashboard middleware chain
  • Path traversal prevention (validates projectId prefix, blocks .. segments)
  • File size limits: 10 MB per file, 100 MB safety max
  • Size tolerance: 64-byte tolerance for cloud storage eventual consistency

Reliability

  • Retryable 409 if file not yet visible after PUT
  • Atomic quota charge with automatic cleanup on limit exceeded
  • Best-effort object deletion on confirmation failure

Shared Infrastructure

  • Uses @urbackend/common helpers: getPresignedUploadUrl, verifyUploadedFile
  • Reuses existing getStorage and getBucket functions
  • Consistent with public API implementation patterns

Test Results

WhatsApp Image 2026-04-25 at 6 53 50 PM

Summary by CodeRabbit

  • New Features

    • Two-phase presigned upload flow for direct browser uploads (request signed URL, PUT file, confirm upload); legacy multipart upload endpoint removed.
    • File size validation and storage quota enforcement with atomic accounting for internal storage.
    • Upload verification with automatic cleanup and size-tolerance handling.
  • Documentation

    • Added guidance and precise bucket CORS configuration for presigned browser uploads.
  • Tests

    • Added comprehensive tests for presigned upload routes and controller behaviors.
  • Chores

    • Exposed input sanitization utilities for reuse.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(dashboard): add presigned URL upload flow to dashboard API

2 participants