P PowerDesk

PowerDesk — Installatiehandleiding

*Voor de systeembeheerder die PowerDesk op een eigen server installeert. Versie 1.3.*

PowerDesk draait volledig on-premise met Docker Compose. De stack bestaat uit drie containers: db (PostgreSQL 16), api en web (de webinterface, die /api/ doorzet naar de api-container). De api- en web-images worden kant-en-klaar geleverd via onze beveiligde registry — je hoeft niets te bouwen. Alle data — tickets, kennisbank, bijlagen én de optionele AI — blijft binnen je eigen omgeving.


1. Vereisten

  • Een Linux-server met Docker en Docker Compose v2 (docker compose).
  • 2 CPU-kernen / 4 GB RAM is ruim voldoende voor tientallen gelijktijdige gebruikers

(de optionele lokale AI vraagt méér, zie §8).

  • Een vrije poort voor de webinterface (standaard 8080, instelbaar met WEB_PORT).
  • Voor extern gebruik: een (sub)domein + reverse proxy met SSL (zie §10).
  • Het geleverde PowerDesk-pakket (zip) en je registry-toegangscode (pull-token).

2. Pakket uitpakken en registry-toegang

Pak het geleverde pakket uit op de server en log eenmalig in op de image-registry met de meegeleverde gebruikersnaam en toegangscode:

cd ~
unzip powerdesk-kit-v1.3.zip && mv powerdesk-kit powerdesk
cd powerdesk
docker login ghcr.io -u <geleverde-gebruikersnaam>
# Plak bij 'Password' het geleverde pull-token
Het token geeft alleen *lees*-toegang tot de PowerDesk-images en kan door de
leverancier worden vernieuwd of ingetrokken. Behandel het als een wachtwoord.

3. Configuratie: .env aanmaken

cp .env.example .env

De .env bevat geheimen en hoort alleen op de server te staan. Vul ten minste in:

Variabele Verplicht Toelichting
DB_PASSWORD aanbevolen Wachtwoord voor de PostgreSQL-gebruiker. Default powerdesk — verander dit.
JWT_SECRET ja Lange willekeurige string. Genereer met openssl rand -base64 48.
WEB_ORIGIN ja Publieke URL waarop gebruikers de app openen, bv. https://helpdesk.bedrijf.nl (gebruikt voor CORS).
SEED_ADMIN_EMAIL aanbevolen E-mailadres van de eerste administrator. Default admin@example.com.
SEED_ADMIN_PASSWORD aanbevolen Wachtwoord van de eerste administrator. Default PowerDesk!2026 — direct wijzigen na eerste login.
POWERDESK_LICENSE nee Licentiesleutel uit de leveringsmail (één regel). Leeg = 30 dagen proefperiode, daarna alleen-lezen. Zie §3a.
DATABASE_URL hoeft in Compose niet in .env; die wordt in docker-compose.yml
opgebouwd uit DB_PASSWORD en wijst naar de db-container.
Gebruik in DB_PASSWORD alleen letters en cijfers: tekens als # @ : / ? en
spaties breken de databaseverbindingsstring.

3a. Licentiesleutel en proefperiode

PowerDesk werkt met een licentiesleutel die je pakket (Basis, Pro of Enterprise) en de looptijd van je abonnement vastlegt.

  • Bij aankoop ontvang je de sleutel in de leveringsmail. Plak hem als één regel in .env:
  POWERDESK_LICENSE="<de sleutel uit de leveringsmail>"

Activeer met docker compose up -d api. De licentie wordt daarna automatisch verlengd zolang je abonnement loopt — je hoeft niets bij te werken. Werkt de server tijdelijk zonder internet, dan gebeurt er niets en blijft de bestaande licentie geldig.

  • Zonder sleutel draait een verse installatie 30 dagen volledig als proefperiode.

Daarna schakelt de omgeving naar alleen-lezen tot je een geldige sleutel invult.

  • Pakketlimiet: het aantal accounts met de rol *Behandelaar of hoger* is begrensd door je

pakket (Basis 5, Pro 15, Enterprise onbeperkt). Boven de limiet kun je geen extra behandelaar aanmaken of activeren tot er ruimte is; melders zijn onbeperkt.

  • Verlopen abonnement: vanaf de vervaldatum ziet de beheerder een waarschuwing. Na een

respijtperiode van 14 dagen gaat de omgeving in alleen-lezen: je kunt alles nog inzien en exporteren, maar niets meer wijzigen. Zodra een geldige licentie binnenkomt (automatisch na betaling, of door een nieuwe sleutel in te vullen) werkt alles direct weer normaal. Je data blijft altijd van jou.

4. Branding: jouw naam en logo (white-label)

PowerDesk toont standaard neutrale PowerDesk-branding. Zet je eigen organisatie erin via .env — geen code-aanpassing nodig:

ORG_NAME="Jansen Techniek B.V."
# Optioneel: eigen logo's (volledige URL, bv. op je intranet of in de app zelf):
ORG_LOGO_URL="https://intranet.bedrijf.nl/logo.svg"          # licht scherm (inlogpagina)
ORG_LOGO_ON_DARK_URL="https://intranet.bedrijf.nl/logo-wit.svg"  # donkere zijbalk; leeg = ORG_LOGO_URL
  • ORG_NAME verschijnt op het inlogscherm, in de topbar, in de browsertitel en in de

AI-assistent.

  • Zonder logo-URL's wordt het gebundelde PowerDesk-logo gebruikt.
  • Eigen logo's in de app-installatie zelf bundelen (incl. PWA-app-iconen) is

maatwerk — neem daarvoor contact op met de leverancier.

Wijzigingen in .env activeer je met docker compose up -d api.

5. Ophalen en starten

docker compose pull
docker compose up -d

De api-container draait bij het opstarten automatisch prisma migrate deploy; het databaseschema wordt dus zelf aangemaakt en bij updates bijgewerkt.

Controleer:

docker compose ps
curl -s http://localhost:8080/api/health     # verwacht: {"status":"ok"}
curl -s http://localhost:8080/api/branding   # verwacht: jouw ORG_NAME

6. Eerste keer: beheerder + SLA-beleid seeden

Eenmalig na de eerste start:

docker compose exec api node dist/seed.js

Dit maakt de eerste administrator aan (SEED_ADMIN_EMAIL / SEED_ADMIN_PASSWORD) en het standaard SLA-beleid per prioriteit. De seed is idempotent: nogmaals draaien doet geen kwaad en overschrijft geen bestaande gebruikers. Bestond de seed-account al met rol *Beheerder* (van vóór de administrator-rol), dan wordt die bij het seeden bewust naar *Administrator* opgewaardeerd zodat er altijd minstens één volwaardige beheerder is.

Log in, wijzig direct het wachtwoord (Mijn profiel) en richt daarna de helpdesk in volgens de beheerdershandleiding.

7. Aanmelden & e-mail (optioneel)

Alle onderstaande blokken zijn fail-safe: leeg laten = die functie staat uit en de rest werkt gewoon door.

Microsoft 365 / Entra SSO

  1. Registreer in Entra ID → App registrations een app.

Redirect-URI (type *Web*): <WEB_ORIGIN>/api/auth/entra/callback.

  1. Maak een client secret aan.
  2. Zet in .env: ENTRA_TENANT_ID, ENTRA_CLIENT_ID, ENTRA_CLIENT_SECRET,

ENTRA_REDIRECT_URI.

  1. Optionele toegangsregels (OR-logica: domein óf groepslid):
  • ALLOWED_EMAIL_DOMAINS="bedrijf.nl,dochter.nl"
  • ALLOWED_GROUP_IDS="<entra-groeps-object-id's>"
  • Rollen automatisch toekennen: ROLE_GROUP_MAP="<groepid>:ADMINISTRATOR,<groepid>:BEHEERDER,<groepid>:BEHANDELAAR"

(geldige rollen: MELDER, BEHANDELAAR, TEAMLEIDER, BEHEERDER, ADMINISTRATOR; alleen verhogen, nooit verlagen)

Uitgaande mail

Twee opties; Graph heeft voorrang als beide ingesteld zijn:

  • SMTP: SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM.
  • Microsoft Graph (app-only Mail.Send): GRAPH_MAIL_TENANT_ID,

GRAPH_MAIL_CLIENT_ID, GRAPH_MAIL_CLIENT_SECRET, GRAPH_MAIL_FROM.

  • PUBLIC_BASE_URL = de publieke app-URL; wordt gebruikt voor links in mails

(o.a. goedkeuren-via-mail).

E-mail-intake (mailbox → ticket)

Een gedeelde supportmailbox die PowerDesk periodiek leest; elke nieuwe mail wordt een ticket: IMAP_HOST, IMAP_PORT, IMAP_USER, IMAP_PASS, IMAP_TLS, SUPPORT_EMAIL (het adres waarop medewerkers mailen), MAIL_POLL_INTERVAL_MS.

Tweestapsverificatie (2FA)

Lokale accounts kunnen 2FA (authenticator-app) aanzetten via Mijn profiel. Voor welke rollen het verplicht is bepaal je met TWO_FACTOR_REQUIRED_ROLES (default BEHEERDER,ADMINISTRATOR; leeg = niemand verplicht). Microsoft 365-logins hebben al MFA via Microsoft. Beheerders/administrators kunnen elkaars 2FA resetten via Gebruikers-beheer; raakt de laatste beheerder buitengesloten, reset dan via de database: docker compose exec db psql -U powerdesk powerdesk -c "UPDATE \"User\" SET \"twoFactorEnabled\"=false, \"totpSecret\"=NULL WHERE email='<beheerder>';"

Microsoft Teams-kanaalmeldingen

Nieuwe tickets, SLA-escalaties en gemelde storingen in een Teams-kanaal:

  1. Maak in Teams (kanaal → Workflows) de flow **"Post to a channel when a webhook

request is received"** en kopieer de webhook-URL.

  1. Zet in .env: TEAMS_WEBHOOK_URL="<de gekopieerde URL>" en herstart de api.

Leeg laten = geen Teams-meldingen; mislukte posts worden stil overgeslagen.

Web Push-notificaties

Meldingen op het toestel, ook als de app dicht is. Genereer een VAPID-sleutelpaar (npx web-push generate-vapid-keys) en zet VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY en VAPID_SUBJECT (mailto: van de beheerder). Gebruikers zetten push aan via Mijn profiel. Vereist https.

8. AI-functies (optioneel, lokaal)

De AI-functies — samenvatten, antwoord/categorie voorstellen, de KB-chatbot en "maak KB-artikel" — gebruiken een lokale LLM via Open WebUI/Ollama. Ticketinhoud verlaat je omgeving dus niet. Zonder configuratie geven de AI-knoppen een nette melding en werkt al het andere gewoon.

  1. Installeer Ollama + Open WebUI op de

server (of een andere machine); trek een model, bv. ollama pull llama3.1:8b.

  1. Maak in Open WebUI een API-key aan voor een service-account.
  2. Zet in .env:
OPENWEBUI_API_BASE=http://host.docker.internal:8090/api
OPENWEBUI_API_KEY=sk-...
OPENWEBUI_MODELS=llama3.1:8b
OPENWEBUI_ASSIST_MODEL=llama3.2:3b   # snel model voor de ticket-helpers
Netwerk vanuit de container: 127.0.0.1 binnen de api-container is de container
zelf. Gebruik host.docker.internal en voeg op Linux bij de api-service toe:
extra_hosts: ["host.docker.internal:host-gateway"].

Richtlijn hardware: een 3B-model draait prima op CPU; 7–8B wordt vlot met een GPU.

9. Snipe-IT asset-koppeling (optioneel)

Gebruik je Snipe-IT als assetbeheer, dan spiegelt PowerDesk de apparaten read-only (Snipe-IT blijft de bron):

SNIPEIT_API_URL=https://assets.bedrijf.nl/api/v1
SNIPEIT_API_TOKEN=<personal API token>
SNIPEIT_SYNC_INTERVAL_MINUTES=60     # 0 = alleen handmatig via de knop

Eigenaren worden gematcht op e-mailadres; apparaten die uit Snipe-IT verdwijnen worden op *Uit dienst* gezet. Handmatig aangemaakte apparaten blijven gewoon bewerkbaar.

10. Reverse proxy + SSL (aanbevolen voor extern gebruik)

De web-container publiceert alleen op 127.0.0.1:8080. Zet er een reverse proxy met een certificaat voor, bv. nginx:

server {
    listen 443 ssl http2;
    server_name helpdesk.bedrijf.nl;
    ssl_certificate     /etc/letsencrypt/live/helpdesk.bedrijf.nl/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/helpdesk.bedrijf.nl/privkey.pem;

    client_max_body_size 15m;   # bijlagen/plattegronden

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

De geleverde images zijn gebouwd voor hosting op het root-pad van een (sub)domein (zoals hierboven). Hosting onder een subpad (bv. https://intranet.bedrijf.nl/helpdesk/) is maatwerk — neem daarvoor contact op met de leverancier.

11. Updaten naar een nieuwe versie

Is er een nieuwe versie, dan ziet de beheerder dat vanzelf als melding bovenin PowerDesk (de app controleert dat dagelijks; werkt de server zonder internet, dan blijft de melding gewoon achterwege). Updaten is één commando op de server, in de PowerDesk-map:

./update.sh v1.1

Het script zet de versie in .env, haalt de nieuwe images op, herstart de stack (databasemigraties draaien automatisch mee) en wacht tot alles weer gezond is. Handmatig kan ook: POWERDESK_VERSION aanpassen in .env → docker compose pull && docker compose up -d.

12. Back-up & herstel

De database leeft in het Docker-volume pgdata; bijlagen in UPLOAD_DIR.

# Back-up
docker compose exec -T db pg_dump -U powerdesk powerdesk > powerdesk-$(date +%F).sql

# Herstel (in een lege database)
cat powerdesk-YYYY-MM-DD.sql | docker compose exec -T db psql -U powerdesk powerdesk

Geautomatiseerd: scripts/backup-db.sh maakt een gecomprimeerde dump in backups/ met 14-daagse rotatie. Als dagelijkse cron (03:30):

chmod +x scripts/backup-db.sh
( crontab -l 2>/dev/null | grep -v backup-db.sh; \
  echo "30 3 * * * $HOME/powerdesk/scripts/backup-db.sh >> $HOME/powerdesk/backups/backup.log 2>&1" ) | crontab -

Ingebouwde robuustheid: log-rotatie (10 MB × 3 per container) en healthchecks (api start pas als de database gezond is) — zie docker compose ps.

13. Probleemoplossing

docker compose logs -f api    # migraties, fouten
docker compose logs -f web    # nginx
docker compose logs -f db     # PostgreSQL
Symptoom Oorzaak / oplossing
502 of /api werkt niet api-container niet Up? Migratie mislukt? → docker compose logs api
CORS-fouten in de browser WEB_ORIGIN moet exact overeenkomen met de URL waarop gebruikers de app openen
AI-knoppen geven 503 OPENWEBUI_* ontbreekt of endpoint onbereikbaar → docker compose exec api wget -qO- $OPENWEBUI_API_BASE/models
Branding verandert niet .env gewijzigd maar api niet herstart → docker compose up -d api; harde refresh in de browser
Mail komt niet aan Controleer SMTP_*/GRAPH_MAIL_* en de logs; Graph heeft voorrang op SMTP

Volgende stappen: richt de helpdesk in met de beheerdershandleiding en deel de gebruikershandleiding met je medewerkers.

← Alle handleidingen