Update health check endpoints and refine TypeScript configuration

- Changed health check endpoint from `/api/health` to `/_health` in Dockerfile and docker-compose.yml for consistency.
- Removed the now obsolete health check route file from the API.
- Updated TypeScript configuration to exclude the `.next` directory, improving build performance and clarity.
- Enhanced documentation in proxy.ts to reflect the updated health check endpoint.
This commit is contained in:
barsa 2025-12-12 16:02:21 +09:00
parent 2266167467
commit 3d56f2895f
9 changed files with 78 additions and 30 deletions

View File

@ -98,7 +98,7 @@ ENV NODE_ENV=production \
# Health check for container orchestration
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD node -e "fetch('http://localhost:3000/api/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"
CMD node -e "fetch('http://localhost:3000/_health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "apps/portal/server.js"]

View File

@ -84,10 +84,10 @@ export const config = {
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
* - api/health (health check endpoint)
* - _health (health check endpoint)
*/
{
source: "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|api/health).*)",
source: "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|_health).*)",
missing: [
{ type: "header", key: "next-router-prefetch" },
{ type: "header", key: "purpose", value: "prefetch" },

View File

@ -9,6 +9,6 @@
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules", ".next"]
}

View File

@ -23,7 +23,7 @@ docker images | grep portal
2. Name: `customer-portal`
3. Paste contents of `docker-compose.yml`
4. Scroll down to **Environment Variables**
5. Copy variables from `stack.env.example` and fill in your production values
5. Copy variables from `env.example` and fill in your production values
### 3. Generate Secrets
@ -65,11 +65,11 @@ This setup uses `network_mode: bridge` with Docker `links` to avoid the iptables
### Service URLs (internal)
| Service | Internal URL |
|----------|-------------------------|
| Backend | http://backend:4000 |
| Service | Internal URL |
| -------- | -------------------------- |
| Backend | http://backend:4000 |
| Database | postgresql://database:5432 |
| Redis | redis://cache:6379 |
| Redis | redis://cache:6379 |
### Nginx/Plesk Proxy
@ -83,6 +83,7 @@ Configure your domain to proxy to:
## Updating the Stack
1. Load new images:
```bash
docker load < portal-frontend-latest.tar
docker load < portal-backend-latest.tar

View File

@ -25,7 +25,13 @@ services:
links:
- backend
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/api/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"]
test:
[
"CMD",
"node",
"-e",
"fetch('http://localhost:3000/_health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 10s
start_period: 40s
@ -46,36 +52,40 @@ services:
- APP_BASE_URL=${APP_BASE_URL}
- BFF_PORT=4000
- PORT=4000
# Database - use "database" as host (via links)
- DATABASE_URL=postgresql://${POSTGRES_USER:-portal}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB:-portal_prod}?schema=public
# Redis - use "cache" as host (via links)
- REDIS_URL=redis://cache:6379/0
# Security
- JWT_SECRET=${JWT_SECRET}
- JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-7d}
- JWT_SECRET_PREVIOUS=${JWT_SECRET_PREVIOUS}
- JWT_ISSUER=${JWT_ISSUER}
- JWT_AUDIENCE=${JWT_AUDIENCE}
- BCRYPT_ROUNDS=${BCRYPT_ROUNDS:-12}
- CORS_ORIGIN=${CORS_ORIGIN}
- TRUST_PROXY=true
- CSRF_SECRET_KEY=${CSRF_SECRET_KEY}
# Auth
- AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=${AUTH_ALLOW_REDIS_TOKEN_FAILOPEN:-false}
- AUTH_REQUIRE_REDIS_FOR_TOKENS=${AUTH_REQUIRE_REDIS_FOR_TOKENS:-false}
- AUTH_BLACKLIST_FAIL_CLOSED=${AUTH_BLACKLIST_FAIL_CLOSED:-false}
- AUTH_MAINTENANCE_MODE=${AUTH_MAINTENANCE_MODE:-false}
# Rate Limiting
- RATE_LIMIT_TTL=${RATE_LIMIT_TTL:-60}
- RATE_LIMIT_LIMIT=${RATE_LIMIT_LIMIT:-100}
- EXPOSE_VALIDATION_ERRORS=false
# WHMCS
- WHMCS_BASE_URL=${WHMCS_BASE_URL}
- WHMCS_API_IDENTIFIER=${WHMCS_API_IDENTIFIER}
- WHMCS_API_SECRET=${WHMCS_API_SECRET}
# Salesforce
- SF_LOGIN_URL=${SF_LOGIN_URL}
- SF_CLIENT_ID=${SF_CLIENT_ID}
@ -83,25 +93,25 @@ services:
- SF_EVENTS_ENABLED=${SF_EVENTS_ENABLED:-true}
- SF_PRIVATE_KEY_BASE64=${SF_PRIVATE_KEY_BASE64}
- SF_PRIVATE_KEY_PATH=/app/secrets/sf-private.key
# Freebit
- FREEBIT_BASE_URL=${FREEBIT_BASE_URL:-https://i1.mvno.net/emptool/api}
- FREEBIT_OEM_ID=${FREEBIT_OEM_ID:-PASI}
- FREEBIT_OEM_KEY=${FREEBIT_OEM_KEY}
# Email
- EMAIL_ENABLED=${EMAIL_ENABLED:-true}
- EMAIL_FROM=${EMAIL_FROM:-no-reply@asolutions.jp}
- EMAIL_FROM_NAME=${EMAIL_FROM_NAME:-Assist Solutions}
- SENDGRID_API_KEY=${SENDGRID_API_KEY}
# Portal
- PORTAL_PRICEBOOK_ID=${PORTAL_PRICEBOOK_ID}
- PORTAL_PRICEBOOK_NAME=${PORTAL_PRICEBOOK_NAME:-Portal}
# Logging
- LOG_LEVEL=${LOG_LEVEL:-info}
# Enable automatic database migrations on startup
- RUN_MIGRATIONS=true
restart: unless-stopped
@ -117,7 +127,13 @@ services:
# - Database migration when RUN_MIGRATIONS=true
# - Waiting for dependencies (nc checks in entrypoint)
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"]
test:
[
"CMD",
"node",
"-e",
"fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 10s
start_period: 60s
@ -151,7 +167,19 @@ services:
cache:
image: redis:7-alpine
container_name: portal-cache
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning", "--maxmemory", "256mb", "--maxmemory-policy", "noeviction"]
command:
[
"redis-server",
"--save",
"60",
"1",
"--loglevel",
"warning",
"--maxmemory",
"256mb",
"--maxmemory-policy",
"noeviction",
]
volumes:
- redis_data:/data
restart: unless-stopped

View File

@ -33,13 +33,17 @@ POSTGRES_PASSWORD=<GENERATE_WITH_openssl_rand_base64_24>
# -----------------------------------------------------------------------------
# Generate with: openssl rand -base64 32
JWT_SECRET=<GENERATE_WITH_openssl_rand_base64_32>
JWT_SECRET_PREVIOUS=
JWT_EXPIRES_IN=7d
JWT_ISSUER=customer-portal
JWT_AUDIENCE=portal
BCRYPT_ROUNDS=12
CSRF_SECRET_KEY=<GENERATE_WITH_openssl_rand_base64_32>
# Auth Settings
AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=false
AUTH_REQUIRE_REDIS_FOR_TOKENS=false
AUTH_BLACKLIST_FAIL_CLOSED=false
AUTH_MAINTENANCE_MODE=false
# Rate Limiting

View File

@ -34,6 +34,8 @@ echo ""
# Look for image files
FRONTEND_TAR="${IMAGES_DIR}/portal-frontend-${TAG}.tar"
BACKEND_TAR="${IMAGES_DIR}/portal-backend-${TAG}.tar"
FRONTEND_TARGZ="${IMAGES_DIR}/portal-frontend-${TAG}.tar.gz"
BACKEND_TARGZ="${IMAGES_DIR}/portal-backend-${TAG}.tar.gz"
# Also check alternative naming
if [[ ! -f "$FRONTEND_TAR" ]]; then
@ -43,20 +45,33 @@ if [[ ! -f "$BACKEND_TAR" ]]; then
BACKEND_TAR="${IMAGES_DIR}/portal-backend.${TAG}.tar"
fi
if [[ ! -f "$FRONTEND_TARGZ" ]]; then
FRONTEND_TARGZ="${IMAGES_DIR}/portal-frontend.${TAG}.tar.gz"
fi
if [[ ! -f "$BACKEND_TARGZ" ]]; then
BACKEND_TARGZ="${IMAGES_DIR}/portal-backend.${TAG}.tar.gz"
fi
# Load frontend
if [[ -f "$FRONTEND_TAR" ]]; then
if [[ -f "$FRONTEND_TARGZ" ]]; then
log "Loading frontend image from: $FRONTEND_TARGZ"
gunzip -c "$FRONTEND_TARGZ" | docker load
elif [[ -f "$FRONTEND_TAR" ]]; then
log "Loading frontend image from: $FRONTEND_TAR"
docker load -i "$FRONTEND_TAR"
else
warn "Frontend tarball not found: $FRONTEND_TAR"
warn "Frontend tarball not found: $FRONTEND_TAR or $FRONTEND_TARGZ"
fi
# Load backend
if [[ -f "$BACKEND_TAR" ]]; then
if [[ -f "$BACKEND_TARGZ" ]]; then
log "Loading backend image from: $BACKEND_TARGZ"
gunzip -c "$BACKEND_TARGZ" | docker load
elif [[ -f "$BACKEND_TAR" ]]; then
log "Loading backend image from: $BACKEND_TAR"
docker load -i "$BACKEND_TAR"
else
warn "Backend tarball not found: $BACKEND_TAR"
warn "Backend tarball not found: $BACKEND_TAR or $BACKEND_TARGZ"
fi
echo ""

View File

@ -16,7 +16,7 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# Default paths (override via env vars)
REPO_PATH="${REPO_PATH:-/var/www/vhosts/yourdomain.com/git/customer-portal}"
COMPOSE_FILE="${COMPOSE_FILE:-$PROJECT_ROOT/docker/portainer/docker-compose.yml}"
COMPOSE_FILE="${COMPOSE_FILE:-$PROJECT_ROOT/docker/Prod - Portainer/docker-compose.yml}"
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
# Image settings