The Timesheet-Wizard is a personal pet project to fetch timesheets from Clockify, transform them to various formats and export them again into other tools.
As of now, the only target formats that are supported are XLSX, PDF and CSV, resulting in the following main features of Timesheet-Wizard:
- Fetch timesheets from Clockify
- Generate & store XLSX files from these timesheets
- Generate & store PDF files from these timesheets
- Generate & store CSV files from these timesheets
As a freelance Software-Engineer & -Architect doing mostly time & material contracting, tracking my working hours is quite essential. To ease this, I'm using Clockify. It's an awesome tool with a nice UI that allows me to track and also categorize my working hours. Besides supporting some Excel-reports out of the box, it also provides an API to export reports in json-format as well.
In order to have the freedom to customize the reports as much as I like and to transfer these reports automatically to other tools, I decided to create my own little application allowing me to do that: the Timesheet-Wizard.
In addition to the business motivation mentioned above, this is also a perfect opportunity to play around with technology in the function-as-a-service territory. That's the reason, why the Timesheet Wizard is bundled and deployed to multiple hyperscalers - at the moment it's only AWS Lambda & Azure Functions.
A more verbose documentation of the architecture following arc42 can be found in the doc-folder.
- a Spring Boot application
- written in Kotlin
- built with Gradle
- deployed continuously to the cloud using GitHub Actions
- running as AWS Lambda function and also as Azure Function
- following the infrastructure-as-code-approach with provisioning via AWS Cloudformation and Azure Bicep
- triggered by AWS EventBridge and Azure Function triggers
- tw-cloud-spi: the service provider interface to be implemented for any cloud specific things. Like e.g. uploading timesheets to some cloud storage.
- tw-core: the code module that contains the business logic. This subproject is cloud-agnostic.
- tw-app-aws: implements the interfaces defined in
tw-cloud-spi
with AWS specific code and also bundles the cloud-agnostictw-core
with AWS specific things to an AWS Lambda function. - tw-app-azure: implements the interfaces defined in
tw-cloud-spi
with Azure specific code and also bundles the cloud-agnostictw-core
with Azure specific things to an Azure Function.
The tw-core
Gradle subproject consists of two independent modules (realized as Kotlin packages) with the following
responsibilities:
import
- importing timesheets from Clockify
- transforming them into the domain model
export
- generating XLSX, PDF & CSV files from the domain model
- storing the XLSX, PDF & CSV files on AWS S3 or Azure Blob Storage
- Java 21+
- Gradle
- Docker (for tests using testcontainers)
- AWS SAM CLI - for building & invoking as AWS Lambda on local machine
- Azure Core Tools - for building & invoking as Azure Function App on local machine
- Build with
gradle build
- Emulate S3 storage with Minio in docker-compose.yml
- Create & upload a
configuration.json
file to local S3- An example file is shown here
- Replace placeholders in tw-app-aws/requests/public/env.json with your keys
- Set import params in tw-app-aws/requests/public/event.json
- Build the AWS Lambda function locally: tw-app-aws/requests/public/build.sh
- Invoke the AWS Lambda function locally: tw-app-aws/requests/public/invoke-local.sh
- Emulate Azure Blob Storage with Azureite in docker-compose.yml
- Create & upload a
configuration.json
file to local Azure Storage totw-sheets/config
- E.g. via Azure Storage Explorer
- An example file is shown here
- Replace placeholders in tw-app-azure/requests/public/run-function-local.sh with your keys
- Build & run the Azure Function locally: tw-app-azure/requests/public/run-function-local.sh
- Invoke the Azure Function locally: tw-app-azure/requests/public/invoke-function.http