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
}
Endpoint | Response |
---|---|
GET /api/v1/jobs | A list of all Jobs. |
GET /api/v1/jobs/:id | A 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
}
Endpoint | Response |
---|---|
GET /api/v1/employees | A list of all Employees. |
GET /api/v1/employees/:id | A single Employee with matching id. |
PUT /api/v1/employees/:id | Updates 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"
}
Endpoint | Response |
---|---|
GET /api/v1/employees | A list of all Employees. |
GET /api/v1/employees/:id | A single Employee with matching id. |
PUT /api/v1/employees/:id | Updates 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
}
Endpoint | Response |
---|---|
GET /api/v1/timecards | A list of all Timecards. |
GET /api/v1/timecards/:id | A single Timecard with matching id. |
GET /api/v1/timecards/:id/timecard-employees | A list of TimecardEmployees who are associated with the timecard with matching id. |
GET /api/v1/timecards/:id/timecard-equipment | A 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.
Endpoint | Request Payload | Response |
---|---|---|
POST /api/v1/auth/register | Username and password. | A user object. |
POST /api/v1/auth/login | Username and password. | A user object. Sets refreshToken cookie. |
GET /api/v1/auth/refresh | refreshToken cookie | UserId, 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 Variable | Description |
---|---|
PORT | The port that the server runs on. |
HCSS_CLIENT_ID | Client ID provided as part of your HCSS API credentials. |
HCSS_CLIENT_SECRET | Client secret provided as part of your HCSS API credentials. |
HCSS_SCOPE | Client scope provided as part of your HCSS API credentials. |
HCSS_GRANT_TYPE | Client grant type provided as part of your HCSS API credentials. |
HCSS_IDENTITY_URL | The endpoint for authenticating via the HCSS Identity API. |
HCSS_TOKEN_REFESH_INT | The interval at which the Timecards API should refresh its credentials with the HCSS Identity API. |
HEAVYJOB_ROOT_URL | The root URL for the HeavyJob API. |
ALLOW_ORIGINS | Allow all request origins (used for development). |
BUSINESS_UNIT_ID | The business unit id used for making HeavyJob API calls. Set to your default per HeavyJob. |
MIN_PASSWORD_LENGTH | Sets the minimum allowed password length when creating a user. |
MAX_PASSWORD_LENGTH | Sets the maximum allowed password length when creating a user. |
MIN_USERNAME_LENGTH | Sets the minimum allowed username length when creating a user. |
MAX_USERNAME_LENGTH | Sets the maximum allowed username length when creating a user. |
JWT_SECRET | Sets the secret string used for JWT creation. |
JWT_EXPIRATION | Time, in seconds, before an issued JWT expires. |
JWT_REFRESH_EXPIRATION | Time, in seconds, before a JWT refresh token expires. |
PG_CONN_STRING | Connection string for a PostgreSQL database. |
JOB_REFRESH_INT | Interval at which “jobs” data will be refreshed from the HeavyJob API. |
EMPLOYEE_REFRESH_INT | Interval at which “employees” data will be refreshed from the HeavyJob API. |
EQUIPMENT_REFRESH_INT | Interval at which “equipment” data will be refreshed from the HeavyJob API. |
TIMECARD_REFRESH_INT | Interval at which “timecard” data will be refreshed from the HeavyJob API. |