A Spring Boot REST API + single-page web UI for managing monthly timesheets and generating filled .docx reports from customizable Word templates.
- User accounts — register, login, update profile (HTTP Basic auth)
- Timesheet entries — add / edit / delete daily work entries (date, activity, start/end time, remarks)
- Monthly preview — JSON snapshot of any month's entries with totals
- DOCX generation — fills a Word template with
{{placeholder}}markers and streams the file - Custom templates — place
.docxtemplates in~/timesheet-templates/; pick one per user - Swagger UI — interactive API docs at
/swagger-ui.html - Built-in SPA — served from
/(no separate front-end server needed)
| Tool | Version |
|---|---|
| Java | 21+ |
| Maven | 3.9+ |
| (Optional) Docker | 24+ |
# Clone
git clone <repo-url>
cd timesheet-api
# Build & run
mvn spring-boot:runThe app starts on http://localhost:8080.
- Web UI → http://localhost:8080
- Swagger UI → http://localhost:8080/swagger-ui.html
# Build image
docker build -t paingan-timesheet .
# Run (mount a host folder for persistent DB + templates)
docker run -p 8080:8080 \
-v "$HOME/timesheet-data/db:/home/timesheet" \
-v "$HOME/timesheet-data/templates:/home/timesheet/timesheet-templates" \
paingan-timesheetAll settings are in src/main/resources/application.properties:
| Property | Default | Description |
|---|---|---|
server.port |
8080 |
HTTP port |
spring.datasource.url |
jdbc:sqlite:~/timesheet.db |
SQLite database path |
timesheet.templates-dir |
~/timesheet-templates |
Folder for custom .docx templates |
| Path | Contents |
|---|---|
~/timesheet.db |
SQLite database (auto-created) |
~/timesheet-templates/ |
DOCX template files (auto-created, seeded with default template) |
All endpoints require HTTP Basic authentication unless noted as public.
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/auth/register |
Public | Register a new account |
GET |
/api/auth/me |
Required | Get current user profile |
PUT |
/api/auth/me |
Required | Update profile |
Register request body:
{
"username": "john",
"password": "secret123",
"fullName": "John Doe",
"company": "PLAI",
"department": "IT",
"position": "Developer",
"email": "john@example.com",
"vendorName": "VendorCo",
"supervisor": "Jane SM",
"headDivision": "Head IT",
"templateName": "my-template.docx"
}| Method | Path | Description |
|---|---|---|
POST |
/api/timesheet/entries |
Add an entry |
PUT |
/api/timesheet/entries/{id} |
Update an entry |
DELETE |
/api/timesheet/entries/{id} |
Delete an entry |
Entry request body:
{
"workDate": "2026-02-20",
"activity": "Sprint planning",
"startTime": "09:00",
"endTime": "17:00",
"remarks": "JIRA-123"
}| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/api/timesheet/preview?month=2&year=2026 |
Required | JSON preview |
GET |
/api/timesheet/generate/docx?month=2&year=2026 |
Required | Download filled .docx |
GET |
/api/timesheet/generate/template |
Required | Download blank template |
GET |
/api/timesheet/templates |
Public | List available templates |
Templates use {{placeholder}} markers that get replaced at generation time.
| Placeholder | Value |
|---|---|
{{fullName}} |
Employee full name |
{{company}} |
Company name |
{{department}} |
Department |
{{position}} |
Job title |
{{email}} |
Email address |
{{vendorName}} |
Vendor / contractor company |
{{supervisor}} |
Supervisor name |
{{headDivision}} |
Head of division |
{{period}} |
Month Year (e.g. February 2026) |
{{date}} |
Entry date (dd/MM/yyyy) — table row |
{{activity}} |
Activity description — table row |
{{startTime}} |
Start time (HH:mm) — table row |
{{endTime}} |
End time (HH:mm) — table row |
{{remarks}} |
Remarks — table row |
{{totalWorkingDays}} |
Total distinct working days |
{{totalHours}} |
Total hours (e.g. 40.0 hrs) |
{{submittedBy}} |
Same as {{fullName}} |
- Download the default template:
GET /api/timesheet/generate/template - Open in Microsoft Word, design your layout, keep the
{{placeholder}}markers - Save the file (
.docx) to~/timesheet-templates/ - In Edit Profile, select your template from the dropdown
- Generate — your template will be used
The entry table must contain a row with {{date}} and {{activity}}; the service clones data rows from it.
mvn testTests use an in-memory SQLite database (profile test).
Key test classes:
| Class | Coverage |
|---|---|
AuthServiceTest |
register, getProfile, updateProfile — success + error paths |
TimesheetServiceTest |
addEntry, updateEntry, deleteEntry, getMonthlyTimesheet totals |
TimesheetApplicationTests |
Spring context loads |
timesheet-api/
├── Dockerfile
├── pom.xml
└── src/
├── main/
│ ├── java/com/timesheet/
│ │ ├── config/ # SecurityConfig
│ │ ├── controller/ # AuthController, TimesheetController
│ │ ├── dto/ # Request / Response DTOs
│ │ ├── entity/ # Employer, TimesheetEntry
│ │ ├── exception/ # GlobalExceptionHandler
│ │ ├── repository/ # JPA repositories
│ │ └── service/ # AuthService, TimesheetService, TimesheetDocxService
│ └── resources/
│ ├── application.properties
│ ├── static/ # index.html, app.js, app.css (SPA)
│ └── templates/ # timesheet-template.docx (classpath fallback)
└── test/
├── java/com/timesheet/
│ └── service/ # AuthServiceTest, TimesheetServiceTest
└── resources/
└── application-test.properties
| Layer | Technology |
|---|---|
| Runtime | Java 21, Spring Boot 3.2.5 |
| Persistence | SQLite + Spring Data JPA (Hibernate) |
| Security | Spring Security (HTTP Basic) |
| Document | Apache POI poi-ooxml 5.2.5 |
| API Docs | SpringDoc OpenAPI / Swagger UI |
| Build | Maven 3.9 |
| Container | Docker (multi-stage, Eclipse Temurin 21 JRE Alpine) |