Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.dev.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ DEV_BIND_ADDRESS=127.0.0.1
API_PORT=3001

# Server timezone — core-time-window and off-hours logic depends on this.
TZ=Europe/Berlin
TZ=UTC

# JWT signing secret for user sessions. Rotate per deployment!
JWT_SECRET=change-me-jwt-secret
Expand Down
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ API_PORT=3000

# Server wall-clock timezone. Core-time-window detection and the
# 07:00/23:00 off-hours approval threshold reason in local time, so the
# API process must run in the deployment's timezone. Default: Europe/Berlin.
TZ=Europe/Berlin
# API process must run in the deployment's IANA timezone. Default: UTC.
# Choose the organisation's working timezone before recording real data.
TZ=UTC

# Allowed CORS origins for the API (comma-separated). The Vite dev server
# runs on 4200; the full Docker stack exposes the web container on 8080.
Expand Down
2 changes: 1 addition & 1 deletion .env.ipad.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ SUPPORT_URL=https://github.com/sponsors/patrickschiller
POSTGRES_USER=openclockwork
POSTGRES_PASSWORD=openclockwork
POSTGRES_DB=openclockwork
TZ=Europe/Berlin
TZ=UTC
JWT_SECRET=change-me-jwt-secret
TERMINAL_QR_SECRET=change-me-independent-terminal-qr-secret
TERMINAL_CHALLENGE_TTL_SECONDS=45
Expand Down
5 changes: 3 additions & 2 deletions .env.prod.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Pin deployments to an immutable OpenClockwork release. Do not use `latest`
# for production upgrades.
OPENCLOCKWORK_VERSION=1.3.0
OPENCLOCKWORK_VERSION=1.4.0
# Keep these names unchanged across upgrades.
OPENCLOCKWORK_DB_VOLUME=openclockwork-db-data-prod
OPENCLOCKWORK_ATTACHMENTS_VOLUME=openclockwork-attachments-prod
Expand All @@ -13,7 +13,8 @@ POSTGRES_PASSWORD=change-me-database-password
POSTGRES_DB=openclockwork
DATABASE_URL=postgresql://openclockwork:change-me-database-password@db:5432/openclockwork?schema=public

TZ=Europe/Berlin
# IANA working timezone for this installation; configure before recording data.
TZ=UTC
JWT_SECRET=change-me-long-random-jwt-secret
TERMINAL_QR_SECRET=change-me-independent-terminal-qr-secret
TERMINAL_CHALLENGE_TTL_SECONDS=45
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
DATABASE_URL: postgresql://openclockwork:openclockwork@localhost:5433/openclockwork_test?schema=public
JWT_SECRET: ci-jwt-secret-do-not-use-in-prod
ERP_API_KEY: ci-erp-key
# Match production — core-time + off-hours logic is timezone-sensitive.
# Pin the legacy fixtures to an explicit zone, independent of deployment defaults.
TZ: Europe/Berlin

steps:
Expand Down
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ If you forgot to sign off, fix the latest commit with `git commit --amend -s` or
## Reporting issues

- **Bugs:** open a GitHub issue with reproduction steps, expected vs. actual behaviour, environment details (OS, Node version, browser).
- **Security vulnerabilities:** do *not* open a public issue. See [SECURITY.md](SECURITY.md).
- **Security vulnerabilities:** do _not_ open a public issue. See [SECURITY.md](SECURITY.md).
- **Feature ideas:** open a GitHub Discussion or a "proposal" issue first. We prefer to discuss design before code.

## Working on a change

1. Fork the repo and create a feature branch from `main`.
2. Review the [README](README.md), [feature overview](FEATURES.md), and existing code before changing domain rules — OpenClockwork models a real working-time-tracking system, and the rules around break deduction, approval thresholds, etc. are not invented.
2. Review the [README](README.md), [feature overview](FEATURES.md), [roadmap](ROADMAP.md), and existing domain tests before changing working-time rules. Country-specific policies must be explicit configuration or optional presets, with existing installations preserved by migrations.
3. Keep new dependencies aligned with the existing TypeScript, Nx, NestJS, React, Prisma, and Tailwind stack unless the pull request clearly explains the reason for a change.
4. Run `pnpm install` at the repo root, then use `pnpm nx run <project>:<target>` (e.g. `pnpm nx serve api`) for local dev.
5. Add tests. New endpoints, business rules, or UI flows without tests will not be merged.
Expand All @@ -34,8 +34,8 @@ If you forgot to sign off, fix the latest commit with `git commit --amend -s` or

## Pull request expectations

- One logical change per PR. If your branch fixes a bug *and* refactors something, split it.
- The PR description should explain *why*, not just *what*. Link to the issue or discussion.
- One logical change per PR. If your branch fixes a bug _and_ refactors something, split it.
- The PR description should explain _why_, not just _what_. Link to the issue or discussion.
- All checks (lint, type-check, tests, DCO) must be green before review.
- A reviewer will respond within a few days. Larger changes may take longer; please be patient.
- We reserve the right to decline contributions that do not align with the project goals stated in the README.
Expand All @@ -47,6 +47,7 @@ If you forgot to sign off, fix the latest commit with `git commit --amend -s` or
- Frontend: Tailwind for styling. Component-local state via React; cross-cutting state via the patterns established in `apps/web`.
- Database: schema changes go through Prisma migrations. Never edit a migration after it has been merged to `main`.
- All public APIs are documented through their OpenAPI spec (NestJS Swagger). UI uses the generated client.
- Keep user-facing text in the English/German translation catalogue. Do not infer holiday calendars, working-time rules, currencies, or tax settings from the UI language.

## Code of Conduct

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.api
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ RUN mkdir -p /app/data/attachments && chown -R app:app /app/data
USER app
EXPOSE 3000

# Default timezone — German Zeiterfassung. Overridable per deployment
# Neutral default timezone. Configure the organisation's working timezone
# (docker-compose / Container App env). Drives core-time-window and
# 07:00/23:00 off-hours reasoning, which is all wall-clock.
ENV NODE_ENV=production \
API_PORT=3000 \
TZ=Europe/Berlin
TZ=UTC

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget -qO- http://127.0.0.1:3000/api/health || exit 1
Expand Down
31 changes: 23 additions & 8 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

OpenClockwork is a responsive, self-hostable time-and-attendance system for
employees, managers, HR administrators, and paired tablet terminals. Its domain
model focuses on real German working-time workflows while keeping deployment,
model supports configurable working-time workflows across countries while keeping deployment,
data, and integrations under the operator's control.

> **Project status:** Stable. Published versions follow semantic versioning and
> include release notes, forward-only database migrations, and documented
> upgrade steps. The capabilities below are implemented and covered by
> automated tests.

For planned Solo mode, invoice creation, and CAUR-based agent billing, see the
[project roadmap](ROADMAP.md).

<p align="center">
<img src="assets/screenshots/tablet/kiosk.png" alt="Paired OpenClockwork tablet kiosk with a rotating QR code" width="100%">
</p>
Expand Down Expand Up @@ -71,7 +74,7 @@ device never acts as an employee and cannot call normal HR or time-entry APIs.
| Kiosk PWA | Dedicated manifest and full-screen view with time, date, location, custom branding, connection state, and automatic challenge refresh |
| Employee scanner | Explicit clock-in or clock-out choice, camera preview, local QR decoding, and GPS only when the terminal requires it |
| Device operations | Last-seen monitoring, re-pairing, immediate device revocation, terminal deactivation, and permanent deletion |
| Time-zone handling | IANA drop-down with `Europe/Berlin` as the default and server-side validation |
| Time-zone handling | IANA selection with the browser timezone suggested, UTC fallback, and server-side validation |
| Durable audit trail | Historical bookings retain terminal/GPS evidence snapshots even when kiosk-only records are removed |

The local iPad pilot includes a trusted-HTTPS Compose overlay, generated test
Expand All @@ -93,7 +96,7 @@ See [the German iPad setup guide](docs/IPAD_TERMINAL_SETUP.de.md).
| Retroactive booking changes | Change project/service-order/activity on completed and approved entries |
| Entry splitting | Split a closed entry at a chosen time when work changes between projects |
| Retroactive range booking | Assign a past interval to a project; coverage is validated and existing entries are split as required |
| Automatic break accounting | Statutory deduction after six and nine hours |
| Automatic break accounting | Configurable schedule thresholds and deductions; no automatic deduction for new schedules by default |
| Time accounts | Calculated target hours, actual hours, overtime, and opening balances |
| Annual calendar | Year view for vacation, home office, special leave, sickness, training, and flextime |
| Requests | Vacation, home-office, special-leave, and time-adjustment workflows |
Expand Down Expand Up @@ -138,7 +141,7 @@ Employee submits
| Work schedules | Working-day masks, permitted frames, and multiple named core-time windows |
| Schedule assignment | Assign individual schedules or bulk-assign by time model |
| Leave allowances | Base leave, carry-over, adjustments, expiry dates, and adjustment reasons |
| German public holidays | State-specific holiday calendars used in target hours and vacation calculations |
| Holiday calendars | Optional regional presets and custom dates used in target hours and vacation calculations |
| Absence administration | Record and review sickness, training, and flextime entries |
| Approval operations | Manager/HR inboxes, bulk actions, correction loops, and workflow history |
| Terminal administration | Configure, activate, pair, monitor, revoke, re-pair, deactivate, or permanently delete tablet kiosks |
Expand Down Expand Up @@ -175,28 +178,39 @@ clocking locations are excluded by default and require an explicit HR action;
operators must document a lawful purpose and suitable retention period before
using them.

## Compliance-oriented domain logic
## Configurable working-time rules

Working-time rules are visible in code and covered by focused tests. Operators
remain responsible for validating their organisation's exact policies.

- Statutory break calculation
- Configurable break calculation with explicit thresholds and deduction minutes
- Target/actual accounting derived from weekly hours and working-day masks
- Opening overtime balances and employee start dates
- Configurable working frames and multiple core-time windows
- Direct daily-target validation against holidays, absences, requests, existing
entries, permitted frames, and automatic breaks
- Detailed core-time violation detection
- Special approval handling for out-of-frame entries
- Working-day and German state-holiday aware vacation calculation
- Working-day and selected-holiday aware vacation calculation
- Half-day leave and carry-over expiry processing
- Multi-stage request workflows and workflow events

New employees start with no regional holiday preset and no assumed annual leave
entitlement. German state calendars remain optional presets; custom dates
support other national, regional, or company calendars. New schedules start
without automatic break deduction. Upgrade migrations preserve existing
employee calendars and break policies.

Working-day and schedule calculations use the deployment's configured `TZ`
(UTC by default). Per-employee working timezones and more built-in regional
calendars are planned; see [ROADMAP.md](ROADMAP.md). Operators must validate
local rules and calendar coverage for each period in use.

## Languages, accessibility, and responsive design

- German and English UI across login, employee, manager, HR, and kiosk routes
- Central translation catalogue for labels, validation, states, and empty views
- Locale-aware dates and timestamps
- Browser-language detection with English fallback and regional date formatting
- Persistent language and theme preferences
- Keyboard-operable account and mobile overflow menus
- Semantic labels for navigation, forms, buttons, progress indicators, and QR
Expand Down Expand Up @@ -266,6 +280,7 @@ installation identity is sent back to OpenClockwork.
## Explore the project

- [Main README and installation guide](README.md)
- [Roadmap: Solo mode, invoices, and CAUR-based agent billing](ROADMAP.md)
- [Set up and test an iPad terminal](docs/IPAD_TERMINAL_SETUP.de.md)
- [Upgrade an existing installation](UPGRADING.md)
- [Review published releases](https://github.com/patrickschiller/openclockwork/releases)
Expand Down
53 changes: 38 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</p>

<p align="center">
<strong>Open-source time and attendance for teams that want trustworthy rules, modern self-hosting, and no proprietary punch-clock hardware.</strong>
<strong>Open-source time and attendance with configurable work rules, modern self-hosting, and no proprietary punch-clock hardware.</strong>
</p>

<p align="center">
Expand All @@ -15,15 +15,20 @@
</p>

OpenClockwork is a mobile-first, self-hostable working-time system for small and
mid-sized organisations. Employees can clock in and out, scan a rotating QR
code from a wall-mounted tablet, or—when HR explicitly enables it—book their
contractual daily target as one completed block.
mid-sized organisations in any country. Employees can clock in and out, scan a
rotating QR code from a wall-mounted tablet, or—when HR explicitly enables
it—book their contractual daily target as one completed block.

The domain model covers real working-time behaviour: statutory break deduction,
target/actual accounts, configurable schedules and core hours, German public
holidays, leave balances, multi-stage approvals, projects, service orders, and
auditable reporting. The UI ships in German and English and works as an
installable PWA on phones, tablets, and desktops.
The domain model covers real working-time behaviour: configurable break deduction,
target/actual accounts, schedules and core hours, selectable holiday calendars
and custom holiday dates, leave balances, multi-stage approvals, projects,
service orders, and auditable reporting. The UI ships in German and English and
works as an installable PWA on phones, tablets, and desktops.

> **Where OpenClockwork is heading:** Read the [project roadmap](ROADMAP.md) for
> the complete **Solo mode**, **invoice creation**, and **CAUR-based agent usage
> accounting and billing** plans. These are planned capabilities; the current
> application provides team time tracking and attendance.

<p align="center">
<img src="assets/screenshots/tablet/kiosk.png" alt="OpenClockwork tablet terminal with a rotating QR code" width="100%">
Expand All @@ -50,7 +55,7 @@ installable PWA on phones, tablets, and desktops.
- **Optional geofencing.** A terminal can work entirely without GPS or require a
fresh employee position inside a server-validated radius with a configured
accuracy limit.
- **Compliance-oriented domain logic.** Break deduction, working frames, core
- **Configurable working-time rules.** Break deduction, working frames, core
hours, target/actual balances, public holidays, and leave calculations live in
tested backend/shared-domain code.
- **Real approval workflows.** Vacation, home office, special leave, time
Expand All @@ -61,10 +66,26 @@ installable PWA on phones, tablets, and desktops.
export customer or working-time reports with optional clock-in/out locations.
- **Self-hosted and API-first.** PostgreSQL, NestJS, React, OpenAPI, Socket.IO,
Docker, and an Azure reference deployment—without SaaS lock-in.
- **German and English.** Centralised translations, locale-aware dates, and a
persistent language switcher across the login, employee, manager, HR, and
- **Localised interface.** German and English translations, browser-aware dates,
and a persistent language switcher across the login, employee, manager, HR, and
kiosk experiences.

## Use in any country

Language does not select a country's work rules. Configure the installation's
IANA working timezone, employee holiday calendars, leave allowances, working
days, and schedule break rules for your organisation. New employee records
start without a regional holiday preset or assumed annual leave entitlement;
new schedules start without automatic break deduction. Existing German state
calendars remain available as optional presets, and custom holiday dates can
represent other countries, regions, and company closures.

The API currently evaluates working days and schedule boundaries in one
deployment timezone (`TZ`, default `UTC`). Set this explicitly before recording
real data. A kiosk's display timezone does not change payroll or working-day
boundaries. Multiple simultaneous employee working timezones and additional
maintained regional calendars are covered in the [roadmap](ROADMAP.md).

## Tablet terminal

An HR administrator creates a terminal with an internal name, visible location,
Expand Down Expand Up @@ -162,8 +183,9 @@ pnpm nx run-many -t serve -p api,web
```

Open `http://localhost:4200`. Vite proxies API calls to
`http://localhost:3000`. The interface starts in German; use the language menu
on the login screen or in the application header to switch to English.
`http://localhost:3000`. The interface uses a supported browser language, falling
back to English. Use the language menu on the login screen or in the application
header to choose English or German; your choice is saved.

### Full local Docker stack

Expand Down Expand Up @@ -344,7 +366,7 @@ docker compose -f docker-compose.prod.yml --env-file .env.prod \
```

Enter the administrator's personnel number, name, email address, time model,
weekly hours, annual leave, start date, and German state. Defaults are shown in
weekly hours, annual leave, start date, and optional holiday calendar. Defaults are shown in
square brackets and can be accepted with Enter.

The command creates exactly one active `HRAdmin` and prints a random initial
Expand Down Expand Up @@ -417,6 +439,7 @@ You can also support the project through
## Documentation

- [Complete feature overview](FEATURES.md)
- [Roadmap: Solo mode, invoices, and CAUR-based agent billing](ROADMAP.md)
- [iPad terminal setup and operations (German)](docs/IPAD_TERMINAL_SETUP.de.md)
- [Upgrade procedure](UPGRADING.md)
- [Release process](RELEASING.md)
Expand Down
Loading