Desktop-friendly search tool for finding the responsible person for a German postal code or locality.
- Sign in with Microsoft Entra ID or Basic Auth
- Search by PLZ or locality for all signed-in users
- Show the import UI only to admins with the Entra app role value
Assignment.Import - Replace assignment data through Excel import
- Store application data in SQLite
- Optional Electron wrapper with a configurable search hotkey such as
F9orCtrl+Alt+K
- Normal users: search only
- Admin users: search plus import
- Entra admin detection is based on the token
rolesclaim containing the app role value - Default accepted admin role values are
Assignment.ImportandAdmin - Basic Auth remains a local fallback mode with import access enabled
Copy .env.example to .env.local and fill in the values.
Required variables:
AUTH_METHOD=entraorAUTH_METHOD=basicAPP_COMPANY_NAMEfor the company label in the UINEXTAUTH_URLfor the public web app base URL, for examplehttp://localhost:3000AUTH_SECRETAUTH_MICROSOFT_ENTRA_ID_IDAUTH_MICROSOFT_ENTRA_ID_SECRETAUTH_MICROSOFT_ENTRA_ID_TENANT_IDAUTH_MICROSOFT_ENTRA_ID_ADMIN_ROLE_VALUESBASIC_AUTH_PASSWORDwhenAUTH_METHOD=basic
Entra requirements:
- Create or reuse an Entra application registration
- Add an app role with a suitable value such as
Assignment.Import - Assign that role to users who should be allowed to import
- Make sure the signed-in token contains the
rolesclaim - The app checks the role
Value, not the display name shown in the Entra portal - Configure the local redirect URI:
http://localhost:3000/api/auth/callback/microsoft-entra-id
npm install
npm run devOpen http://localhost:3000.
npm run test
npm run lint
npm run buildBuild once, then let PM2 run the production server through the committed ecosystem file:
npm run build
npm run pm2:startRestart an existing PM2 process after a new build with:
npm run pm2:restartThe committed ecosystem.config.cjs:
- starts the built Next.js app as
plz-minitool - defaults to
PORT=3000andHOSTNAME=0.0.0.0 - reads overridden
PORT,HOSTNAME, and auth variables from the environment
JetBrains project run configurations are included in .run/ for:
BuildPM2 StartPM2 Restart
- Number input is treated as PLZ
- Exact PLZ matches are preferred before prefix matches
- Text input searches localities
- Live search updates in place after a short debounce instead of reloading the page on every keypress
- While a new query is loading, the previous search surface stays visible so the panel does not flicker through an empty state
- The current query stays in the
qURL parameter for bookmarking and sharing - The current data set always comes from the latest successful import
Example searches:
10115Berlin
- Only available to admins with a matching Entra role value such as
Assignment.Import - Accepts
.xlsxand.xlsm - Automatically selects the most suitable worksheet
- Header rows are allowed
- Column A must contain PLZ values
- Column B must contain the responsible person
- A new import replaces all existing assignments
- For duplicate PLZ entries, the last row wins
Development:
npm run electron:devWindows package:
npm run electron:pack -- --app-url=https://your-app.example.comElectron URL variables:
npm run electron:devalready injectsAPP_WEB_URL=http://localhost:3000npm run electron:packnow loads.env.local, soAPP_WEB_URLcan come from there- packaged Electron builds need
APP_WEB_URLonly for the pack step, either through.env.local,--app-url=..., or the environment APP_WEB_URLis optional unless you build the Electron package
The Electron app:
- opens the web app
- hides the native Electron menu bar
- uses
F9by default and lets users capture another shortcut directly in the UI - supports combinations such as
Ctrl+Alt+K - focuses the search field when triggered
- can start Microsoft SSO in the default browser and finish the desktop login inside Electron after the browser flow succeeds
- starts the desktop browser login through the app's own auth route so the web login flow stays compatible
- keeps pending desktop login requests in SQLite so development reloads do not break the browser handoff
- SQLite defaults to
data/app.db - Reference PLZ data is loaded on first start
- Missing auth variables are shown on the login page
- GeoNames attribution lives in
data/reference/ATTRIBUTION.md
OAuthCallbackErroron login: verify the redirect URI and make sureAUTH_MICROSOFT_ENTRA_ID_SECRETcontains the secret value, not the secret ID- Import link does not appear:
confirm the signed-in Entra token includes the app role value, for example
Assignment.Import, in therolesclaim - User can search but cannot import: the account is authenticated, but no configured admin role value was found
- No search results after setup: import an Excel file first
- Search suddenly redirects to login: the authenticated session expired and the search API now requires a fresh login
- PM2 restart does not pick up new settings:
rebuild if required and use
npm run pm2:restartso PM2 refreshes the process environment - Desktop login does not return to the Electron app:
finish the Microsoft login in the real browser first; Electron now continues by
polling the server, so the custom
plz-zuordnung://callback is optional rather than required - The Electron app shows only the normal web login button: update the deployed web app as well as the Electron shell; the Electron-only browser login button is added on the client after hydration and will stay hidden if the deployed web bundle is still on the older code