{"id":28640555,"url":"https://github.com/mrcoder57/freelance-backend","last_synced_at":"2025-06-12T20:07:06.616Z","repository":{"id":293073328,"uuid":"932221110","full_name":"mrcoder57/freelance-backend","owner":"mrcoder57","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-29T19:39:49.000Z","size":561,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-29T20:39:30.239Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrcoder57.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-13T15:10:40.000Z","updated_at":"2025-05-29T19:39:53.000Z","dependencies_parsed_at":"2025-05-13T15:33:05.314Z","dependency_job_id":"7e563a6f-16d3-4f8c-ae54-4f6b876fbb43","html_url":"https://github.com/mrcoder57/freelance-backend","commit_stats":null,"previous_names":["mrcoder57/freelance-backend"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mrcoder57/freelance-backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrcoder57%2Ffreelance-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrcoder57%2Ffreelance-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrcoder57%2Ffreelance-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrcoder57%2Ffreelance-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrcoder57","download_url":"https://codeload.github.com/mrcoder57/freelance-backend/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrcoder57%2Ffreelance-backend/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259522109,"owners_count":22870449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-12T20:07:04.311Z","updated_at":"2025-06-12T20:07:06.606Z","avatar_url":"https://github.com/mrcoder57.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Freelance Backend API\n\nThis is the backend API for a freelance platform that connects freelancers with clients. It includes functionality for authentication, job posting, proposals, messaging, and more.\n\n## Technologies\n\n- **Runtime**: Bun\n- **Framework**: Hono.js\n- **Database**: MongoDB (Mongoose)\n- **Messaging**: Upstash Redis\n- **Real-time Communication**: WebSockets\n- **File Storage**: AWS S3\n\n## Getting Started\n\n### Prerequisites\n\n- Bun runtime\n- MongoDB\n- Upstash Redis account\n\n### Installation\n\n1. Clone the repository\n2. Install dependencies:\n   ```\n   bun install\n   ```\n3. Set up environment variables in a `.env` file:\n   ```\n   # Server Configuration\n   PORT=3000\n\n   # MongoDB Connection\n   MONGODB_URI=mongodb://localhost:27017/freelance-db\n   \n   # Upstash Redis Configuration\n   UPSTASH_REDIS_REST_URL=your_upstash_redis_url\n   UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_token\n   \n   # JWT Secrets\n   JWT_SECRET=your_jwt_secret_key\n   KAFKA_SECRET=your_secret_key_for_jwt\n   \n   # AWS S3 Credentials\n   AWS_ACCESS_KEY_ID=your_aws_access_key\n   AWS_SECRET_ACCESS_KEY=your_aws_secret_key\n   AWS_REGION=your_aws_region\n   AWS_BUCKET_NAME=your_bucket_name\n   ```\n\n4. Start the server:\n   ```\n   bun run src/index.ts\n   ```\n\n## API Documentation\n\n### Authentication\n\n#### Sign up\n\n- **URL**: `/signup`\n- **Method**: `POST`\n- **Body**:\n  ```json\n  {\n    \"email\": \"user@example.com\",\n    \"password\": \"password123\",\n    \"firstName\": \"John\",\n    \"lastName\": \"Doe\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"message\": \"User registered successfully\",\n    \"token\": \"jwt_token\"\n  }\n  ```\n\n#### Login\n\n- **URL**: `/login`\n- **Method**: `POST`\n- **Body**:\n  ```json\n  {\n    \"email\": \"user@example.com\",\n    \"password\": \"password123\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"token\": \"jwt_token\",\n    \"user\": {\n      \"id\": \"user_id\",\n      \"email\": \"user@example.com\",\n      \"firstName\": \"John\",\n      \"lastName\": \"Doe\"\n    }\n  }\n  ```\n\n#### Google Auth\n\n- **URL**: `/auth/google`\n- **Method**: `GET`\n- **Response**: Redirects to Google authentication\n\n- **URL**: `/auth/google/callback`\n- **Method**: `GET`\n- **Response**: Redirects with authentication token\n\n#### Forgot Password\n\n- **URL**: `/forgot-password`\n- **Method**: `POST`\n- **Body**:\n  ```json\n  {\n    \"email\": \"user@example.com\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"message\": \"Password reset email sent\"\n  }\n  ```\n\n### Profile Management\n\n#### Get Profile\n\n- **URL**: `/profile`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"profile\": {\n      \"id\": \"user_id\",\n      \"email\": \"user@example.com\",\n      \"firstName\": \"John\",\n      \"lastName\": \"Doe\",\n      \"bio\": \"...\",\n      \"skills\": [\"skill1\", \"skill2\"]\n    }\n  }\n  ```\n\n#### Update Profile\n\n- **URL**: `/profile`\n- **Method**: `PUT`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**:\n  ```json\n  {\n    \"firstName\": \"John\",\n    \"lastName\": \"Doe\",\n    \"bio\": \"Updated bio\",\n    \"skills\": [\"skill1\", \"skill2\", \"skill3\"]\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"message\": \"Profile updated successfully\"\n  }\n  ```\n\n### File Upload\n\n- **URL**: `/upload`\n- **Method**: `POST`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**: Form data with file\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"fileUrl\": \"https://your-s3-bucket.amazonaws.com/path/to/file\"\n  }\n  ```\n\n### Jobs\n\n#### Create Job\n\n- **URL**: `/jobs`\n- **Method**: `POST`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**:\n  ```json\n  {\n    \"title\": \"Job Title\",\n    \"description\": \"Job Description\",\n    \"budget\": 500,\n    \"skills\": [\"skill1\", \"skill2\"],\n    \"duration\": \"1 month\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"job\": {\n      \"id\": \"job_id\",\n      \"title\": \"Job Title\",\n      \"description\": \"Job Description\",\n      \"budget\": 500,\n      \"skills\": [\"skill1\", \"skill2\"],\n      \"duration\": \"1 month\",\n      \"client\": \"client_id\",\n      \"createdAt\": \"timestamp\"\n    }\n  }\n  ```\n\n#### Get All Jobs\n\n- **URL**: `/jobs`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Query Parameters**:\n  - `page`: Page number (default: 1)\n  - `limit`: Items per page (default: 10)\n  - `search`: Search term\n  - `skills`: Skills filter (comma-separated)\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"jobs\": [\n      {\n        \"id\": \"job_id\",\n        \"title\": \"Job Title\",\n        \"description\": \"Job Description\",\n        \"budget\": 500,\n        \"skills\": [\"skill1\", \"skill2\"],\n        \"duration\": \"1 month\",\n        \"client\": \"client_id\",\n        \"createdAt\": \"timestamp\"\n      }\n    ],\n    \"pagination\": {\n      \"page\": 1,\n      \"limit\": 10,\n      \"totalPages\": 5,\n      \"totalItems\": 50\n    }\n  }\n  ```\n\n#### Get Job by ID\n\n- **URL**: `/jobs/:id`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"job\": {\n      \"id\": \"job_id\",\n      \"title\": \"Job Title\",\n      \"description\": \"Job Description\",\n      \"budget\": 500,\n      \"skills\": [\"skill1\", \"skill2\"],\n      \"duration\": \"1 month\",\n      \"client\": \"client_id\",\n      \"createdAt\": \"timestamp\"\n    }\n  }\n  ```\n\n### Proposals\n\n#### Submit Proposal\n\n- **URL**: `/proposals`\n- **Method**: `POST`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**:\n  ```json\n  {\n    \"jobId\": \"job_id\",\n    \"coverLetter\": \"Cover letter content\",\n    \"bidAmount\": 450,\n    \"estimatedDuration\": \"3 weeks\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"proposal\": {\n      \"id\": \"proposal_id\",\n      \"job\": \"job_id\",\n      \"freelancer\": \"user_id\",\n      \"coverLetter\": \"Cover letter content\",\n      \"bidAmount\": 450,\n      \"estimatedDuration\": \"3 weeks\",\n      \"status\": \"pending\",\n      \"createdAt\": \"timestamp\"\n    }\n  }\n  ```\n\n#### Get All Proposals for a Job\n\n- **URL**: `/proposals/job/:jobId`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"proposals\": [\n      {\n        \"id\": \"proposal_id\",\n        \"job\": \"job_id\",\n        \"freelancer\": {\n          \"id\": \"user_id\",\n          \"firstName\": \"John\",\n          \"lastName\": \"Doe\",\n          \"skills\": [\"skill1\", \"skill2\"]\n        },\n        \"coverLetter\": \"Cover letter content\",\n        \"bidAmount\": 450,\n        \"estimatedDuration\": \"3 weeks\",\n        \"status\": \"pending\",\n        \"createdAt\": \"timestamp\"\n      }\n    ]\n  }\n  ```\n\n#### Get All Proposals by User\n\n- **URL**: `/proposals/user`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"proposals\": [\n      {\n        \"id\": \"proposal_id\",\n        \"job\": {\n          \"id\": \"job_id\",\n          \"title\": \"Job Title\",\n          \"description\": \"Job Description\",\n          \"budget\": 500\n        },\n        \"coverLetter\": \"Cover letter content\",\n        \"bidAmount\": 450,\n        \"estimatedDuration\": \"3 weeks\",\n        \"status\": \"pending\",\n        \"createdAt\": \"timestamp\"\n      }\n    ]\n  }\n  ```\n\n### Messages\n\n#### Send Message\n\n- **URL**: `/message/send`\n- **Method**: `POST`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**:\n  ```json\n  {\n    \"receiverId\": \"user_id\",\n    \"content\": \"Message content\",\n    \"messageType\": \"text\",\n    \"files\": [\"file_url1\", \"file_url2\"]\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"message\": \"Message queued successfully!\"\n  }\n  ```\n\n#### Get Conversation Messages\n\n- **URL**: `/message/conversation/:conversationId`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"messages\": [\n      {\n        \"id\": \"message_id\",\n        \"conversationId\": \"conversation_id\",\n        \"sender\": {\n          \"id\": \"user_id\",\n          \"name\": \"John Doe\",\n          \"email\": \"user@example.com\"\n        },\n        \"content\": \"Message content\",\n        \"messageType\": \"text\",\n        \"files\": [\"file_url1\"],\n        \"status\": \"sent\",\n        \"createdAt\": \"timestamp\"\n      }\n    ]\n  }\n  ```\n\n#### Get All Conversations\n\n- **URL**: `/message/conversations`\n- **Method**: `GET`\n- **Headers**: `Authorization: Bearer {token}`\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"conversations\": [\n      {\n        \"_id\": \"conversation_id\",\n        \"participants\": [\n          {\n            \"_id\": \"user_id\",\n            \"firstName\": \"John\",\n            \"lastName\": \"Doe\",\n            \"image\": \"profile_image_url\"\n          },\n          {\n            \"_id\": \"user_id2\",\n            \"firstName\": \"Jane\",\n            \"lastName\": \"Smith\",\n            \"image\": \"profile_image_url\"\n          }\n        ],\n        \"lastMessage\": {\n          \"_id\": \"message_id\",\n          \"content\": \"Last message content\",\n          \"createdAt\": \"timestamp\"\n        }\n      }\n    ]\n  }\n  ```\n\n### WebSocket Connection\n\nReal-time messaging is handled through WebSocket connections:\n\n- **URL**: `/ws?token=jwt_token`\n- **Protocol**: WebSocket\n- **Authentication**: JWT token as query parameter\n\n### Agreements\n\n- **URL**: `/agreements/create`\n- **Method**: `POST`\n- **Headers**: `Authorization: Bearer {token}`\n- **Body**:\n  ```json\n  {\n    \"jobId\": \"job_id\",\n    \"freelancerId\": \"freelancer_id\",\n    \"terms\": \"Agreement terms\",\n    \"paymentAmount\": 450,\n    \"duration\": \"3 weeks\"\n  }\n  ```\n- **Response**:\n  ```json\n  {\n    \"success\": true,\n    \"agreement\": {\n      \"id\": \"agreement_id\",\n      \"job\": \"job_id\",\n      \"client\": \"client_id\",\n      \"freelancer\": \"freelancer_id\",\n      \"terms\": \"Agreement terms\",\n      \"paymentAmount\": 450,\n      \"duration\": \"3 weeks\",\n      \"status\": \"pending\",\n      \"createdAt\": \"timestamp\"\n    }\n  }\n  ```\n\n## Real-time Messaging Architecture\n\nThe application uses Upstash Redis for real-time messaging:\n\n1. Messages are published to Redis lists using the `publishMessage` function\n2. A periodic polling mechanism checks for new messages in Redis lists\n3. When a message is received, it's saved to the database and sent to relevant users via WebSockets\n4. WebSocket connections are authenticated using JWT tokens\n5. WebSocket clients receive real-time updates for new messages\n\n## Error Handling\n\nAll API endpoints return standardized error responses with appropriate HTTP status codes:\n\n```json\n{\n  \"error\": \"Error message\"\n}\n```\n\nCommon status codes:\n- `400` - Bad Request (invalid input)\n- `401` - Unauthorized (invalid or missing authentication)\n- `403` - Forbidden (insufficient permissions)\n- `404` - Not Found\n- `500` - Internal Server Error\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrcoder57%2Ffreelance-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrcoder57%2Ffreelance-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrcoder57%2Ffreelance-backend/lists"}