Resume Upload and Processing
Relevant source files
The following files were used as context for generating this wiki page:The Resume Upload and Processing system is a core feature responsible for allowing users to upload their resume files, which are then processed, stored, and prepared for AI enhancement. This process involves a client-side React component for the user interface, a Next.js API route for handling the backend logic, Supabase for file storage, and a PostgreSQL database managed by Prisma for metadata storage.
The system supports PDF and DOCX file types, performs validation on the client and server, extracts text content from the documents, and securely stores both the original file and its extracted text. This functionality is the entry point for all subsequent resume enhancement operations.
System Architecture Overview
The upload process is initiated from the frontend UploadSection component. The user selects a file, which is then sent to the /api/resumes/upload API endpoint. The backend API authenticates the user, validates the file, extracts its text content, uploads the raw file to a Supabase Storage bucket, and finally creates a corresponding record in the Resume table in the database.
High-Level Data Flow
The following diagram illustrates the overall flow of data from the user's browser to the application's backend services.
Frontend: Upload Component
The user interface for uploading resumes is handled by the UploadSection React component. It provides a drag-and-drop area and a traditional file browser input.
Sources: dashboard/_components/upload-section.tsx
Key Responsibilities
- File Selection: Allows users to select a file via a file input or by dragging and dropping it onto a designated area.
- Client-Side Validation: Before uploading, the component performs checks on the selected file.
- Upload Trigger: On user confirmation, it constructs a
FormDataobject and sends a POST request to the backend API. - UI Feedback: Displays the selected file's name and size, shows upload progress, and reports any errors returned from the server.
- Redirection: Upon a successful upload, it redirects the user to the enhancement page for the newly uploaded resume.
Client-Side Validation Logic
The component validates the file based on type and size to provide immediate feedback and prevent unnecessary network requests.
The validation rules are as follows:
| Validation | Rule | Error Message |
|---|---|---|
| File Type | Must be application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document, or application/msword. | "Please select a PDF or Word document (.pdf, .doc, .docx)" |
| File Size | Must not exceed 10MB (10 * 1024 * 1024 bytes). | "File size must be less than 10MB" |
Sources: dashboard/_components/upload-section.tsx:34-45
Backend: Upload API Endpoint
The POST /api/resumes/upload endpoint is the core of the upload processing logic. It handles file reception, processing, storage, and database record creation.
Sources: api/resumes/upload/route.ts
Endpoint Details
- Route:
POST /api/resumes/upload - Authentication: Required. The user must have a valid session.
- Request Body:
FormDatacontaining the file under the key"file".
Processing Steps
- Authentication: Verifies the user's session using
next-auth. If no session is found, it returns a401 Unauthorizederror. - File Validation: Checks for file existence, type (PDF/DOCX), and size (max 10MB) on the server side as a security measure.
- Text Extraction:
- For PDFs (
application/pdf), it uses thepdf-parselibrary to extract raw text content. - For DOCX files (
application/vnd.openxmlformats-officedocument.wordprocessingml.document), it uses themammothlibrary.
- For PDFs (
- File Name Sanitization: The original file name is sanitized using the
sanitizeFileNamefunction to prevent path traversal attacks and remove special characters before being used in the storage path. - File Storage: The file buffer is uploaded to Supabase Storage using the
uploadFileToSupabaseutility. The file is stored under a path structured as{userId}/{timestamp}-{sanitizedFileName}. - Database Record Creation: A new record is created in the
Resumetable using Prisma. This record stores metadata including the user ID, original file name, the path in Supabase Storage, file type, and the extracted text content. - Logging: A log entry is created to record the successful upload event.
- Response: A JSON object is returned containing the
idand other details of the newly created resume record.
Sources: api/resumes/upload/route.ts:54-135
Storage and Data Model
Supabase Storage
All uploaded resume files are stored in a private Supabase Storage bucket. The lib/supabase-storage.ts file provides a set of utility functions to interact with this bucket.
Sources: lib/supabase-storage.ts, SUPABASE_SETUP.md
Key Functions
| Function | Description |
|---|---|
uploadFileToSupabase | Uploads a file buffer to the resumes bucket. It constructs a unique file path using the user ID and a timestamp. |
downloadFileFromSupabase | Downloads a file as a Blob from the storage bucket given its path. |
getSignedUrl | Creates a temporary, secure URL to access a private file. |
deleteFileFromSupabase | Removes a file from the storage bucket. |
Sources: lib/supabase-storage.ts:22-96
The storage bucket is named resumes and is configured to be private. Access is controlled via RLS policies that ensure users can only access their own files.
Sources: lib/supabase-storage.ts:19, SUPABASE_SETUP.md:29-35
Database Schema
The Resume model, defined in schema.prisma, stores all metadata related to an uploaded resume.
This diagram shows the relationship between the User and Resume models.
Sources: schema.prisma:35-64
Resume Model Fields
| Field | Type | Description |
|---|---|---|
id | String | Unique identifier (CUID). |
userId | String | Foreign key linking to the User model. |
originalName | String | The original name of the uploaded file. |
cloudStoragePath | String | The full path to the file in Supabase Storage (e.g., userId/timestamp-filename.pdf). |
fileType | String | The type of the file, either 'pdf' or 'docx'. |
originalContent | String | The raw text content extracted from the file. |
status | String | The current status of the resume (e.g., 'uploaded', 'processing'). Defaults to 'uploaded'. |
user | User | Relation to the User who owns the resume. |
enhancements | ResumeEnhancement[] | Relation to any AI enhancements performed on this resume. |
Sources: schema.prisma:88-102
File Retrieval and Display
After a resume is uploaded, it needs to be displayed in the enhancement interface. This is handled by the EnhanceInterface component.
For PDF files, a special proxy API route is used to serve the file to the client, avoiding potential CORS issues with direct links from Supabase Storage and ensuring the user is authenticated.
PDF Proxy Endpoint
- Route:
GET /api/proxy-pdf/[id] - Logic:
- Authenticates the user session.
- Finds the
Resumerecord by its ID, ensuring it belongs to the authenticated user. - Uses
downloadFileFromSupabaseto fetch the file blob from storage using itscloudStoragePath. - Returns the file as a
NextResponsewith theContent-Typeset toapplication/pdfandContent-Dispositionset toinline.
This allows the react-pdf library on the frontend to render the PDF directly from the application's own domain.
Sources: api/proxy-pdf/[id]/route.ts, enhance/[id]/_components/enhance-interface.tsx:168-172
Conclusion
The Resume Upload and Processing feature is a well-structured system that securely handles user file uploads from start to finish. It combines client-side and server-side validation for robustness, uses dedicated libraries for text extraction, and leverages Supabase for scalable file storage. By storing file metadata and extracted text in a relational database, the system efficiently prepares resumes for the subsequent AI enhancement stages, providing a seamless user experience. The use of a proxy for serving PDFs demonstrates attention to security and browser compatibility.