Go home
Bill Kerr Software Developer
Bill Kerr
Bill Kerr Software Developer
Back to projects

Timecards

Timecards is a productivity tool that allows users to view an aggregated breakdown of employee timecards by week. It was built to eliminate the need to analyze by hand lengthy reports generated by the timekeeping software. Previously, a physical stack of paper, tens of pages long, had to be closely examined for time entry errors and ommissions. Timecards simplifies the process and automatically flags potential mistakes. All of the timecard data for the application is sourced via the HeavyJob API, whose software is used to input the time data.

The API

The API for Timecards is written in Go and uses the Express-inspired GoFiber framework. Data is stored in a PostgreSQL database.

One of the first challenges that had to be addressed was how to provide the timecard data to the client application. The first implementation of the API simply forwarded requests, after appending credentials, to the HeavyJob API. While this worked, it was far too slow. Responses from the HeavyJob API are slow and contain too much data to be effectively handled by the client. Therefore, the decision was made to periodically query the HeavyJob API from the server and store the results in a PostgreSQL database. This way, smaller chunks of data could be served to the client and requests would be much faster. The drawback to this approach, of course, is that some delay between the data becoming available on the HeavyJob API and the data becoming available on the Timecards API was to be expected. This was deemed an acceptable tradeoff as long as the data refresh occurred at least once every five minutes.

The data refresh was implemented using the goCron package, separating data refreshes accross “jobs”, “employees”, “equipment”, and “timecards”. Refresh interval configuration is exposed via a number of environmental variables. See the configuration section for specific environmental variable options.

Core Resources

The API is organized around seven main resources:

Each of these resources is read-only with the exception of Employee. Changes to any of these resources should be made in the HeavyJob application itself—they will then be reflected in the API.

Job

A Job represents a project in HeavyJob. The following is an example of a Job response from the Timecards API:

{
	"id": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"jobNumber": "18203",
	"description": "Example Project Name",
	"createdAt": 1607969066,
	"updatedAt": 1607969066
}
EndpointResponse
GET /api/v1/jobsA list of all Jobs.
GET /api/v1/jobs/:idA single Job with matching id.
Employee

An Employee represents a single employee in the Timecard API. The Employee object contains general information about a person, including their base pay class.

{
	"id": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"name": "John Doe",
	"isForeman": true,
	"payClassCode": "LAB",
	"payClassDescription": "Laborer",
	"payClassId": "LA",
	"createdAt": 1607969066,
	"updatedAt": 1607969066
}
{
	"isForeman": false
}
EndpointResponse
GET /api/v1/employeesA list of all Employees.
GET /api/v1/employees/:idA single Employee with matching id.
PUT /api/v1/employees/:idUpdates a single Employee with matching id. “isForeman” is the only field that can be updated.
Equipment

An Equipment object contains information identifying a single piece of equipment in the Timecards API.

{
	"id": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"code": "E-1422",
	"description": "Volvo 235ECR Excavator",
	"isRental": false,
	"make": "Volvo",
	"model": "235ECR",
	"serialNumber": "54sdfs65464",
	"year": 2011,
	"operatorPayClass": "OG",
	"operatorPayClassDescription": "Operator Group II",
	"equipmentType": "Excavator"
}
EndpointResponse
GET /api/v1/employeesA list of all Employees.
GET /api/v1/employees/:idA single Employee with matching id.
PUT /api/v1/employees/:idUpdates a single Employee with matching id. “isForeman” is the only field that can be updated.
Timecard

Timecards represent the core resource of the Timecards API. They contain labor and equipment data for a single day of work.

{
	"id": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"jobId": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"foremanId": "d26e5cc0-e96c-4652-9071-e524024b72a4",
	"date": "2020-12-05",
	"revision": 1,
	"isApproved": false,
	"isReviewed": false,
	"isAccepted": false,
	"isRejected": false,
	"sentToPayrollRevision": 1,
	"sentToPayrollDateTime": "2020-12-05",
	"lastModifiedDateTime": "2020-12-05",
	"createdAt": 1607969066,
	"updatedAt": 1607969066
}
EndpointResponse
GET /api/v1/timecardsA list of all Timecards.
GET /api/v1/timecards/:idA single Timecard with matching id.
GET /api/v1/timecards/:id/timecard-employeesA list of TimecardEmployees who are associated with the timecard with matching id.
GET /api/v1/timecards/:id/timecard-equipmentA list of TimecardEquipment that are associated with the timecard with matching id.

Authentication

Authentication is handled using JWTs. When users login, they will receive an access token and a refresh token. On every request, the access token must be included in the “Authorization” header as a bearer token. The access token expires after 60 minutes—a new token can be generated with the refresh token. Auth-related endpoints and examples are listed below.

EndpointRequest PayloadResponse
POST /api/v1/auth/registerUsername and password.A user object.
POST /api/v1/auth/loginUsername and password.A user object. Sets refreshToken cookie.
GET /api/v1/auth/refreshrefreshToken cookieUserId, Username, and AccessToken. Sets refreshToken cookie.
{
	"username": "billk",
	"password": "password"
}
{
	"username": "billk",
	"password": "password"
}

Configuration

Each of the following environmental variables is required to be present in a .env file in the root of the server. The server will not start without all required configuration options present.

Environmental VariableDescription
PORTThe port that the server runs on.
HCSS_CLIENT_IDClient ID provided as part of your HCSS API credentials.
HCSS_CLIENT_SECRETClient secret provided as part of your HCSS API credentials.
HCSS_SCOPEClient scope provided as part of your HCSS API credentials.
HCSS_GRANT_TYPEClient grant type provided as part of your HCSS API credentials.
HCSS_IDENTITY_URLThe endpoint for authenticating via the HCSS Identity API.
HCSS_TOKEN_REFESH_INTThe interval at which the Timecards API should refresh its credentials with the HCSS Identity API.
HEAVYJOB_ROOT_URLThe root URL for the HeavyJob API.
ALLOW_ORIGINSAllow all request origins (used for development).
BUSINESS_UNIT_IDThe business unit id used for making HeavyJob API calls. Set to your default per HeavyJob.
MIN_PASSWORD_LENGTHSets the minimum allowed password length when creating a user.
MAX_PASSWORD_LENGTHSets the maximum allowed password length when creating a user.
MIN_USERNAME_LENGTHSets the minimum allowed username length when creating a user.
MAX_USERNAME_LENGTHSets the maximum allowed username length when creating a user.
JWT_SECRETSets the secret string used for JWT creation.
JWT_EXPIRATIONTime, in seconds, before an issued JWT expires.
JWT_REFRESH_EXPIRATIONTime, in seconds, before a JWT refresh token expires.
PG_CONN_STRINGConnection string for a PostgreSQL database.
JOB_REFRESH_INTInterval at which “jobs” data will be refreshed from the HeavyJob API.
EMPLOYEE_REFRESH_INTInterval at which “employees” data will be refreshed from the HeavyJob API.
EQUIPMENT_REFRESH_INTInterval at which “equipment” data will be refreshed from the HeavyJob API.
TIMECARD_REFRESH_INTInterval at which “timecard” data will be refreshed from the HeavyJob API.