Recruitify - Where Talent Meets Opportunity
Tags: devchallenge, awschallenge, amplify, fullstack
Published: 2024-05-27 05:33:59

*This is a submission for the [The AWS Amplify Fullstack TypeScript Challenge ](https://dev.to/challenges/aws)*

## What I Built

**Recruitify** is a platform designed to bridge the gap between job seekers and employers. It provides a seamless experience for both parties to find the perfect match for their needs.


## Features
**Employer**
- Create Job Postings: Employers can create detailed job listings specifying required skills, experience, location, and more.
- Manage Applications: Employers can efficiently manage and validate applications received for their job postings.

**Job Seeker**
- Browse Jobs: Job seekers can search and filter job listings based on their preferences.
- Apply for Jobs: Easily apply for various job opportunities.
- Receive Notifications: Get notified about new job listings that match your skills

## Demo and Code
**Recruitify** is available [here](https://main.d14oy3wnmg7qbg.amplifyapp.com/) and the code is available on GitHub. {% embed https://github.com/mtwn105/recruitify %}

### Screenshots

Browse Jobs Page
![Browse Jobs Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0zoqco99fx2x0zyq3mc.png)

Edit Profile
![Edit Profile](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rvwyhqc3ep9fpbu26hk.png)

Create/Edit Job Posting
![Create/Edit Job Posting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xcu601w7fid33rqus1z.png)
![Create/Edit Job Posting2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ww7prb0rdtiz2ctcwo0v.png)

Generate Job Description
![Generate Job Description
](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/llvf6zgnnru0mxj0adjk.png)

Job Details Page (Job Creator)
![Job Details Page (Job Creator)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72o7a91ymvwmba1eyz3m.png)

Job Details Page (Job Seeker)
![Job Details Page (Job Seeker)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abmxtlvbt18jtjgoo738.png)

Job Applications Page (Job Seeker)
![Job Seeker](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqhea926ewge6qbap3r3.png)

Job Applications Page (Job Creator)
![Job Applications Page (Job Creator)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7r39avlzyrishvioszp.png)

New Job Notification
![New Job Notification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ejyto9hwbxyv0plev8p.png)

## Integrations
### Tech Stack
- **Backend**: AWS Amplify
- **Frontend**: Angular 17, Angular Material, Tailwind CSS
- **AWS Technologies**: Data (DynamoDB), Authentication (Cognito), Serverless Functions (Lambda), File Storage (S3), AI (Bedrock)
- **Hosting**: AWS Amplify

**Connected Components and Feature Full**

This project uses Amplify connected components for Angular - **Authenticator** for users to sign up and log in.

This project also integrates all four integrations - **Data, Authentication, Serverless Functions, File Storage**

### AWS Amplify

**Architecture**

![recruitify-aws-architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k24glf82owsx0w66p5qd.png)

**Authentication**

Utilizes AWS Amplify Authentication for user sign-up and login via email which uses AWS Cognito services.

Configured in `amplify/auth/resource.ts` 

```typescript 
export const auth = defineAuth({
  loginWith: {
    email: true,
  }
});
```

Implemented with the Amplify UI component `<amplify-authenticator>` for Angular.

**Data**

Utilizes AWS Amplify Data to store information about **Users**, **Companies**, and **Jobs** which uses AWS DynamoDB. Database Design is shown above.

Configured in `amplify/data/resource.ts` 

**Database Design**
![Recruityfy-DB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2u5ksntgvh84ju606pl.png) 
 
**Storage**

AWS Amplify S3 Storage is used for storing company **logos** and job seeker **resumes**.

Configured in `amplify/storage/resource.ts`

```typescript
export const storage = defineStorage({
  name: 'recruitifyFiles',
  access: (allow) => ({
    'companyLogos/*': [
      allow.authenticated.to(['read', 'write']),
      allow.guest.to(['read', 'write'])
    ],
    'resumes/*': [
      allow.authenticated.to(['read', 'write']),
      allow.guest.to(['read', 'write'])
    ],
  })
});
```

The files were uploaded using `uploadData` like below

```typescript
 const result = await uploadData({
        data: this.previewUrl,
        path: `companyLogos/${this.authService?.userProfile?.id}`,
      }).result;
```

And the files were downloaded when necessary using `downloadData` like below

```typescript
 downloadData({ path: profile.data[0].resume })
```

**Functions**

AWS Amplify Lambda Functions are used to send **New Job Notifications** to job seekers matching their skill set and **Generate Job Description** to generate job descriptions for job creators.

Used AWS Amplify **AppSync GraphQL API** inside the function to find relevant job seekers and create new job notifications.

Used **AWS Bedrock** with Mistral AI Model inside the function to generate job description.


Configured in `amplify/functions/new-job/handler.ts`

Triggered when a new job is created by an employer using a mutation in data like the below:

```typescript
sendJobNotification: a.mutation()
    .arguments({ jobId: a.string(), companyId: a.string() })
    .returns(a.string())
    .authorization(allow => [allow.publicApiKey()])
    .handler(a.handler.function(newJob))
```

```typescript
client.mutations.sendJobNotification({
        jobId: job.data?.id,
        companyId: job.data?.companyId
      }).then((job) => {
        console.log(job)
      })
```

Triggered generate job description like the below:

```typescript
generateJobDescription: a.mutation()
    .arguments({ title: a.string(), minExperience: a.float(), skills: a.string(), domain: a.string() })
    .returns(a.string())
    .authorization(allow => [allow.publicApiKey()])
    .handler(a.handler.function(generateJobDescription))
```

```typescript
client.mutations.generateJobDescription({
      title: this.createJobForm.value.title,
      skills: this.skills.join(','),
      domain: this.createJobForm.value.domain,
      minExperience: this.createJobForm.value.minExperience,
    }).then((response) => {
      console.log(response);
      if (response?.data) {
        this.createJobForm.patchValue({
          description: response.data
        })
      }
    }).finally(() => {
      this.loadingService.hide();
    })
```

Used **Mistral 7B** model with prompt like this:

```typescript
 const text = `
          Job Title: ${title}
          Job Domain: ${domain}
          Job Min Experience: ${minExperience} years
          Job Required Skills: ${skills}
        `
    const prompt = `Your task is to generate a job description for below-given job details.

        Job Details: ${text}

        Job Description: `
```

And invoke the model like below:

```typescript
const input = {
      modelId: "mistral.mistral-7b-instruct-v0:2",
      contentType: "application/json",
      accept: "application/json",
      body: JSON.stringify({
        prompt: `

 ${prompt} 
`,
        max_tokens: 2000,
        temperature: 0.5,
      }),
    } as InvokeModelCommandInput;
```

**Hosting**

Utilised AWS Hosting for seamless deployment of the application.

## Future Scope

- **Application Notifications**: Notifications for Job Application status changes for both job seekers and employers
- **Realtime chat messaging**: Realtime chat messaging between job seeker and employer

## Conclusion

**Recruitify** leverages the power of **AWS Amplify** to deliver a robust, full-stack application. A lot to learn while working with AWS and AWS Amplify toolkit along with Angular on this project.