Organizations have different ways of managing workforce/employees. If we talk about the traditional way, for each active employee has to send out emails or fill up forms and submit it to HR. Over the time when organization size increases managing this in a traditional manner becomes a very hard problem.

It is the time when organizations started looking for employee management tools. Well, there are multiple tools already available in the market which comes with many features included inbuilt. But as an organization, you want only a few features that too which fits in your use case.

Being a startup company, HashedIn also wanted to have an employee management tool which is customized to our use cases. We came up with the workforce management tool for the services industry named as ‘HIWAY’, which is an ambitious employee management system that logs employee timesheet and every other activity and maintains employee record.

Now before starting how we came up with the solution, let’s discuss one use case. Every organization has its set of leave policies and the HR also keeps a track of their employees’ leave in one way or the other. This looks like a simple problem, but considering different policies such as different types of leave (Leave, WFH, Comp Off, Sabbatical, etc.), Leave Carry Forward, Holidays, Optional Holidays; it makes things even more complex.

Now that we understand how hard it will be doing it in a traditional way, so let’s discuss how we achieved a solution to this problem using modern tech stack in HIWAY.

When you build software, you want to start with the right foundation.“
It is always better to spend a good amount of time focusing on the design and architecture before starting off any solution. Out of many, one important aspect is “Choosing a technology stack. This is crucial because it will help in tackling hard and complex problems in development. One should also consider aspects such as performance, security, scalability, and maintainability to handle sudden traffic increase when the application starts growing.

Let’s discuss each aspect in detail:

Client-side (Front-end)

Firstly, it is important to provide employees with a nice user interface and user experience when applying for leave. Both these things are achieved using AngularJS along with Angular Material UI in HIWAY. Employees can select the date range, leave type and provide some description; using Angular Material UI Card Layout and raise a request to the respective manager. Managers can approve/deny the request and employees will be able to see the status of the request. HIWAY uses AngularJS features such as two way binding, scope variables, and filtering etc. to display the leave history of employees for different years. MomentJS is a very helpful library used here to display Date for leaves in different time-date format and also according to different time zones.
Considering that the employees will only use HIWAY web app for applying for leave, will be a wrong design choice. In the future, there can be a requirement that it will be handy for the employees to apply for leave using the mobile app. So in such cases, it is always better to separate frontend and backend logic and connect them using RESTful APIs.

Server-side (Backend)

HIWAY uses Python Django,  which is built upon Python. Python Django is very secure, scalable and carries all the advantages of coding in Python. It has a package called Django Rest Framework (DRF), which is used to create REST APIs for this problem. Once Leave Request goes to the backend using REST APIs, the backend python code validates the requests (e.g. Carry Forward + Leaves Accrued Till This Month > Leaves Opt for – Holidays ) and returns status code with some message in JSON format.

This message is shown in some form of notification in the frontend. On a valid request, it saves the entry into the database. Postgres database is used to save and retrieve all user’s Leave History. Celery package is used to run background jobs for updating Leave Carry Forward from last year to new year. Django also provides Django Admin inbuilt, in which you can create Role (e.g. HR) and give permission to view all Leave Requested by employees or to create/update Holidays list. For roles and permission related more data, you can follow the link here.

Cloud

HIWAY Application is deployed on the cloud using AWS Cloud Services. HIWAY uses service like AWS ELB which adds or removes web servers based on traffic and makes application auto scalable. HIWAY also uses S3 and Cloudfront to upload and serve static content quickly across the world.

Modern Tools

Jenkins is used in HIWAY and it tests on a non-developer machine automatically every time someone pushes new codes into the source repository. In this case, HIWAY uses GitHub. Once the test is complete it notifies on the build success or failure result to concerned teams. HIWAY uses Logentries for logging the exceptions or errors if something goes during code execution within the server. For monitoring and performance measurement HIWAY uses New Relic, which provides useful insights via Dashboard and Analytics and also sends out the mail if the server is down or the majority of requests are failing.
As shown above, using modern tech stack it makes employee management very easy and efficient. This is the just one example, with this stack, HIWAY solves problems like TimeSheet, reimbursement, PFF etc.

 

For our setup, SSL negotiation will be done by nginx on the web server, rather than by the ELB. With nginx, leveraging multiple server blocks each with its own SSL certificate is pretty straight forward. Here is what you will need:

Nginx >= 1.6.2 Ubuntu >= 14.04 AWS CLI

Prerequisites: The nginx PPA includes the required modules, so there is no need to compile a build. Feel free to adjust to your own requirements.

Install Nginx

sudo add-apt-repository -y ppa:nginx/stable
sudo apt-get update
sudo apt-get -y install nginx

The AWS CLI will require credentials provided by your account.

Install AWS CLI

sudo apt-get install awscli
aws configure

Create and Configure the Load Balancer: The listener port should be created using the TCP protocol for both the Load Balancer Protocol and the Instance Protocol. The application layer protocol (HTTPS) is not handled until we reach the nginx instance. In most cases, the public port should be the standard 443.

Create proxy protocol policy

aws elb create-load-balancer-policy \
  --load-balancer-name acme-balancer \
  --policy-name EnableProxyProtocol \
  --policy-type-name ProxyProtocolPolicyType \
  --policy-attributes AttributeName=ProxyProtocol,AttributeValue=True

Add policy to elb

aws elb set-load-balancer-policies-for-backend-server \
  --load-balancer-name acme-balancer \
  --instance-port 443 \
  --policy-names EnableProxyProtocol
aws elb set-load-balancer-policies-for-backend-server \
  --load-balancer-name acme-balancer \
  --instance-port 80 \
  --policy-names EnableProxyProtocol

Describe ELB

upstream django {
  server app:8000;
}
server {
  listen 80 proxy_protocol;
    # sets the proper client ip
    real_ip_header proxy_protocol;
    # aws vpc subnet ip range
    set_real_ip_from ;
  server_name xyz.com;
  return 301 https://$server_name$request_uri;
   }
server {
  listen 443 ssl proxy_protocol;
  ssl    on;
  ssl_certificate /etc/cert/xyz_com.crt;
  ssl_certificate_key /etc/cert/xyz_com.key;
      # sets the proper client ip
    real_ip_header proxy_protocol;
    # aws vpc subnet ip range
    set_real_ip_from ;
  server_namexyz.com;
#  root /var/www/html;
    access_log /var/log/nginx-access.log;
    error_log /var/log/nginx-error.log;
    client_max_body_size 32M;
	gzip on;
	gzip_http_version  1.1;
	gzip_comp_level    2;
	gzip_buffers 16 8k;
	#gzip_min_length    1100;
	gzip_proxied       any;
	gzip_disable "MSIE [1-6].(?!.*SV1)";
	gzip_vary          on;
	gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/rss+xml
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/svg+xml
    image/x-icon
    text/css
    text/plain
    text/x-component;
    location /static {
        alias   /srv/conf/collected/;
}
  location / {
    proxy_pass http://app:8000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Port 443;
    proxy_redirect off;
    proxy_next_upstream error;
    # Add HTTP Strict Transport Security for good measure.
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;";
  }
}

And that’s it. If the real IP settings are working correctly, you should not need to setup a custom log format.

Creating separate server blocks for direct and proxied traffic is more verbose, but has a few benefits. It mitigates the need for conditional blocks later down the road. I also find that it is easier for others to understand.