Skip to content
Open
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 .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
engine-strict=true
engine-strict=false
81 changes: 43 additions & 38 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
# -------------------------------------------------------------------
# Minimal dockerfile from alpine base
#
# Instructions:
# =============
# 1. Create an empty directory and copy this file into it.
#
# 2. Create image with:
# docker build --tag timeoff:latest .
#
# 3. Run with:
# docker run -d -p 3000:3000 --name alpine_timeoff timeoff
#
# 4. Login to running container (to update config (vi config/app.json):
# docker exec -ti --user root alpine_timeoff /bin/sh
# --------------------------------------------------------------------
FROM alpine:latest as dependencies

RUN apk add --no-cache \
nodejs npm

COPY package.json .
RUN npm install

FROM alpine:latest

LABEL org.label-schema.schema-version="1.0"
LABEL org.label-schema.docker.cmd="docker run -d -p 3000:3000 --name alpine_timeoff"

RUN apk add --no-cache \
nodejs npm \
vim

RUN adduser --system app --home /app
USER app
##
## Multi-stage build using official Node image for compatibility
## Avoids Alpine musl/node-gyp issues with native modules like sqlite3
##

FROM node:22-slim AS builder
WORKDIR /app

# System deps required to build native modules when prebuilds are unavailable
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
make \
g++ \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Ensure node-gyp finds Python 3 if a build-from-source is needed
ENV PYTHON=/usr/bin/python3
ENV npm_config_python=/usr/bin/python3

# Install dependencies first for better layer caching
COPY package.json ./
# If a lockfile exists, use it for reproducible builds
# COPY package-lock.json ./

RUN npm install

# Copy the rest of the app
COPY . .

# Optional: compile CSS if needed (non-fatal if sources are already present)
RUN npm run compile-sass || true

# Prune devDependencies for smaller runtime image
ENV NODE_ENV=production
RUN npm prune --omit=dev


FROM node:22-slim AS runtime
WORKDIR /app
COPY . /app
COPY --from=dependencies node_modules ./node_modules

CMD npm start
# Copy app and pruned node_modules from builder
COPY --from=builder /app /app

EXPOSE 3000
CMD ["npm","start"]
50 changes: 47 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,34 @@ Create company account and use cloud based version.

### Self hosting

Install TimeOff.Management application within your infrastructure:
Install TimeOff.Management within your infrastructure.

(make sure you have Node.js (>=4.0.0) and SQLite installed)
Prerequisites:
- Node.js 18+ (Node 22 supported). Use `nvm` if possible.
- Git and a working C/C++ toolchain are not required for a standard install (sqlite3 is prebuilt).

Recommended install steps:
```bash
git clone https://github.com/timeoff-management/application.git timeoff-management
cd timeoff-management

# If you see "Invalid Version" errors from an old lockfile, remove it
rm -f package-lock.json

npm install

# Build CSS (uses dart-sass)
npm run compile-sass

# Start the app
npm start
```
Open http://localhost:3000/ in your browser.

Notes:
- The project now uses `sqlite3@^5` and `sass` (dart-sass) instead of `node-sass` to avoid native build issues on modern Node.
- If you use a different Node version per machine, consider adding an `.nvmrc` (e.g., `18`).

## Run tests

We have quite a wide test coverage, to make sure that the main user paths work as expected.
Expand Down Expand Up @@ -122,6 +138,35 @@ npm run-script db-update
npm start
```

## Run in background (forever)

Recommended: PM2 process manager
- Install: `npm i -g pm2`
- Start: `pm2 start bin/wwww --name timeoff`
- Persist reboots: `pm2 save && pm2 startup` (run the printed command)
- Manage: `pm2 status`, `pm2 logs timeoff`, `pm2 restart timeoff`, `pm2 stop timeoff`

Alternative: macOS Launchd
- Create a LaunchAgent with `KeepAlive=true` pointing to `node /absolute/path/to/bin/wwww` and load with `launchctl`.

## Docker

This repository includes a Dockerfile based on `node:22-slim` for reliable installs on modern Node.

Prerequisite: Docker daemon must be running (Docker Desktop on macOS). Verify with `docker info`.

Build and run:
```bash
docker build -t timeoff .
docker run -d --name timeoff -p 3000:3000 --restart unless-stopped timeoff
```
Then open http://localhost:3000/.

If you prefer BuildKit/buildx:
```bash
docker buildx build --load -t timeoff .
```

## How to?

There are some customizations available.
Expand Down Expand Up @@ -156,4 +201,3 @@ Follow instructions on [this page](docs/SessionStoreInRedis.md).
## Feedback

Please report any issues or feedback to <a href="https://twitter.com/FreeTimeOffApp">twitter</a> or Email: pavlo at timeoff.management

Loading