Project Introduction & Development Overview
KDS Werkzeugbau is a corporate website built for KDS Werkzeugbau GmbH, a German tool and mould manufacturer. The project covers a public-facing multilingual company website — including core competencies, news, job listings, and contact — as well as a staff admin portal for content management. The architecture is identical to the Marienmühle project, sharing the same monorepo stack, so this page focuses on what is different.
System Specifications & Feature Overview
The system is focused on corporate content management rather than transactional workflows. There are no reservations or menus — instead the key public-facing features are the news feed, job board, core competency pages, and a contact/inquiry form.
Database Architecture & Schema
The database is PostgreSQL with Prisma ORM, following the same migration workflow as Marienmühle. The schema is simpler — there are no reservations or tables. The core models are:
- Post — News and event articles with optional image, PDF, date range, and tags ()
- Job — Open positions with tasks, profile requirements, benefits, and a start/end date range
- Customer — Inquiry senders (name, optional email, optional phone, newsletter opt-in)
- ContactRequest — Linked to a Customer; carries a one-time process token for staff acknowledgement
- Media — Images and PDFs stored in SeaweedFS, referenced by Posts
- Email / EmailTemplate — Job queue records and MJML template references
- Staff / RefreshToken — Admin users and session management
- ClosedDay — Date ranges when the company is closed
- Settings — Company name and contact email used across the site
Project Structure & Turborepo Monorepo Setup
Identical monorepo layout to Marienmühle — three apps under and six shared packages under , built with Turborepo.
- api
- email-worker
- web
- common
- database
- eslint-config
- logger
- typescript-config
- ui
- docs
- bruno
REST API Endpoints & NestJS Backend
The API is a NestJS application. Modules cover: auth, analytics, posts, jobs, contact-requests, customers, media, email, email-template, settings, staff, closed-days, health, storage, and BullMQ. Most write endpoints require staff authentication; public endpoints are limited to reading posts/jobs and submitting contact requests.
Get all news posts with optional tag filtering and pagination
Query Parameters:
Create a new post (staff only)
Request Body (json):
Get all active job listings
Query Parameters:
Submit a public contact/inquiry request
Request Body (json):
Upload image or PDF to SeaweedFS (staff only)
Request Body (form):
Authentication & Security
Authentication is the same CSRF + JWT dual-cookie scheme used in Marienmühle — short-lived access token (HS512, 15 min), long-lived refresh token (7 days), and a 48-character hex CSRF token. All three arrive as cookies on login; write endpoints check the CSRF token in addition to the access JWT.
Staff authentication with email and password
Request Body (json):
Staff logout and deletion of session cookies
Refresh access token using refresh token cookie
Incoming request bodies are validated with Zod via a custom NestJS before any business logic runs, rejecting malformed input with a 400 response.
Next.js Web Application
The web app uses the same Next.js 16 / Tailwind v4 / setup as Marienmühle with one notable addition: next-intl for German/English internationalisation. Translation JSON files live in and .
The app is split into three route groups:
- — public-facing company site (home, core competencies, news, jobs, contact, directions)
- — staff portal (dashboard, posts, jobs, customers, contact requests, emails, settings, closed days)
- — login and preview-login flows
Email Worker Service
The email worker is a separate NestJS application that consumes the BullMQ queue backed by Redis. It handles two email types:
- Contact Request Confirmation — sent to the customer immediately after they submit an inquiry
- Contact Request Notification — sent to staff to alert them of a new inquiry
Templates are written in MJML and rendered via Handlebars for dynamic content. Nodemailer handles dispatch; failed jobs are retried with exponential backoff.
Docker Deployment & CI/CD Pipeline
Deployment follows the same pattern as Marienmühle — Docker Compose, Coolify, and GitHub Actions. Four application images are built and pushed to GitHub Container Registry: , , , and . Each has its own build workflow triggered by path-filtered pushes to .
A single workflow watches for the successful completion of all four build workflows, then triggers a Coolify webhook to pull and restart the updated containers.