All apps · 0 apps
Coworkee
Docker app from Coworkee's Repository
Overview
Readme
View on GitHubCoworkee
Read this in Deutsch 🇩🇪.
Modern, self-hosted HR / personnel-management software in the spirit of Personio / HR-Works — for one company (single-tenant). Fully available in German and English, and extensible.
"A workplace for everything human."
Public landing page at /, the application after login at /dashboard.
Modules
| Area | Features |
|---|---|
| Employees | Directory (search/filter/pagination), detail profiles, create/edit, org chart |
| Absence | Leave balance, request → approval workflow, team overview, entitlement management |
| Time tracking | Clock-in/out, weekly overview + hours, manual entries, team times |
| Documents | Secure private storage, access-guarded download, HR upload, profile tab |
| Onboarding | Checklist templates + per-employee processes with checkable tasks |
| Performance | Goals (with self-service progress) + performance reviews (Draft → Submitted → Acknowledged) |
| Analytics | HR dashboard with KPIs + charts (headcount, contract types, new hires, absence days) |
| Recruiting | Job postings + applicant pipeline (Kanban, 6 stages) |
| News | Announcement feed + in-app notifications (topbar bell) |
Cross-cutting: roles & permissions (ADMIN / HR / MANAGER / EMPLOYEE, enforced server-side), DE/EN i18n (cookie-based, stored per user), light/dark mode, theming (style presets + corporate identity: accent color & logo), a REST API + MCP server (per-user tokens), and an audit log for write operations.
Tech stack
- Next.js 16 (App Router, TypeScript, Turbopack)
- PostgreSQL + Prisma 7 (pg driver adapter)
- Auth.js v5 (NextAuth) — Credentials, JWT session
- next-intl (DE/EN, no URL prefixes)
- Tailwind CSS v4 + shadcn/ui (Base UI)
- Vitest (unit tests)
Requirements
- Node.js 20+
- Docker (for local PostgreSQL) — or your own PostgreSQL instance
Quick start (local)
# 1. Dependencies
npm install
# 2. Environment variables
cp .env.example .env # adjust DATABASE_URL + AUTH_SECRET if needed
# 3. Start PostgreSQL (Docker, host port 5433)
docker compose up -d
# 4. Migrate schema + load demo data
npx prisma migrate dev
npm run db:seed
# 5. Dev server
npm run dev
Demo logins
All passwords: coworkee
| Role | |
|---|---|
| Administrator | admin@coworkee.test |
| HR | hr@coworkee.test |
| Manager | manager@coworkee.test |
| Employee | employee@coworkee.test |
The logins are shown on the login page (click fills the form) when the instance runs in demo mode (DEMO=1).
Environment variables
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string (Prisma) |
AUTH_SECRET |
Signing key for Auth.js sessions (required in production: openssl rand -base64 32) |
DEMO |
1 = demo instance: auto-seeds demo data on first boot if the DB is empty and shows the demo logins on /login. Unset/0 = real install (empty DB → setup wizard). Read at runtime. |
The DB URL is read by Prisma 7 from prisma.config.ts (via dotenv); the app/auth read .env directly.
Scripts
npm run dev # dev server
npm run build # production build
npm run start # production server (after build)
npm test # Vitest
npm run db:migrate # prisma migrate dev
npm run db:seed # demo data (idempotent)
Project structure (excerpt)
app/
page.tsx # public landing page (/)
(auth)/login/ # login (split-screen + demo logins)
(auth)/setup/ # first-run setup wizard (empty DB)
(app)/ # protected app (sidebar shell)
dashboard/ employees/ org/ absences/ time/ documents/
onboarding/ performance/ analytics/ recruiting/ news/
settings/ account/ notifications/
actions/ # server actions (Zod-validated, audited)
api/
auth/[...nextauth]/ # Auth.js
v1/ # REST API (Bearer token, OpenAPI)
mcp/ # MCP server (RBAC-scoped)
documents/[id]/ # access-guarded file download
branding/logo/ # tenant logo
version/ # version endpoint
components/ # UI (shadcn), feature components, marketing
lib/ # db, rbac, auth helpers, domain logic (tested)
messages/ # de.json, en.json (i18n)
prisma/ # schema.prisma, migrations, seed.ts
deploy/ # self-host / GHCR / Proxmox / Unraid / Umbrel packaging
storage/ # uploaded documents (not in repo, not public)
API & MCP
Coworkee exposes a real REST API and an MCP server, both authenticated with per-user API tokens that carry exactly that user's RBAC permissions (an AI/client can only do what the user may do).
- Create/revoke tokens: Account page (self-service, shown once).
- REST base:
GET /api/v1/*—me, employees, absences, time, documents, goals, reviews, recruiting, announcements, … · OpenAPI 3.1 atGET /api/v1/openapi.json. - MCP endpoint:
POST /api/mcp(JSON-RPC, RBAC-scoped tools). - In-app reference + client config:
/settings/api.
Send the token as Authorization: Bearer <token>.
Production notes
- Documents are stored under
storage/documents/→ hosting needs persistent storage (a volume). Serverless platforms without a persistent disk are unsuitable without object-storage integration. - Set
AUTH_SECRETand a strong DB password in production.POSTGRES_PASSWORDmust be URL-safe (use hex — no/ + =), since it is embedded inDATABASE_URL. - German deployment reference:
docs/DEPLOYMENT.md.
Installation & self-hosting
Coworkee ships as a Docker image (ghcr.io/fgilde/coworkeenextjs:latest) with a PostgreSQL 16 database. It listens on port 3000 and stores uploads in /app/storage (needs a persistent volume).
Fresh install vs. demo: on an empty database the first visit opens a setup wizard to create the admin account (no sample data). Set DEMO=1 to instead seed demo data and show the demo logins on /login (only on an empty DB; it never overwrites existing data). DEMO is read at runtime — no rebuild needed.
The GHCR image is published by CI on every push to master (tag latest) and on v* tags (semver). The GHCR package must be public (GitHub → Packages → the package → Package settings → Change visibility → Public) so servers can pull anonymously; otherwise run docker login ghcr.io (PAT with read:packages) first.
1. One command (any Linux with Docker)
curl -fsSL https://raw.githubusercontent.com/fgilde/CoworkeeNextJs/master/install.sh | sudo bash
Installs Docker if missing, clones to /opt/coworkee, generates secrets, asks for an optional domain (blank = plain HTTP on port 3000), and starts the stack with an empty database → setup wizard.
2. Docker Compose — prebuilt image (GHCR)
Recommended for low-RAM hosts (~1 GB): it pulls the prebuilt image instead of running next build, so it never OOMs. Run from the repo root:
# create deploy/.env with your secrets
cat > deploy/.env <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
AUTH_SECRET=$(openssl rand -hex 32)
DEMO=0 # 0 = fresh install (setup wizard); 1 = seed demo data
EOF
docker compose --env-file deploy/.env -f deploy/docker-compose.ghcr.yml pull
docker compose --env-file deploy/.env -f deploy/docker-compose.ghcr.yml up -d
This stack includes a Caddy reverse proxy (automatic HTTPS). Edit the root Caddyfile to your own domain first, or for LAN/plain-HTTP use deploy/docker-compose.selfhost-http.yml (app published directly on port 3000).
3. Proxmox VE
On the Proxmox host shell (not inside a container):
bash -c "$(curl -fsSL https://raw.githubusercontent.com/fgilde/CoworkeeNextJs/master/deploy/proxmox/coworkee.sh)"
Creates an unprivileged Debian LXC (defaults: 2 vCPU, 4 GB RAM, 12 GB disk), installs PostgreSQL and Node in it, builds Coworkee from its newest tag, generates the database password and the session secret, and leaves a systemd service behind — then prints the container IP and URL (http://<ip>:3020). Override defaults via env, e.g. CORES=4 RAM_MB=8192 STORAGE=local-lvm bash …. Scripts: deploy/proxmox/coworkee.sh on the host, deploy/proxmox/install.sh inside — the second one works on any Debian machine and is also how you update: run it again.
No Docker in there, deliberately. On a current Proxmox an unprivileged container runs no Docker container at all — runc writes net.ipv4.ip_unprivileged_port_start and /proc/sys is read-only — and a privileged container buys that back by handing the container root on the host. The database, the generated secrets and the uploaded documents survive an update.
4. Unraid
Coworkee needs a separate PostgreSQL 16 container (Unraid Community Applications is per-container). First start a Postgres 16 container (e.g. the postgres CA template) with a coworkee database and user, then add the Coworkee app:
- Copy
templates/coworkee.xmlto/boot/config/plugins/dockerMan/templates-user/on your Unraid server (or add its raw GitHub URL as a private CA template repo under Apps → Settings). - In the template set
DATABASE_URLto your Postgres container, e.g.postgresql://coworkee:PASSWORD@POSTGRES_HOST:5432/coworkee?schema=public, setAUTH_SECRET(openssl rand -base64 32), map/app/storageto appdata, and leaveDEMOempty for a fresh install. - Open the WebUI at
http://<unraid-ip>:3000.
Official listing in Community Applications later requires publishing the template to a GitHub template repo and contacting the CA maintainer (Squid) on the Unraid forums.
5. Umbrel
This repository is itself a community app store: umbrel-app-store.yml names it and fgilde-coworkee/ is the app (umbrel-app.yml + docker-compose.yml, bundling the app + PostgreSQL 16). In Umbrel, App Store → ⋯ → Community app stores, add https://github.com/fgilde/CoworkeeNextJs.
CasaOS
App Store → Add source with https://github.com/fgilde/CoworkeeNextJs/releases/download/store/casaos-appstore.zip, rebuilt from store/casaos/ on every push.
Cosmos
store/cosmos/servapps/Coworkee/ is a ServApp with its own PostgreSQL; the installer form asks for the session secret.
For an official listing, open a PR against getumbrel/umbrel-apps adding a coworkee/ directory with these two files plus gallery images.
License
Coworkee is dual-licensed: the open-source GNU AGPLv3 (see LICENSE)
or a commercial license for closed-source/proprietary use. Details and contact in
LICENSING.md.
Proprietary – © 2026 Coworkee.
Install Coworkee on Unraid in a few clicks.
Find Coworkee in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/fgilde/coworkeenextjs:latestRuntime arguments
- Web UI
http://[IP]:[PORT:3000]- Network
bridge- Shell
sh- Privileged
- false
Template configuration
Container Port: 3000 (Coworkee web UI)
- Target
- 3000
- Default
- 3000
- Value
- 3000
PostgreSQL 16 connection string. Point this at your separate Postgres container.
- Default
- postgresql://coworkee:CHANGEME@POSTGRES_HOST:5432/coworkee?schema=public
Auth.js session signing key. Generate with: openssl rand -base64 32
Let Auth.js trust the reverse-proxy host header. Keep 'true' on Unraid.
- Default
- true
- Value
- true
Leave empty for a fresh install (setup wizard). Set to 1 to seed demo data and show demo logins on an empty DB.
- Target
- DEMO
Uploaded documents. Must persist across container updates.
- Target
- /app/storage
- Default
- /mnt/user/appdata/coworkee/storage