Description
Currently, the application handles file uploads (e.g., audio transcription for activity feedback) but stores files temporarily in memory. We need to implement a proper file storage system using AWS S3 to support:
- User profile images/avatars
- Sports movement videos
- Other media files that need persistent storage
Current State
- File uploads are handled via
FileInterceptor from @nestjs/platform-express in ActivityFeedbackController
- Audio files are processed in-memory and sent directly to OpenAI for transcription
- No persistent file storage infrastructure exists
- Avatar component (
apps/web/src/components/ui/avatar.tsx) currently uses a placeholder image path
Requirements
Backend (NestJS API)
-
S3 Configuration
- Add AWS S3 SDK dependency (
@aws-sdk/client-s3)
- Create S3 configuration module/service
- Add environment variables:
AWS_S3_REGION
AWS_S3_BUCKET_NAME
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
- Support for different buckets/environments (dev, staging, prod)
-
File Upload Service
- Create a
FileStorageService that handles:
- Uploading files to S3
- Generating secure, unique file paths
- File validation (type, size)
- Generating presigned URLs for file access
- File deletion
- Support for different file types:
- Images (profile pictures, avatars)
- Videos (sports movement videos)
- Other media files
-
API Endpoints
POST /files/upload - Upload a file and return the S3 URL
DELETE /files/:fileId - Delete a file from S3
GET /files/:fileId/url - Get a presigned URL for file access
-
Database Schema Updates
- Add
profileImageUrl field to User model (or create a separate UserProfile model if needed)
- Consider adding a
File model to track uploaded files:
model File {
fileId Int @id @default(autoincrement())
s3Key String @unique
s3Url String
fileName String
fileType String
fileSize Int
uploadedBy Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
-
Security
- Validate file types (MIME type checking)
- Enforce file size limits
- Implement proper access control (users can only delete their own files)
- Use presigned URLs with expiration for secure file access
Frontend (React/Web)
-
File Upload Component
- Create a reusable file upload component
- Support drag-and-drop
- Show upload progress
- Preview for images
- Error handling
-
Profile Image Upload
- Update
NavUser component to allow profile image upload
- Display uploaded profile image in avatar
- Fallback to initials if no image
-
API Integration
- Add file upload methods to API client
- Handle file upload responses
- Update user profile endpoints to accept image URLs
Technical Considerations
- Use AWS SDK v3 (latest version)
- Implement proper error handling and retry logic
- Consider using CloudFront CDN for file delivery (future enhancement)
- Support for image optimization/resizing (future enhancement)
- Consider file versioning for profile images
- Implement cleanup jobs for orphaned files
Acceptance Criteria
Related Files
apps/api/src/modules/core/controllers/activity-feedback.controller.ts - Current file upload implementation
apps/web/src/components/ui/avatar.tsx - Avatar component
apps/web/src/components/sidebar/nav-user.tsx - User navigation with avatar
libs/database/prisma/schema/core.prisma - User model
Dependencies
- AWS S3 bucket must be created and configured
- AWS credentials must be available in environment
- IAM permissions for S3 access must be configured
Description
Currently, the application handles file uploads (e.g., audio transcription for activity feedback) but stores files temporarily in memory. We need to implement a proper file storage system using AWS S3 to support:
Current State
FileInterceptorfrom@nestjs/platform-expressinActivityFeedbackControllerapps/web/src/components/ui/avatar.tsx) currently uses a placeholder image pathRequirements
Backend (NestJS API)
S3 Configuration
@aws-sdk/client-s3)AWS_S3_REGIONAWS_S3_BUCKET_NAMEAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYFile Upload Service
FileStorageServicethat handles:API Endpoints
POST /files/upload- Upload a file and return the S3 URLDELETE /files/:fileId- Delete a file from S3GET /files/:fileId/url- Get a presigned URL for file accessDatabase Schema Updates
profileImageUrlfield toUsermodel (or create a separateUserProfilemodel if needed)Filemodel to track uploaded files:Security
Frontend (React/Web)
File Upload Component
Profile Image Upload
NavUsercomponent to allow profile image uploadAPI Integration
Technical Considerations
Acceptance Criteria
Related Files
apps/api/src/modules/core/controllers/activity-feedback.controller.ts- Current file upload implementationapps/web/src/components/ui/avatar.tsx- Avatar componentapps/web/src/components/sidebar/nav-user.tsx- User navigation with avatarlibs/database/prisma/schema/core.prisma- User modelDependencies