# README
Time Tracking API

Go API for tracking time.
Manage time entries for tasks that are associated with projects. Built with Golang and PostgreSQL.
See the React Time Tracking App for a reference UI.
Setup
You can use Docker to get started quickly or run the Go server locally using a PostgreSQL instance.
Option #1: Docker
To run the Go server and PostgreSQL database in a container you can start both using Docker Compose:
docker-compose up
The API will be available at http://localhost:8000 and the PostgreSQL instance will be exposed on port 5432.
Option #2: Local
Database
Ensure you have PostgreSQL 12 or higher installed and running.
Create a timetracker
database and role using the bootstrap SQL in:
./database/bootstrap.sql
Then create the schema in the timetracker
database using:
./database/schema-1.sql
Run Server
To run the Go API server use the run
Makefile target:
make run
which will start the server on the port configured in config/dev.yml
. By default the API will be available at http://localhost:8000
Testing
Unit Tests
Unit tests can be run using:
make unit_test
Integration Tests
Integration tests are managed under the integration_test
root folder and can be run using:
make int_test
Postman Tests
Additional functional tests are available using the Postman tool. These tests require the newman Postman command-line runner. Install using:
npm install -g newman
The test rely on the database/bootstrap.sql
data to be present. To run the Postman tests locally, first start the web server:
make run
then run the Postman tests:
make postman
API
Authentication Token
Most of the REST endpoints require an authentication token which can be supplied as a custom header:
Authorization: Bearer {token}
Endpoints that do not require a token are noted below.
To validate the local or Docker instance is working you can hit the /_ping
endpoint and you should get back an OK
response:
curl http://localhost:8000/_ping
Authentication
Method | Path | Request | Response | Notes |
---|---|---|---|---|
POST | /api/auth/login | LoginRequest | AuthResponse | Does not require an authentication token |
POST | /api/auth/token | AuthResponse | ||
POST | /api/auth/logout | {} | ||
POST | /api/auth/forgot | EmailRequest | {} | Does not require an authentication token. Sends a forgot password validation email. |
Profile
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/profile/ | ProfileResponse | ||
PUT | /api/profile/ | ProfileRequest | ProfileResponse | |
PUT | /api/profile/password | PasswordChangeRequest | {} |
Account
Method | Path | Request | Response | Notes |
---|---|---|---|---|
POST | /api/account | AccountRequest | ProfileResponse | Does not require an authentication token |
PUT | /api/account | AccountUpdateRequest | ProfileResponse | |
GET | /api/account | AccountResponse | ||
GET | /api/account/users | []ProfileResponse | ||
POST | /api/account/user | AddUserRequest | ProfileResponse |
Client
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/client/{client_id} | string | ClientResponse | |
GET | /api/client/all | []ClientResponse | ||
GET | /api/client/archived | []ClientResponse | ||
POST | /api/client/ | ClientRequest | ClientResponse | |
PUT | /api/client/ | ClientRequest | {} | |
DELETE | /api/client/ | ClientRequest | {} | |
PUT | /api/client/archive | ClientRequest | {} | |
PUT | /api/client/restore | ClientRequest | {} |
Project
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/project/{project_id} | string | ProjectResponse | |
GET | /api/project/all | []ProjectResponse | ||
GET | /api/project/archived | []ProjectResponse | ||
POST | /api/project/ | ProjectContainerRequest | ProjectResponse | |
PUT | /api/project/ | ProjectContainerRequest | {} | |
DELETE | /api/project/ | ProjectIdRequest | {} | |
PUT | /api/project/archive | ProjectIdRequest | {} | |
PUT | /api/project/restore | ProjectIdRequest | {} | |
POST | /api/project/copy/last/week | StartAndEndDateRequest | {} or TimeRangeResponse | Empty if no records the prior week |
Time
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/time/week | TimeRangeResponse | ||
GET | /api/time/week/{startDate} | string | TimeRangeResponse | Date must be in the ISOShortDateFormat (e.g. "2006-01-02") |
PUT | /api/time/ | TimeEntryRangeRequest | {} | |
POST | /api/time/project/week | ProjectWeekRequest | {} | |
DELETE | /api/time/project/week | ProjectDeleteRequest | {} |
Task
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/task/{taskId} | string | TaskResponse | |
GET | /api/task/all | []TaskResponse | ||
GET | /api/task/archived | []TaskResponse | ||
POST | /api/task/ | TaskRequest | TaskResponse | |
PUT | /api/task/ | TaskRequest | {} | |
PUT | /api/task/archive | TaskRequest | {} | |
PUT | /api/task/restore | TaskRequest | {} | |
DELETE | /api/task/ | TaskRequest | {} |
Report
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /api/report/time/client | query parameters: from , to , page | []ClientReportResponse | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/project | query parameters: from , to , page | []ProjectReportResponse | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/task | query parameters: from , to , page | []TaskReportResponse | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/person | query parameters: from , to , page | []PersonReportResponse | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/export/client | query parameters: from , to | CSV file with content type text/csv | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/export/project | query parameters: from , to | CSV file with content type text/csv | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/export/task | query parameters: from , to | CSV file with content type text/csv | from and to are date strings in the ISOShortDateFormat format |
GET | /api/report/time/export/person | query parameters: from , to | CSV file with content type text/csv | from and to are date strings in the ISOShortDateFormat format |
Ping
Method | Path | Request | Response | Notes |
---|---|---|---|---|
GET | /_ping | Text ok with content type text/plain |
Errors
If an API fails, the HTTP status code will reflect the type of error response. Common error status codes are:
Status Code | Error |
---|---|
400 | http.StatusBadRequest |
401 | http.StatusUnauthorized |
404 | http.StatusNotFound |
405 | http.StatusMethodNotAllowed |
500 | http.StatusInternalServerError |
Errors will produce a JSON response that contains a status
field set to error
.
Error details will be included as part of the serialized Error struct.
For example the error response below shows the JSON response for a 400 error when an email
value is invalid:
{
"status": "error",
"error": "invalid input",
"message": "Invalid email",
"code": "InvalidEmail",
"detail": {"field": "email" }
}