A minimal time tracking REST API.
This project serves as a hands-on environment for exploring FoundationDB features through a realistic application written in Clojure. It aims to implement timeslip tracking (work time entries) with multi-tenant isolation, composite indexes, and query filtering.
- FoundationDB - Install the server and client libraries
- Clojure CLI
- Gradle - For Protocol Buffer compilation
- Optional: Docker for containerized deployment
Before starting the service or REPL, compile the protobuf definitions:
make proto-compileThis generates Java classes from resources/proto/timeslip.proto into build/classes/java/main/.
make run
# or
clojure -M:run/serviceThe service starts on port 8080. Verify it's running:
curl http://localhost:8080/system-admin/statusOpen the Swagger UI in your browser:
http://localhost:8080
Start a REPL with development tools (Portal data inspector, Integrant REPL, hot-reload):
make replOnce in the REPL:
;; Start the system
(start)
;; Restart (reload changed namespaces and restart)
(restart)
;; Stop the system
(stop)
;; View system configuration
(system)List all available tasks:
makeKey development commands:
make test # Run tests with kaocha
make test-watch # Run tests on file save
make format-check # Check code formatting with cljstyle
make format-fix # Fix code formattingClink provides a REST API for timeslip CRUD operations and timer functionality. All endpoints require an X-Organization-ID header for multi-tenant isolation.
Main Features:
- Create, read, update, delete timeslips
- Start/stop timers for live time tracking
- Query timeslips with filters (person, project, task, date range, billable status)
- OpenAPI/Swagger documentation
Example Request:
curl -X POST http://localhost:8080/api/v1/timeslips \
-H "Content-Type: application/json" \
-H "X-Organization-ID: my-org" \
-d '{
"person-id": "person-123",
"project-id": "project-456",
"task-id": "task-789",
"start-time": 1704067200000,
"end-time": 1704070800000,
"billable": true
}'For full API documentation, see the Swagger UI at http://localhost:8080.
├── src/bru/clink/ # Source code
│ ├── service.clj # Entry point
│ ├── system.clj # Integrant component lifecycle
│ ├── router.clj # HTTP routing (Reitit)
│ ├── api/ # HTTP handlers
│ └── fdb/ # FoundationDB integration
├── resources/
│ ├── config.edn # System configuration
│ └── proto/ # Protocol Buffer schemas
├── test/ # Test files
└── dev/user.clj # REPL development tools
- Multi-tenancy: Organization-based subspace isolation
- Record Layer: Type-safe record storage with protobuf schemas
- Indexes: Composite indexes on
(person_id, start_time)and(project_id, start_time) - Queries: Dynamic query builder with filtering and range scans
- Transactions: ACID transactions with retry logic
Build an uberjar:
make build-uberjarOr build and run with Docker:
make docker-buildCopyright © 2025 Bru