openapi: 3.0.0 info: title: Portfolio API version: 1.0.0 description: API for Ibrahim Al-Asfar's portfolio website, supporting user authentication, project management, profile handling, and more. servers: - url: https://mgzon-server.hf.space/ description: Production server - url: http://localhost:3000 description: Local development server components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT schemas: Project: type: object properties: _id: type: string title: type: string description: type: string image: type: string rating: type: string stars: type: number links: type: array items: type: object properties: option: type: string value: type: string isPrivate: type: boolean Comment: type: object properties: _id: type: string projectId: type: string userId: type: object properties: username: type: string email: type: string rating: type: number text: type: string timestamp: type: string format: date-time replies: type: array items: type: object properties: text: type: string timestamp: type: string format: date-time Skill: type: object properties: _id: type: string name: type: string icon: type: string percentage: type: number UserProfile: type: object properties: username: type: string profile: type: object properties: nickname: type: string portfolioName: type: string avatar: type: string avatarDisplayType: type: string enum: ['svg', 'normal'] svgColor: type: string jobTitle: type: string bio: type: string phone: type: string socialLinks: type: object properties: linkedin: type: string behance: type: string github: type: string whatsapp: type: string education: type: array items: type: object properties: institution: type: string degree: type: string year: type: string experience: type: array items: type: object properties: company: type: string role: type: string duration: type: string certificates: type: array items: type: object properties: name: type: string issuer: type: string year: type: string skills: type: array items: type: object properties: name: type: string percentage: type: number projects: type: array items: type: object properties: title: type: string description: type: string image: type: string links: type: array items: type: object properties: option: type: string value: type: string interests: type: array items: type: string customFields: type: array items: type: object properties: key: type: string value: type: string Notification: type: object properties: message: type: string paths: /api/login: post: summary: Log in a user description: Authenticates a user with email and password. Returns tokens for admin users or sends OTP for non-admin users. requestBody: required: true content: application/json: schema: type: object properties: email: type: string example: user@example.com password: type: string example: password123 required: - email - password responses: '200': description: OTP sent or tokens returned content: application/json: schema: oneOf: - type: object properties: message: type: string example: OTP sent to your email - type: object properties: token: type: string refreshToken: type: string '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '401': description: Invalid credentials '500': description: Server error /api/login/verify-otp: post: summary: Verify OTP for login description: Verifies the OTP sent to the user's email to complete login. requestBody: required: true content: application/json: schema: type: object properties: email: type: string example: user@example.com otp: type: string example: "123456" required: - email - otp responses: '200': description: Login successful, returns tokens content: application/json: schema: type: object properties: token: type: string refreshToken: type: string '400': description: Invalid or expired OTP '500': description: Server error /api/register: post: summary: Register a new user description: Creates a new user account with username, email, and password. requestBody: required: true content: application/json: schema: type: object properties: username: type: string example: testuser email: type: string example: user@example.com password: type: string example: password123 required: - email - password responses: '201': description: User registered successfully content: application/json: schema: type: object properties: token: type: string refreshToken: type: string '400': description: Invalid input or email already exists content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '500': description: Server error /api/verify-token: get: summary: Verify JWT token description: Verifies the provided JWT token and returns user information. security: - bearerAuth: [] responses: '200': description: Token is valid content: application/json: schema: type: object properties: valid: type: boolean userId: type: string isAdmin: type: boolean username: type: string profile: $ref: '#/components/schemas/UserProfile' '401': description: Token is required '403': description: Invalid token '404': description: User not found /api/logout: post: summary: Log out a user description: Invalidates the refresh token and logs out the user. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: refreshToken: type: string required: - refreshToken responses: '200': description: Logged out successfully content: application/json: schema: type: object properties: message: type: string example: Logged out successfully '404': description: User not found '500': description: Server error /api/upload: post: summary: Upload a file description: Uploads a file (JPEG, PNG, or PDF) to Cloudinary (authenticated users only). security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary required: - file responses: '200': description: File uploaded successfully content: application/json: schema: type: object properties: message: type: string example: "File uploaded successfully: " '400': description: No file uploaded or invalid file type '401': description: Authentication required /api/projects: get: summary: Get all projects description: Retrieves a list of all projects. responses: '200': description: List of projects content: application/json: schema: type: array items: $ref: '#/components/schemas/Project' '500': description: Server error post: summary: Create a new project description: Creates a new project (admin only). security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: title: type: string example: Project Title description: type: string example: Project description image: type: string example: https://example.com/image.jpg rating: type: string example: High stars: type: number example: 5 links: type: array items: type: object properties: option: type: string value: type: string isPrivate: type: boolean required: - title - description - image - rating - stars - links responses: '201': description: Project created content: application/json: schema: $ref: '#/components/schemas/Project' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '403': description: Admin access required '500': description: Server error /api/projects/{projectId}: put: summary: Update a project description: Updates an existing project (admin only). security: - bearerAuth: [] parameters: - in: path name: projectId required: true schema: type: string description: The ID of the project to update requestBody: required: true content: application/json: schema: type: object properties: title: type: string example: Updated Project Title description: type: string example: Updated project description image: type: string example: https://example.com/updated-image.jpg rating: type: string example: High stars: type: number example: 4 links: type: array items: type: object properties: option: type: string value: type: string isPrivate: type: boolean required: - title - description - image - rating - stars - links responses: '200': description: Project updated content: application/json: schema: $ref: '#/components/schemas/Project' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '403': description: Admin access required '404': description: Project not found '500': description: Server error delete: summary: Delete a project description: Deletes a project and its associated comments (admin only). security: - bearerAuth: [] parameters: - in: path name: projectId required: true schema: type: string description: The ID of the project to delete responses: '204': description: Project deleted '403': description: Admin access required '500': description: Server error /api/comments/{projectId}: get: summary: Get comments for a project description: Retrieves all comments for a specific project. parameters: - in: path name: projectId required: true schema: type: string description: The ID of the project responses: '200': description: List of comments content: application/json: schema: type: array items: $ref: '#/components/schemas/Comment' '500': description: Server error /api/comments: get: summary: Get all comments description: Retrieves all comments with user and project details (admin only). security: - bearerAuth: [] responses: '200': description: List of comments content: application/json: schema: type: array items: type: object properties: _id: type: string projectId: type: string projectTitle: type: string userId: type: object properties: username: type: string email: type: string rating: type: number text: type: string timestamp: type: string format: date-time replies: type: array items: type: object properties: text: type: string timestamp: type: string format: date-time '403': description: Admin access required '500': description: Server error post: summary: Add a comment description: Adds a new comment to a project (authenticated users only). security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: projectId: type: string example: 507f1f77bcf86cd799439011 rating: type: number example: 5 text: type: string example: Great project! required: - projectId - rating - text responses: '201': description: Comment added content: application/json: schema: $ref: '#/components/schemas/Comment' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '401': description: Authentication required '500': description: Server error /api/comments/{commentId}/reply: post: summary: Reply to a comment description: Adds a reply to an existing comment (admin only). security: - bearerAuth: [] parameters: - in: path name: commentId required: true schema: type: string description: The ID of the comment to reply to requestBody: required: true content: application/json: schema: type: object properties: text: type: string example: Thanks for your feedback! required: - text responses: '200': description: Reply added content: application/json: schema: $ref: '#/components/schemas/Comment' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '403': description: Admin access required '404': description: Comment not found '500': description: Server error /api/comments/{commentId}: delete: summary: Delete a comment description: Deletes a comment (admin only). security: - bearerAuth: [] parameters: - in: path name: commentId required: true schema: type: string description: The ID of the comment to delete responses: '204': description: Comment deleted '403': description: Admin access required '500': description: Server error /api/skills: get: summary: Get all skills description: Retrieves a list of all skills. responses: '200': description: List of skills content: application/json: schema: type: array items: $ref: '#/components/schemas/Skill' '500': description: Server error post: summary: Create a new skill description: Creates a new skill (admin only). security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: name: type: string example: JavaScript icon: type: string example: https://example.com/icon.png percentage: type: number example: 90 required: - name - icon - percentage responses: '201': description: Skill created content: application/json: schema: $ref: '#/components/schemas/Skill' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '403': description: Admin access required '500': description: Server error /api/skills/{skillId}: put: summary: Update a skill description: Updates an existing skill (admin only). security: - bearerAuth: [] parameters: - in: path name: skillId required: true schema: type: string description: The ID of the skill to update requestBody: required: true content: application/json: schema: type: object properties: name: type: string example: Updated JavaScript icon: type: string example: https://example.com/updated-icon.png percentage: type: number example: 95 required: - name - icon - percentage responses: '200': description: Skill updated content: application/json: schema: $ref: '#/components/schemas/Skill' '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '403': description: Admin access required '404': description: Skill not found '500': description: Server error delete: summary: Delete a skill description: Deletes a skill (admin only). security: - bearerAuth: [] parameters: - in: path name: skillId required: true schema: type: string description: The ID of the skill to delete responses: '204': description: Skill deleted '403': description: Admin access required '500': description: Server error /api/profile/{nickname}: get: summary: Get a user's profile description: Retrieves a user's profile by nickname or username. parameters: - in: path name: nickname required: true schema: type: string description: The nickname or username of the user responses: '200': description: User profile content: application/json: schema: $ref: '#/components/schemas/UserProfile' '404': description: User not found /api/profile: put: summary: Update user profile description: Updates the authenticated user's profile, including optional file uploads for avatar and project images. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object properties: nickname: type: string example: johndoe jobTitle: type: string example: Full-Stack Developer bio: type: string example: Experienced developer with a passion for web technologies phone: type: string example: +1234567890 socialLinks: type: string example: '{"linkedin":"https://linkedin.com/in/johndoe","github":"https://github.com/johndoe"}' education: type: string example: '[{"institution":"University","degree":"BSc","year":"2020"}]' experience: type: string example: '[{"company":"Tech Corp","role":"Developer","duration":"2020-2022"}]' certificates: type: string example: '[{"name":"AWS Certified","issuer":"Amazon","year":"2021"}]' skills: type: string example: '[{"name":"JavaScript","percentage":90}]' projects: type: string example: '[{"title":"Project X","description":"A web app","image":"https://example.com/image.jpg"}]' interests: type: string example: '["coding","gaming"]' isPublic: type: boolean example: true avatarDisplayType: type: string enum: ['svg', 'normal'] example: normal svgColor: type: string example: '#000000' avatar: type: string format: binary projectImages: type: array items: type: string format: binary responses: '200': description: Profile updated content: application/json: schema: type: object properties: success: type: boolean message: type: string example: Profile updated successfully profile: $ref: '#/components/schemas/UserProfile' hasTransparency: type: boolean '400': description: Invalid input content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '401': description: Authentication required '404': description: User not found '500': description: Server error /api/profile/pdf/{nickname}: get: summary: Generate a PDF resume description: Generates a PDF resume for a user by nickname, using jsPDF with autoTable for professional formatting. Only accessible for public profiles or authenticated users. parameters: - in: path name: nickname required: true schema: type: string description: The nickname or username of the user responses: '200': description: PDF resume generated content: application/pdf: schema: type: string format: binary '403': description: Profile is private '404': description: User not found '500': description: Server error /api/notifications: get: summary: Get user notifications description: Retrieves all notifications for the authenticated user (admin only). security: - bearerAuth: [] responses: '200': description: List of notifications content: application/json: schema: type: array items: $ref: '#/components/schemas/Notification' '403': description: Admin access required '500': description: Server error /api/user-interactions: get: summary: Get user interactions description: Retrieves all comments made by the authenticated user. security: - bearerAuth: [] responses: '200': description: List of user comments content: application/json: schema: type: array items: $ref: '#/components/schemas/Comment' '401': description: Authentication required '500': description: Server error /api/users: get: summary: Get all users description: Retrieves a list of all users (admin only). security: - bearerAuth: [] responses: '200': description: List of users content: application/json: schema: type: array items: type: object properties: username: type: string email: type: string profile: $ref: '#/components/schemas/UserProfile' '403': description: Admin access required '500': description: Server error /api/users/{userId}: delete: summary: Delete a user description: Deletes a user and their comments (admin only). security: - bearerAuth: [] parameters: - in: path name: userId required: true schema: type: string description: The ID of the user to delete responses: '204': description: User deleted '403': description: Admin access required '500': description: Server error /api/forgot-password: post: summary: Request password reset description: Sends a password reset OTP to the user's email. requestBody: required: true content: application/json: schema: type: object properties: email: type: string example: user@example.com required: - email responses: '200': description: Reset code sent content: application/json: schema: type: object properties: message: type: string example: Reset code sent to your email '400': description: Email required '404': description: User not found '500': description: Server error /api/reset-password: post: summary: Reset password description: Resets the user's password using the OTP. requestBody: required: true content: application/json: schema: type: object properties: email: type: string example: user@example.com otp: type: string example: "123456" newPassword: type: string example: newpassword123 required: - email - otp - newPassword responses: '200': description: Password reset successfully content: application/json: schema: type: object properties: message: type: string example: Password reset successfully '400': description: Invalid input or OTP content: application/json: schema: type: object properties: errors: type: array items: type: object properties: msg: type: string param: type: string location: type: string '500': description: Server error /api/health: get: summary: Check server health description: Checks the health of the server and MongoDB connection. responses: '200': description: Server is healthy content: application/json: schema: type: object properties: status: type: string example: ok mongodb: type: string example: connected timestamp: type: string format: date-time '500': description: Server error /api/users/search: get: summary: Search users description: Searches for public users by nickname or username. parameters: - in: query name: query required: true schema: type: string description: Search query for nickname or username responses: '200': description: List of matching users content: application/json: schema: type: array items: type: object properties: username: type: string nickname: type: string avatar: type: string profileUrl: type: string portfolioName: type: string '500': description: Server error /api/conversations/export: get: summary: Export conversations description: Exports all conversations as a CSV file (admin only). security: - bearerAuth: [] responses: '200': description: Conversations exported as CSV content: text/csv: schema: type: string format: binary '403': description: Admin access required '500': description: Server error /api/github-projects: get: summary: Get GitHub projects description: Retrieves the GitHub repositories for the user Mark-Lasfar. responses: '200': description: List of GitHub repositories content: application/json: schema: type: array items: type: object properties: id: type: number name: type: string description: type: string html_url: type: string created_at: type: string format: date-time '500': description: Server error /auth/google: get: summary: Initiate Google OAuth login description: Redirects to Google for OAuth authentication. responses: '302': description: Redirect to Google authentication /auth/facebook: get: summary: Initiate Facebook OAuth login description: Redirects to Facebook for OAuth authentication. responses: '302': description: Redirect to Facebook authentication /api/revoke-token: post: summary: Revoke a specific refresh token tags: [Authentication] security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: refreshToken: type: string description: The refresh token to revoke required: - refreshToken responses: 200: description: Refresh token revoked successfully content: application/json: schema: type: object properties: success: type: boolean message: type: string 400: description: Invalid request 401: description: Unauthorized 500: description: Server error /auth/github: get: summary: Initiate GitHub OAuth login description: Redirects to GitHub for OAuth authentication. responses: '302': description: Redirect to GitHub authentication /auth/google/callback: get: summary: Google OAuth callback description: Handles the callback from Google OAuth and redirects with tokens. responses: '302': description: Redirect to client with tokens or error /auth/facebook/callback: get: summary: Facebook OAuth callback description: Handles the callback from Facebook OAuth and redirects with tokens. responses: '302': description: Redirect to client with tokens or error /auth/github/callback: get: summary: GitHub OAuth callback description: Handles the callback from GitHub OAuth and redirects with tokens. responses: '302': description: Redirect to client with tokens or error /: get: summary: Welcome message description: Returns a welcome message for the API. responses: '200': description: Welcome message content: application/json: schema: type: object properties: message: type: string example: Welcome to Ibrahim Al-Asfar's Portfolio Backend API