A robust Node.js backend for an acquisitions system built with Express.js 5.x, Drizzle ORM, and PostgreSQL. This project features a modern ES modules setup, advanced security with Arcjet, and a full Docker/Kubernetes deployment pipeline.
- Runtime: Node.js 22 (ES modules)
- Framework: Express.js 5.x
- Database: PostgreSQL with Neon Serverless
- ORM: Drizzle ORM
- Security: Arcjet (Bot Protection, Rate Limiting, Shield WAF)
- Authentication: JWT with
httpOnlycookies &bcrypthashing - Validation: Zod schemas
- Containerization: Docker
- Deployment Kubernetes-Minikube
- CI/CD Pipeline: Github Actions
- Logging: Winston + Morgan
- Code Quality: ESLint + Prettier
src/index.js (Env Loader) → src/server.js (Server Startup) → src/app.js (App Config)
We use Node.js import maps for clean module imports using the # prefix:
#config/*→./src/config/*#controllers/*→./src/controllers/*#middleware/*→./src/middleware/*#models/*→./src/models/*#routes/*→./src/routes/*#services/*→./src/services/*#utils/*→./src/utils/*#validations/*→./src/validations/*
- Routes: Express route definitions.
- Controllers: Handle HTTP requests/responses.
- Services: Business logic and data operations.
- Models: Drizzle ORM table definitions.
- Validations: Zod schema validations.
- Utils: Shared utility functions.
- Neon Database Branching: Uses
/.neon-localto allow testing migrations on a copy of data without touching production. - Schema Management: Managed via files in
src/models/. - Migrations: Generated and stored in the
drizzle/directory. - Configuration: Database connection setup in
src/config/database.js.
- JWT-based auth with
httpOnlycookies. - Bcrypt password hashing (10 rounds).
- Role-based access control (User/Admin) via auth middleware.
- Utilities in
src/utils/jwt.jsandsrc/utils/cookies.js.
- Bot Protection: Blocks malicious automated traffic.
- Rate Limiting: Prevents API abuse.
- Shield: Protects against SQL injection and Cross-Site Scripting (XSS).
- Winston: Configured in
src/config/logger.js. - Files: Error logs in
logs/error.logand combined logs inlogs/combined.log. - Console: Active during development for real-time debugging.
- Morgan: Integrated with Winston for HTTP request logging.
- Multi-stage builds: Optimized for small image size and security.
- Base Image:
node:22-alpine. - User Security: Runs as a non-root
nodejsuser. - Optimization: Uses
npm ci --only=productionfor immutable builds. - Registry: Pushed to Docker Hub as
mrkyojin/kubernetes-api.
Declarative manifests are located in k8s/:
- Deployment: Runs 2 replicas for high availability.
- Service: Exposed via
LoadBalanceron port5173. - Health Checks: Liveness and Readiness probes at
/healthzand/readyzfor zero-downtime restarts. - Automation:
scripts/deploy.shhandles building, pushing, and updating the cluster.
Automated via GitHub Actions in three phases:
- Static Analysis (
lint-and-format.yml): Runs ESLint and Prettier. - Automated Testing (
tests.yml): Uses Jest and Supertest. - Containerization (
docker-build-docker-push.yml): Packages via Docker Buildx and pushes to Docker Hub only if previous stages pass.
| Category | Command | Description |
|---|---|---|
| Dev | npm run dev:docker |
Start dev server with file watching |
npm run prod:docker |
Start production server | |
npm run db:migrate |
Apply database migrations | |
| Quality | npm run lint |
Run ESLint |
npm run lint:fix |
Fix linting issues automatically | |
npm run format |
Format code with Prettier | |
| DevOps | minikube start |
Start Minikube |
npm run deploy:k8s-minikube |
Build, Push, and Deploy |
Create .env.development files based on .env_example:
PORT=5173
DATABASE_URL=postgresql://...
JWT_SECRET=your-secret-key-here
NODE_ENV=development
LOG_LEVEL=info