Skip to main content
Version: MyBestDealNow

File Management System

Author(s)

  • Ashik

Last Updated Date

2025-10-24


SRS References

  • 3.4.1 File Upload
  • 3.4.2 File Retrieval
  • 3.4.3 Access Control

Version History

VersionDateChangesAuthor
1.02025-10-24Initial draft for File Management moduleAshik

Feature Overview

Objective:
Implement a centralized file management system for handling files uploads and retrievals with type-based organization, automatic filename generation.

Scope:

  • Binary file upload with type classification (Inventory, Dealer)
  • Support for image formats (.jpg, .jpeg, .png, .svg) and documents (.xlsx)
  • Type-specific folder storage (/uploads/inventory/, /uploads/dealer/)
  • Default root folder storage (/uploads/) for unrecognized types
  • Unique filename generation (GUID/timestamp-based)
  • File metadata tracking in database
  • Integration with inventorymaster table
  • File retrieval through existing Inventory Fetch API

Dependencies:

  • IAM Service (authentication)
  • Storage provider (local filesystem or S3)
  • inventorymaster table
  • Email service for notifications (optional)

Requirements

Functional Requirements

  1. File Upload

    • Accept file uploads with required Enum type parameter (Inventory/Dealer)
    • Store files in type-specific folders (/uploads/inventory/, /uploads/dealer/)
    • If Enum type doesn't match predefined types, store in root folder (/uploads/)
    • Generate unique filenames to prevent collisions
    • Record full file path in filelocation field
    • Insert metadata into filemetadata table
  2. Entity Integration

    • Update inventorymaster.thumbnailimage with generatedfilename (single image)
    • Append to inventorymaster.images field (comma-separated for multiple images)
    • Support file-entity mapping through foreign keys
    • Maintain referential integrity between tables
  3. File Retrieval

    • Integrate with existing Inventory Fetch API
    • Return both generated filename and full path
    • Support JOIN queries between inventorymaster and filemetadata
    • If Enum type doesn't match (Inventory/Dealer), fetch from root folder (/uploads/)
    • Exclude soft-deleted files from results
  4. File Management

    • Soft-delete files (mark as deleted, retain physical file)
    • Retrieve file metadata by ID
    • Validate Enum type values

Non-Functional Requirements

  1. Security

    • Validate file types (whitelist: .jpg, .jpeg, .png, .svg, .xlsx)
    • Enforce file size limits
    • Never expose internal filesystem paths
    • Implement role-based access control
  2. Performance

    • Optimize JOIN queries with proper indexing
    • API response time under 500ms
    • Efficient pagination support
  3. Scalability

    • Support cloud storage migration (S3, CDN)
    • Handle large volumes of files
    • Extensible for additional Enum types
  4. Reliability

    • Audit trail with timestamps
    • Data consistency across tables
    • Prevent orphaned records

Design Specifications

UI/UX Design

(Dealer Portal / Admin Panel)

  • File upload component with type selector dropdown (Inventory/Dealer)
  • Drag-and-drop or click-to-browse interface
  • Image preview after successful upload
  • Inline error messages for validation failures
  • Progress indicator during upload

Workflow

Upload Process:

  1. Client selects file and type (Inventory/Dealer)
  2. Backend validates file type and size
  3. Generate unique filename (GUID-based)
  4. Determine storage path:
    • If type = "Inventory" → /uploads/inventory/
    • If type = "Dealer" → /uploads/dealer/
    • Default/Other → /uploads/ (root folder)
  5. Insert record into filemetadata table with full path
  6. Return file metadata to client

Retrieval Process (Inventory Master Example):

  1. Inventory Fetch API called
  2. Query inventorymaster table
  3. LEFT JOIN with filemetadata for thumbnailimage
  4. Split images field by comma to get all image filenames
  5. Query filemetadata for each image filename
  6. Determine file path based on enumtype:
    • If enumtype = "Inventory" → /uploads/inventory/{filename}
    • If enumtype = "Dealer" → /uploads/dealer/{filename}
    • Default/Other → /uploads/{filename} (root folder)
  7. Build imagepaths array with full file locations
  8. Return inventory data with thumbnail and multiple image paths
  9. Filter out soft-deleted files

Data Models

public class FileMetadata
{
public Guid Id { get; set; }
public string OriginalFileName { get; set; }
public string GeneratedFileName { get; set; }
public string FileLocation { get; set; }
public string EnumType { get; set; } // "Inventory" or "Dealer"
public DateTime CreatedAt { get; set; }
public bool IsDeleted { get; set; }
}

public class InventoryMaster
{
public Guid Id { get; set; }
public string ThumbnailImage { get; set; } // Single thumbnail - References filemetadata.generatedfilename
public string Images { get; set; } // Multiple images - Comma-separated generatedfilenames (e.g., "img1.jpg,img2.jpg,img3.jpg")
// ... other inventory fields
}

public record FileUploadRequest
{
[Required]
public List<IFormFile> Files { get; init; } // Accepts single or multiple files

[Required]
public FileType Type { get; init; } // Inventory or Dealer
}

public record FileUploadResponse
{
public List<UploadedFileInfo> UploadedFiles { get; init; }
public int TotalUploaded { get; init; }
public string UpdatedImagesField { get; init; } // Only populated if InventoryId provided
}

public record UploadedFileInfo
{
public Guid Id { get; init; }
public string OriginalFileName { get; init; }
public string GeneratedFileName { get; init; }
public string FileLocation { get; init; }
public string EnumType { get; init; }
public DateTime CreatedAt { get; init; }
}

public record InventoryDetailsWithImage
{
public Guid Id { get; init; }
public string ThumbnailImage { get; init; }
public string ThumbnailImagePath { get; init; }
public string Images { get; init; } // Comma-separated filenames
public List<string> ImagePaths { get; init; } // Full paths for all images
// ... other inventory fields
}

public enum FileType
{
Inventory,
Dealer
}

Database Schema:

-- filemetadata table
CREATE TABLE filemetadata (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
originalfilename VARCHAR(255),
generatedfilename VARCHAR(255) NOT NULL UNIQUE,
filelocation VARCHAR(500) NOT NULL,
enumtype VARCHAR(50) NOT NULL, -- Stores 'Inventory', 'Dealer', or other types (falls back to root folder)
createdat TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
isdeleted BOOLEAN DEFAULT FALSE
);

CREATE INDEX idx_filemetadata_generatedfilename ON filemetadata(generatedfilename);
CREATE INDEX idx_filemetadata_enumtype ON filemetadata(enumtype);

-- inventorymaster table (Partial)
CREATE TABLE inventorymaster (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
thumbnailimage VARCHAR(255), -- Single thumbnail image
images TEXT, -- Comma-separated list of image filenames
-- ... other columns
FOREIGN KEY (thumbnailimage) REFERENCES filemetadata(generatedfilename)
);

CREATE INDEX idx_inventorymaster_thumbnailimage ON inventorymaster(thumbnailimage);

-- Note: images field contains comma-separated generatedfilenames
-- Example: "img1.jpg,img2.jpg,img3.jpg"
-- Each filename should exist in filemetadata.generatedfilename

API Interfaces

EndpointMethodPayloadResponseStatus Codes
/api/v1/files/uploadPOSTfiles (IFormFile/IFormFile[]), typeFileUploadResponse201, 400, 415, 500
/api/v1/files/deleteDELETEfileNames (array in body)CommonResponse200, 404, 500
/api/v1/files/{fileId}GETfileIdFileMetadata200, 404, 500
/api/v1/files/download/{generatedFileName}GETgeneratedFileNameFile (attachment)200, 404, 500

API Request/Response Examples

Upload File (Single or Multiple)

Request (Single File):

POST /api/v1/files/upload
Content-Type: multipart/form-data

files: <binary>
type: "Inventory"

Response (201):

{
"uploadedFiles": [
{
"id": "a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c",
"originalFileName": "car_front.jpg",
"generatedFileName": "a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c.jpg",
"fileLocation": "/uploads/inventory/a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c.jpg",
"enumType": "Inventory",
"createdAt": "2025-10-24T10:15:00Z"
}
],
"totalUploaded": 1,
"updatedImagesField": "img1.jpg,a3f4b2c1.jpg"
}

Request (Multiple Files):

POST /api/v1/files/upload
Content-Type: multipart/form-data

files: <binary[]>
type: "Inventory"

Response (201):

{
"uploadedFiles": [
{
"id": "a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c",
"originalFileName": "car_front.jpg",
"generatedFileName": "a3f4b2c1.jpg",
"fileLocation": "/uploads/inventory/a3f4b2c1.jpg",
"enumType": "Inventory",
"createdAt": "2025-10-24T10:15:00Z"
},
{
"id": "b4e5c3d2-6f7e-5g8h-9i0j-1k2l3m4n5o6p",
"originalFileName": "car_side.jpg",
"generatedFileName": "b4e5c3d2.jpg",
"fileLocation": "/uploads/inventory/b4e5c3d2.jpg",
"enumType": "Inventory",
"createdAt": "2025-10-24T10:15:00Z"
}
],
"totalUploaded": 2,
"updatedImagesField": "img1.jpg,img2.jpg,a3f4b2c1.jpg,b4e5c3d2.jpg"
}

Note:

  • files parameter accepts both single file and multiple files
  • Response format is consistent for both single and multiple uploads

Delete files from storage (Batch)

Request:

DELETE /api/v1/files/delete
Content-Type: application/json

{
"fileNames": ["img2.jpg", "img3.jpg"]
}

Response (200):

{
"message": "Files removed from storage",
"updatedImagesField": "img1.jpg"
}

Note: Removes the specified filenames from the images field and soft-deletes the corresponding filemetadata records if not used elsewhere.

Get File by ID

Request:

GET /api/v1/files/a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c

Response (200):

{
"id": "a3f4b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c",
"originalFileName": "car_front.jpg",
"generatedFileName": "a3f4b2c1.jpg",
"fileLocation": "/uploads/inventory/a3f4b2c1.jpg",
"enumType": "Inventory",
"isDeleted": false,
"createdAt": "2025-10-24T10:15:00Z"
}

Download File by Generated Filename

To allow users to download files, implement a dedicated download endpoint:

Request:

GET /api/v1/files/download/{generatedFileName}

Response:

  • Returns the file as an attachment (with appropriate Content-Type and Content-Disposition headers).

Managing Multiple Images

Storage Strategy:

  • thumbnailimage: Single filename for primary/featured image
  • images: Comma-separated list of all image filenames
  • Example: "img1.jpg,img2.jpg,img3.jpg"

Upload:

  • Single API endpoint handles both single and multiple file uploads
  • Accepts files parameter as array (single or multiple)

Retrieval:

  • For inventory thumbnailimage: Query the filemetadata table where generatedfilename = thumbnailimage and get fileLocation for the thumbnail image.
  • For inventory images: Split the images field by comma in application code, then query filemetadata with WHERE generatedfilename IN (...) to get fileLocation for each image.
  • Build array of full paths for frontend display using the fileLocation values.

Delete:

  • Delete the given single or multiple file(s).

Development Tasks

TaskDescriptionEstimateDependencies
DB MigrationCreate filemetadata table with indexesX hours-
DB MigrationAdd thumbnailimage FK to inventorymasterX hoursfilemetadata table
BackendImplement storage service with folder logicX hoursConfiguration
BackendBuild file upload endpointX hoursStorage service, DB
BackendModify InventoryFetch API with JOINX hoursfilemetadata table
BackendFile retrieval and soft-delete endpointsX hoursfilemetadata table
BackendUnit tests for file operationsX hoursUpload endpoint
BackendIntegration testsX hoursAll endpoints
FrontendFile upload componentX hoursUpload endpoint
FrontendDisplay images in inventory listX hoursInventoryFetch API
DevOpsConfigure storage paths and permissionsX hours-
TotalX hours

Testing & Quality Assurance

Unit Tests

  • Filename generation produces unique GUIDs
  • Folder path logic for Inventory/Dealer/Default (root)
  • Enum type stored correctly regardless of value
  • filemetadata insertion with all fields
  • Soft-delete excludes files from queries

Integration Tests

  1. Upload Flow

    • Upload Inventory image → verify /uploads/inventory/ storage
    • Upload Dealer image → verify /uploads/dealer/ storage
    • Upload with unrecognized type → verify /uploads/ (root) storage
    • Verify filemetadata record creation
    • Verify response includes correct file metadata and updated images field (if applicable)
  2. Retrieval Flow

    • InventoryFetch API includes imagePath
    • JOIN query returns correct file paths (type-specific folders)
    • Files with unrecognized types returned from root folder
    • Soft-deleted files excluded
  3. Error Handling

    • Invalid file type rejected (415)
    • File size exceeded rejected (400)
    • Unrecognized Enum type stored in root folder (not rejected)

Acceptance Criteria

  • ✅ Upload image with type selection
  • ✅ Files stored in correct folders
  • ✅ Unique filenames generated
  • ✅ Database records created correctly
  • ✅ Inventory API returns image paths
  • ✅ Soft-delete hides files
  • ✅ Physical files retained after soft-delete

Deployment Considerations

Infrastructure

  • Storage folder permissions: chmod 755 /var/www/uploads
  • Auto-create subfolders: inventory/, dealer/
  • Root folder (/uploads/) for default/unrecognized types
  • Disk space monitoring and alerts
  • Database indexes on generatedfilename

Rollout Steps

  1. Run database migrations (filemetadata table, inventorymaster FK)
  2. Deploy backend with file upload endpoints
  3. Verify folder structure and permissions
  4. Deploy frontend with upload component
  5. Test in staging environment
  6. Production deployment during off-peak hours
  7. Monitor logs and performance metrics
  8. Migrate legacy data (if applicable)

Risks & Mitigations

RiskImpactMitigation
Malicious file uploadsHighFile type whitelist, size limits, antivirus scanning
Filename collisionsMediumGUID-based unique generation
Unauthorized accessHighRole-based permissions, authentication
Orphaned filesMediumScheduled cleanup jobs
JOIN performanceMediumProper indexing on generatedfilename
Disk space exhaustionHighMonitoring, quotas, archival strategy
Missing folder permissionsHighDeployment checklist, automated setup

Future Enhancements

  • Image reordering functionality
  • Set/change thumbnail image
  • Additional file types (PDF, Word documents, invoices)
  • Image transformation (resize, compress, watermark)
  • CDN integration for faster delivery
  • Virus scanning integration
  • Temporary upload expiry
  • Image optimization and compression
  • Excel file preview and processing