Manpower service supplier application

Wathsala Rasanjalee Ganewatta
11 min readMay 31, 2021

Easy Way

An application to find manpower easily and securely with their own choice with nearest workers. Open platform to interact with people who are given their manpower. Responsive application.

Introduction

Compared to the way people lived in Sri Lanka 10 to 20 years ago, the reason why people are busier today is because of the competitive nature of the economy today. As a result, even women have become involved in the economic process. Because of this, most of the older people in the house are very busy. The person who leaves home in the morning returns home after nightfall. If they need to make any repairs or needs in their home, they will have to spend extra time on it. In some cases, the internet may even be used to buy household items.

some people even look for someone to take care of their child. We have to be very careful when looking for someone for that. Because if the caregiver is an insecure person, our child is insecure. So when looking for someone we need to know more about that person’s character and how they have acted before.

Some people even look for someone to repair their house. In our society, there are a lot of thieves, robbers so we have to take some risk to give the responsibility of the house to do the things anyone else.

We can hire anyone from the manpower agency. But we have to take extra time on that because we have to call to agency or go to the agency and find out someone. But in that case, we can’t sure we hire a good or bad person. We must have to trust the agency with that person. Because that agency recommends that person to us. Or otherwise, we have to talk with other persons who get the service from that man. And get an idea about that person. For all of that processes take some time from their valuable time.

There is another way to find a person. That was calling for that job vacancy through a trustworthy person or website.

Problem

With our busy lives, it’s not easy to find secure manpower. But nowadays people can find it through manpower agencies. But for that, we also have to spend some time finding a good service.

We have to trust the manpower agency when we choose a man. And also we have to search about their history and it takes some time to get an idea about that man. In Sri Lanka, there are lots of agencies that provide manpower services. But we can’t find the best person with a fair charge from those agencies from one place.

Problems:

Nowadays we can’t trust anyone in our first impression. Believing only one person’s word and giving some responsibilities to unknown parties is a dangerous thing.

Solution

Most of the people are going with the technology. And like to live with technology because they want to do everything easily. So that for searching manpower I propose a mobile and web application. I call it Easyway.

Functionalities

Using that, I propose to do the process of choosing manpower service.

  • Customers can find the nearest workers
  • From that workers can choose top rated workers
  • And also can view how they got feedback.
  • Workers cant directly register to the system. they have to give their details to agencies and agencies must register that worker into the system.
  • customers and agencies can directly get access to the system with their valid mail id.
  • customers can make a reservation to the worker for some time, but the worker must accept it within a limited period. if they do not accept it the customer can cancel it and book another worker.
  • After completing the task customers and workers can give feedback to each other.
  • and also can do payments through the system
  • Workers are registered to the agency with a license period. To get the license, they have to pay some amount of value to the agency. That value varies based on the agency.
  • If any worker gets the worst feedback from customers continuing, the system admin can remove that worker from the system after informing the agency.
  • through the system, any user can take a chat with another user. (like customers and workers, workers and agencies, customers and agencies)

Design Architecture

Design Architecture

Implementation steps

I was supposed to do the processes version-wise. so for the first step, I implemented some parts of the system with basic transactions between worker and customer and the agent.

Version 1

  • Requirements gathering and design the use case diagram
  • Design sketches for UIs
  • Implementing main services. ( Feedback service, Booking service, User service, Authentication service, GraphQL server, Mail service )
  • Integrate with frontend and backend

Version 2

  • Implementing the payment service

Version 3

  • Implementing message broker

Version 1

- For the first step, I create a simple use case diagram

a simple use case diagram

- Then design UIs for the application

All the forms are validated using form Builder.

landing page
customer registration page
agency registration page
login page
workers adding page with available worker page
user view with feedback ( received, sent, and give feedback to others)

For UI implementations I have created a rating bar in my own way to display and to set rate to that bar. For the rating bar, I have created a different component to implement.

For Example rate-bar.component.html:

<div><div *ngIf="display"><span class="fa fa-star {{givenRate>=1? 'checked':'nonchecked'}}"></span><span class="fa fa-star {{givenRate>=2? 'checked':'nonchecked'}}"></span><span class="fa fa-star {{givenRate>=3? 'checked':'nonchecked'}}"></span><span class="fa fa-star {{givenRate>=4? 'checked':'nonchecked'}}"></span><span class="fa fa-star {{givenRate>=5? 'checked':'nonchecked'}}"></span></div><div *ngIf="setFeedback"><span class="fa fa-star {{givenRate>=1? 'checked':'nonchecked'}}" (click)="setRate(1)"></span><span class="fa fa-star {{givenRate>=2? 'checked':'nonchecked'}}" (click)="setRate(2)"></span><span class="fa fa-star {{givenRate>=3? 'checked':'nonchecked'}}" (click)="setRate(3)"></span><span class="fa fa-star {{givenRate>=4? 'checked':'nonchecked'}}" (click)="setRate(4)"></span><span class="fa fa-star {{givenRate>=5? 'checked':'nonchecked'}}" (click)="setRate(5)"></span></div></div>

For Example rate-bar.component.css:

.checked{color: darkorange;}.nonchecked{color: gainsboro;}

For Example rate-bar.component.ts :

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';@Component({selector: 'app-rate-bar',templateUrl: './rate-bar.component.html',styleUrls: ['./rate-bar.component.css']})export class RateBarComponent implements OnInit {@Input() givenRate:number = 0;@Input() display:boolean@Input() setFeedback:boolean@Output() rate:EventEmitter<number> = new EventEmitter<number>();constructor() { }ngOnInit(): void {if(this.givenRate<0 ||this.givenRate>5){this.givenRate = 0;}}setRate(rate){this.givenRate = ratethis.rate.emit(this.givenRate);}}

I have used that rating bar component on the send-feedback component to set the feedback rate.

Example from send-feedback.component.html:

<div class="form-group"><app-rate-bar [setFeedback]=true (rate)="getFeedbackRate($event)"></app-rate-bar></div>

set data using getfeedbackRate() method

getFeedbackRate(event){this.feedbackRate= event;}

I have used that rating bar component on different components to display the feedback rate.

For Example in profile.component.html :

<app-rate-bar [givenRate] = "profile.rate" [display]=true>
</app-rate-bar>

- Implement backend micro-services

User Service

There are four kinds of users like customer, agency, worker, admin. Every user has their own attributes. For example, the worker has a job title but the customer and agency don't have. The agency has a registration number but the others haven't. Every user has a different username (email) and password. In their cannot have one or more same username. all of them has role attribute. This service contact all the other services. This service implemented using nest JS.

  • Create user
  • Get user details from given user id
  • delete user from the system
  • update user details

I have implemented an AuthGuard in my user Service using that I have checked the token is valid or not. For that, I use Client Proxy to connect with the Auth service.

import { CanActivate, ExecutionContext, Inject, Logger } from "@nestjs/common";import { ClientProxy } from "@nestjs/microservices";import { timeout} from 'rxjs/operators';export class AuthGuard implements CanActivate {constructor(@Inject('AUTH_CLIENT') private readonly client: ClientProxy) {}async canActivate(context: ExecutionContext): Promise<boolean> {const req = context.switchToHttp().getRequest();try{const res = await this.client.send({ role: 'auth', cmd: 'check' },{ jwt: req.headers['authorization']?.split(' ')[1]}).pipe(timeout(5000)).toPromise<boolean>();return res;} catch(err) {Logger.error(err);return false;}}}

For the user service Create my own validator to check the username already exist or not.

Example userExist.validator.ts

import { Injectable } from "@nestjs/common";import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator";import { WorkerRepository } from "src/worker/worker.repository";import { AgentRepository } from "../agent/aget.repository";import { CustomerRepositry } from "../customer/customer.repository";@ValidatorConstraint({ name: 'UserExists', async: true })@Injectable()export class UserExistsRule implements ValidatorConstraintInterface {constructor(private usersRepository: CustomerRepositry,private agentRepository:AgentRepository,private workerRepository:WorkerRepository) {}async validate(value: string) {try {await this.usersRepository.getOneOrFail(value);await this.agentRepository.getOneOrFail(value);await this.workerRepository.getOneOrFail(value);} catch (e) {return false;}return true;}defaultMessage(args: ValidationArguments) {return `${args.value} username already exist `;}}

Using that validator in to. Example customerCreate.dto.ts

import { IsEmail, IsNotEmpty, registerDecorator, ValidationOptions } from "class-validator"import { UserExistsRule } from "../validators/userExist.validator"export class CustomerCreateDto{@IsNotEmpty()firstName:stringlastName:stringlocation:stringrate:stringrole:string@UserExists()@IsEmail()username:string@IsNotEmpty()password:stringimage:string}function UserExists(validationOptions?: ValidationOptions) {return function (object: any, propertyName: string) {registerDecorator({name: 'UserExists',target: object.constructor,propertyName: propertyName,options: validationOptions,validator: UserExistsRule,});};}

Authorization Service

Using Authorization service check the user is a valid user with contacting the user service and if it is a valid user then create a token by signing that token by a secret key. And also set a time period to expire that token. This service implemented using nest js.

  • Get user profile from user service
  • authorize the login
  • validate token
@MessagePattern({ role: 'auth', cmd: 'check'})async loggedIn(data) {try {const res = this.authService.validateToken(data.jwt);return res;} catch(e) {Logger.log(e);return false;}}

Feedback Service

Using feedback service any user except admin can give feedback to others. And also can view sent feedbacks and received feedbacks. Feedback has from whom feedback, to whom feedback, given feedback rate, and the feedback message. This service implemented using nest js as a microservice.

  • Create feedback
  • Get a total rate for the user by using the user id.

customer ← → worker

worker ← → agent

agent ←→ customer

Every user could view their total average feedback rate from their profile. For that from the feedback service calculate the average feedback rate.

async getRate(id:string){let feedbacks = await this.findAll();let rates=0;let avgRate = 0;let selectedUserFeedbacks = feedbacks.filter((feedback)=>feedback.feedbackTo == id)if(selectedUserFeedbacks.length>0){selectedUserFeedbacks.forEach((feedback)=>{rates+=feedback.feedbackRate;})avgRate = rates/selectedUserFeedbacks.length;}else{return 0;}return Math.round(avgRate);}
profile card shows the average feedback rate

Mail Service

Using mail service sent notification in all the cases need to inform that user. That part is an ongoing process. For example when register to the system sends a mail to the user mail by saying the user has successfully registered with that system. This service implemented using node mailer and using express js.

async function sendMail(user,callback){let transporter = nodemailer.createTransport({host:'smtp.gmail.com',port:587,secure:false,auth:{user:"easyWay.manpowerService@gmail.com",pass:"*******"}});let mailOptions= {from:'"EasyWay Manpower"',to:user.email,subject:"Welcome to Easy way",html:`<h1> Hi ${user.name} &#128512;</h1><br><h4> Thanks for Joining us...</h4>`}let info = await transporter.sendMail(mailOptions);callback(info);}
email when the user registered to the system

Booking Service

Booking service mainly uses customers to make a reservation for the worker. For a booking has booking status, booking date, who reserved? , who made the booking?.

  • display all the bookings
  • display all the booking with a user id
  • Create booking
  • Cancel booking

- Implement the GraphQL server

Through graphQL server call all the endpoints within one endpoint. For the REST APIs create their own schema on the graphQL server. For the get request, write queries and for the post request, write mutations.

For Example:

submit(){const LOGIN =gql`mutation login($username:String,$password:String){login(username:$username,password:$password){userIduserRoleaccessTokenlocation}}`this.apollo.mutate({mutation:LOGIN,variables:{username:this.form.value.username,password:this.form.value.password}}).subscribe(({data})=>{this.user = datalocalStorage.setItem(‘token’,this.user.login.accessToken)localStorage.setItem(‘userId’,this.user.login.userId)localStorage.setItem(‘userRole’,this.user.login.userRole)localStorage.setItem(‘location’,this.user.login.location)if(localStorage.getItem(‘userRole’) == ‘customer’){this.route.navigate([‘customer’])}if(localStorage.getItem(‘userRole’) == ‘agent’){this.route.navigate([‘agent’])}if(localStorage.getItem(‘userRole’) == ‘worker’){this.route.navigate([‘worker’])}})}

- Deploy the Application to Production server

  • Hope to do it by Dockerization. And using Docker Hub.

Technology stack

Back-end software tools stack

  • Node JS
  • Nest JS
  • GraphQL
  • MongoDB

Client-side software tools stacks

  • Angular 9

Why did I choose these tech stacks?

Nest JS

  • Node js can be used on both sides of backend and frontend development.
  • Most developers focus on node js because of its speed.
  • Nest js is the fastest-growing framework among the frameworks and well-documented frameworks for developing node js applications.
  • Nest js leverages typescript.
  • Nest js can learn quickly.
  • Support for dozens of nest-specific modules that help you easily integrate with common technologies and concepts like TypeORM, Mongoose, GraphQL, Logging, Validation, Caching, WebSockets, and much more.
  • NestJS forces developers to use a specific architecture by introducing Angular-like modules, services, and controllers, ensuring the application is scalable, highly testable

Angular

Reusability

  • Because of its component-based structure. Those components are highly reusable across the application.

Readability

  • If anyone new that project the new developers easily go through the application

Easy to unit testing

  • components are independent that makes the component unit testing easy.

Easy to maintain

  • Components are easy to maintain and can easy to update coding implementations

GraphQL

  • Has Schema Definition Languages ( SDL )
  • Schema serves as the contract between the client and the server to define how a client can access the data.
  • In that schema write all the types that exposed in APIs
  • GraphQL is acting as an API Gateway.

MongoDB

  • It is a document-oriented database
  • It allows developers to work fast because the document data model is a powerful way to store and retrieve data.
  • And also its non-relation database
  • It is immediately understandable to anyone.
  • it stores data in key/value pair type and it stores information as series of binary JSON or BSON

References

I have used different media as a reference

youtube:

For Nest JS implementations

For GraphQL implementations

For Angular implementations

For Bootstrap implementations

For Access locations

For mail Service

--

--