feat : add docker

This commit is contained in:
Yusron alamsyah
2026-02-27 14:17:28 +07:00
parent a1efe0a73b
commit 8d9c2585e4
10 changed files with 459 additions and 25 deletions
+49
View File
@@ -0,0 +1,49 @@
# Node modules
node_modules
npm-debug.log
yarn-error.log
# Build outputs
.output
.nuxt
dist
.cache
# Environment files
.env
.env.local
.env.*.local
# IDE
.vscode
.idea
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Git
.git
.gitignore
.github
# Documentation
README.md
docs
# Test files
*.test.js
*.spec.js
coverage
# Logs
logs
*.log
# Docker files (if building)
Dockerfile
.dockerignore
docker-compose.yml
+23
View File
@@ -0,0 +1,23 @@
# Environment Variables Example
# Copy this file to .env and fill in your values
# This file is used by both development and Docker
# Application
NODE_ENV=development
# Keycloak Configuration
KEYCLOAK_ISSUER=https://your-keycloak-server/realms/your-realm
KEYCLOAK_CLIENT_ID=your-client-id
KEYCLOAK_CLIENT_SECRET=your-client-secret
# API Configuration
NUXT_PUBLIC_API_BASE_URL=https://your-api-server.com
NUXT_PUBLIC_AUTH_URL=http://localhost:3005
# Database (if needed)
# DATABASE_URL=postgresql://user:password@postgres:5432/dbname
# Redis (if using Redis for session store)
# REDIS_HOST=redis
# REDIS_PORT=6379
# REDIS_PASSWORD=your-redis-password
+5 -2
View File
@@ -5,6 +5,9 @@ node_modules
.cache
.output
.env
.env.local
.env.*.local
dist
Dockerfile
docker-compose.yml
# Dockerfile and docker-compose.yml should be committed
# Dockerfile
# docker-compose.yml
+61
View File
@@ -0,0 +1,61 @@
# Dockerfile for Nuxt.js Application
# Multi-stage build for optimized image size
# Stage 1: Build Stage
FROM node:20-alpine AS builder
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy application files
COPY . .
# Build the application
RUN npm run build
# Stage 2: Production Stage
FROM node:20-alpine AS runner
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install production dependencies only (skip postinstall script)
RUN npm ci --omit=dev --ignore-scripts
# Copy built application from builder stage
COPY --from=builder /app/.output /app/.output
COPY --from=builder /app/.nuxt /app/.nuxt
COPY --from=builder /app/nuxt.config.ts /app/nuxt.config.ts
COPY --from=builder /app/node_modules /app/node_modules
# Create non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nuxtjs -u 1001 && \
chown -R nuxtjs:nodejs /app
# Switch to non-root user
USER nuxtjs
# Expose port
EXPOSE 3000
# Set environment variables
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start the application
CMD ["node", ".output/server/index.mjs"]
+179
View File
@@ -0,0 +1,179 @@
# Docker Deployment Guide
## 📦 Prerequisites
- Docker Desktop installed
- Docker Compose installed (included with Docker Desktop)
## 🚀 Quick Start
### 1. Build the Docker Image
```bash
docker build -t antrean-operasi:latest .
```
### 2. Run with Docker Compose
```bash
# Make sure .env file exists with your configuration
# Docker Compose will automatically use .env file
docker-compose up -d
```
### 3. Run without Docker Compose
```bash
docker run -d \
--name antrean-operasi \
-p 3005:3000 \
-e KEYCLOAK_ISSUER=https://your-keycloak/realms/your-realm \
-e KEYCLOAK_CLIENT_ID=your-client-id \
-e KEYCLOAK_CLIENT_SECRET=your-client-secret \
-e API_BASE_URL=https://your-api.com \
-e AUTH_URL=http://localhost:3005 \
antrean-operasi:latest
```
## 🔧 Available Commands
### Build image
```bash
docker build -t antrean-operasi:latest .
```
### Start containers
```bash
docker-compose up -d
```
### Stop containers
```bash
docker-compose down
```
### View logs
```bash
docker-compose logs -f antrean-operasi
```
### Rebuild and restart
```bash
docker-compose up -d --build
```
### Access container shell
```bash
docker exec -it antrean-operasi sh
```
## 🌐 Access Application
After starting the container, access the application at:
- **http://localhost:3005**
## 📝 Environment Variables
Required environment variables (set in `.env` file):
| Variable | Description | Example |
|----------|-------------|---------|
| `KEYCLOAK_ISSUER` | Keycloak realm URL | `https://keycloak.example.com/realms/myrealm` |
| `KEYCLOAK_CLIENT_ID` | Keycloak client ID | `antrean-operasi-client` |
| `KEYCLOAK_CLIENT_SECRET` | Keycloak client secret | `your-secret-here` |
| `API_BASE_URL` | Backend API URL | `https://api.example.com` |
| `AUTH_URL` | Application auth URL | `http://localhost:3005` |
## 🐳 Docker Hub (Optional)
### Tag and Push to Docker Hub
```bash
# Tag the image
docker tag antrean-operasi:latest yourusername/antrean-operasi:latest
# Login to Docker Hub
docker login
# Push to Docker Hub
docker push yourusername/antrean-operasi:latest
```
### Pull from Docker Hub
```bash
docker pull yourusername/antrean-operasi:latest
```
## 🔍 Troubleshooting
### Check container status
```bash
docker ps -a
```
### View detailed logs
```bash
docker logs antrean-operasi
```
### Check container resource usage
```bash
docker stats antrean-operasi
```
### Restart container
```bash
docker restart antrean-operasi
```
### Remove all containers and images
```bash
docker-compose down --rmi all --volumes
```
## 🏗️ Production Recommendations
1. **Use environment-specific configs**: Create separate `.env.production` files
2. **Enable HTTPS**: Use a reverse proxy (Nginx, Traefik) with SSL certificates
3. **Use Docker secrets**: For sensitive data in production
4. **Set resource limits**: Add memory and CPU limits in docker-compose.yml
5. **Use Redis**: Replace in-memory session store with Redis
6. **Setup monitoring**: Add health checks and monitoring tools
7. **Regular backups**: Backup mounted volumes and data
### Example Production docker-compose.yml with limits:
```yaml
services:
antrean-operasi:
# ... other config ...
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
```
## 📊 Health Check
The container includes a health check endpoint. Check container health:
```bash
docker inspect --format='{{json .State.Health}}' antrean-operasi
```
## 🔐 Security Notes
- Never commit `.env.docker` to version control
- Use Docker secrets for production deployments
- Run container as non-root user (already configured)
- Regularly update base images for security patches
## 📞 Support
For issues or questions, please contact the development team.
+35
View File
@@ -0,0 +1,35 @@
version: '3.8'
services:
antrean-operasi:
build:
context: .
dockerfile: Dockerfile
container_name: antrean-operasi
ports:
- "3005:3000"
env_file:
- .env
environment:
- NODE_ENV=production
- HOST=0.0.0.0
- PORT=3000
volumes:
# Mount for persistent data
- ./data:/app/data
restart: unless-stopped
networks:
- antrean-network
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
antrean-network:
driver: bridge
volumes:
data:
+17 -14
View File
@@ -89,22 +89,25 @@ export default defineNuxtConfig({
// }
},
runtimeConfig: {
// Nuxt will automatically map NUXT_* environment variables
// NUXT_KEYCLOAK_CLIENT_ID → keycloakClientId
authSecret: process.env.NUXT_AUTH_SECRET,
keycloakClientId: process.env.KEYCLOAK_CLIENT_ID,
keycloakClientSecret: process.env.KEYCLOAK_CLIENT_SECRET,
keycloakIssuer: process.env.KEYCLOAK_ISSUER,
keycloakLogoutUri: process.env.KEYCLOAK_LOGOUT_URI, // Optional: custom logout URI
postLogoutRedirectUri: process.env.POST_LOGOUT_REDIRECT_URI, // Optional: custom post-logout redirect URI
keycloakClientId: process.env.NUXT_KEYCLOAK_CLIENT_ID || process.env.KEYCLOAK_CLIENT_ID,
keycloakClientSecret: process.env.NUXT_KEYCLOAK_CLIENT_SECRET || process.env.KEYCLOAK_CLIENT_SECRET,
keycloakIssuer: process.env.NUXT_KEYCLOAK_ISSUER || process.env.KEYCLOAK_ISSUER,
keycloakLogoutUri: process.env.NUXT_KEYCLOAK_LOGOUT_URI || process.env.KEYCLOAK_LOGOUT_URI,
postLogoutRedirectUri: process.env.NUXT_POST_LOGOUT_REDIRECT_URI || process.env.POST_LOGOUT_REDIRECT_URI,
public: {
authUrl: process.env.AUTH_ORIGIN,
// authUrl: process.env.AUTH_ORIGIN || "http://10.10.150.175:3001",
// authUrl: process.env.AUTH_ORIGIN || "http://localhost:3001",
wsBaseUrl: process.env.WS_BASE_URL || 'ws://10.10.150.100:8084/api/v1/ws',
baseUrl: process.env.BASE_URL || 'http://10.10.150.144:8080/api',
baseUrlGomed: process.env.BASE_URL_GOMED || 'https://gomed.rssa.my.id/api',
keycloakUrl: process.env.KEYCLOAK_ISSUER ? `${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token` : 'https://auth.rssa.top/realms/sandbox/protocol/openid-connect/token',
keycloakClientId: process.env.KEYCLOAK_CLIENT_ID || 'akbar-test',
keycloakClientSecret: process.env.KEYCLOAK_CLIENT_SECRET || 'FDyv3UYMgJOYPnvzXVVv6diRtcgEevKg',
// NUXT_PUBLIC_* variables are exposed to client-side
authUrl: process.env.NUXT_PUBLIC_AUTH_URL || process.env.AUTH_ORIGIN,
wsBaseUrl: process.env.NUXT_PUBLIC_WS_BASE_URL || process.env.WS_BASE_URL || 'ws://10.10.150.100:8084/api/v1/ws',
baseUrl: process.env.NUXT_PUBLIC_BASE_URL || process.env.BASE_URL || 'http://10.10.150.144:8080/api',
baseUrlGomed: process.env.NUXT_PUBLIC_BASE_URL_GOMED || process.env.BASE_URL_GOMED || 'https://gomed.rssa.my.id/api',
keycloakUrl: process.env.NUXT_KEYCLOAK_ISSUER ? `${process.env.NUXT_KEYCLOAK_ISSUER}/protocol/openid-connect/token` :
process.env.KEYCLOAK_ISSUER ? `${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token` :
'https://auth.rssa.top/realms/sandbox/protocol/openid-connect/token',
keycloakClientId: process.env.NUXT_KEYCLOAK_CLIENT_ID || process.env.KEYCLOAK_CLIENT_ID || 'akbar-test',
keycloakClientSecret: process.env.NUXT_KEYCLOAK_CLIENT_SECRET || process.env.KEYCLOAK_CLIENT_SECRET || 'FDyv3UYMgJOYPnvzXVVv6diRtcgEevKg',
keycloakClientUuid: process.env.KEYCLOAK_CLIENT_UUID,
keycloakAdminRealmUrl: process.env.KEYCLOAK_ADMIN_REALM_URL
},
+57 -8
View File
@@ -18,7 +18,6 @@
"apexcharts": "4.5.0",
"axios": "^1.9.0",
"axios-mock-adapter": "^2.1.0",
"better-sqlite3": "^12.6.2",
"gsap": "^3.14.2",
"jsonwebtoken": "^9.0.2",
"lodash-es": "^4.17.21",
@@ -3926,6 +3925,8 @@
"integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
@@ -3969,6 +3970,8 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
@@ -3994,6 +3997,8 @@
}
],
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
@@ -4004,6 +4009,8 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -4916,6 +4923,8 @@
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"mimic-response": "^3.1.0"
},
@@ -4931,6 +4940,8 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=4.0.0"
}
@@ -5651,6 +5662,8 @@
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"license": "(MIT OR WTFPL)",
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
@@ -6004,7 +6017,9 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/fsevents": {
"version": "2.3.3",
@@ -6168,7 +6183,9 @@
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/glob": {
"version": "10.4.5",
@@ -7471,6 +7488,8 @@
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
},
@@ -7548,7 +7567,9 @@
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/mlly": {
"version": "1.7.4",
@@ -7648,7 +7669,9 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/neo-async": {
"version": "2.6.2",
@@ -7940,6 +7963,8 @@
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz",
"integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"semver": "^7.3.5"
},
@@ -9573,6 +9598,8 @@
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
@@ -9599,6 +9626,8 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@@ -9798,6 +9827,8 @@
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"optional": true,
"peer": true,
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@@ -9812,7 +9843,9 @@
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"license": "ISC"
"license": "ISC",
"optional": true,
"peer": true
},
"node_modules/rc9": {
"version": "2.1.2",
@@ -10512,7 +10545,9 @@
"url": "https://feross.org/support"
}
],
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/simple-get": {
"version": "4.0.1",
@@ -10533,6 +10568,8 @@
}
],
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
@@ -10875,6 +10912,8 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11061,6 +11100,8 @@
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
@@ -11072,13 +11113,17 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"license": "ISC"
"license": "ISC",
"optional": true,
"peer": true
},
"node_modules/tar-fs/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -11093,6 +11138,8 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
@@ -11286,6 +11333,8 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"safe-buffer": "^5.0.1"
},
-1
View File
@@ -20,7 +20,6 @@
"apexcharts": "4.5.0",
"axios": "^1.9.0",
"axios-mock-adapter": "^2.1.0",
"better-sqlite3": "^12.6.2",
"gsap": "^3.14.2",
"jsonwebtoken": "^9.0.2",
"lodash-es": "^4.17.21",
+33
View File
@@ -0,0 +1,33 @@
// server/api/health.get.ts
// Health check endpoint for Docker and monitoring
export default defineEventHandler(async (event) => {
try {
// Basic health check
const health = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV || 'development',
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
unit: 'MB'
}
};
return {
success: true,
...health
};
} catch (error: any) {
// If health check fails, return 500
setResponseStatus(event, 500);
return {
success: false,
status: 'unhealthy',
error: error.message,
timestamp: new Date().toISOString()
};
}
});