deploy: hr-portal
This commit is contained in:
+19
-7
@@ -2,26 +2,37 @@
|
||||
FROM node:20-alpine AS backend-builder
|
||||
WORKDIR /app/backend
|
||||
COPY backend/package*.json ./
|
||||
RUN npm ci --legacy-peer-deps
|
||||
# Use inline NODE_ENV=development so devDeps (nest CLI) are installed
|
||||
# but the global NODE_ENV stays production for the actual build
|
||||
RUN NODE_ENV=development npm ci --legacy-peer-deps --include=dev
|
||||
COPY backend/ .
|
||||
RUN npm run build
|
||||
RUN ./node_modules/.bin/nest build
|
||||
|
||||
# Stage 2: Build frontend
|
||||
FROM node:20-alpine AS frontend-builder
|
||||
WORKDIR /app/frontend
|
||||
COPY frontend/package*.json ./
|
||||
RUN npm ci --legacy-peer-deps
|
||||
RUN NODE_ENV=development npm ci --legacy-peer-deps --include=dev
|
||||
COPY frontend/ .
|
||||
ENV NEXT_PUBLIC_API_URL=/api-backend
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
RUN npm run build
|
||||
|
||||
# Stage 3: Runtime
|
||||
FROM node:20-alpine AS runner
|
||||
FROM node:20-bookworm-slim AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Install nginx
|
||||
RUN apk add --no-cache nginx
|
||||
# Install nginx and MongoDB
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
nginx \
|
||||
gnupg \
|
||||
curl \
|
||||
&& curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor \
|
||||
&& echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/7.0 main" > /etc/apt/sources.list.d/mongodb-org-7.0.list \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends mongodb-org \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /data/db /run/nginx
|
||||
|
||||
# Copy backend build
|
||||
COPY --from=backend-builder /app/backend/dist ./backend/dist
|
||||
@@ -31,7 +42,8 @@ COPY --from=backend-builder /app/backend/package.json ./backend/
|
||||
# Copy frontend build (standalone mode)
|
||||
COPY --from=frontend-builder /app/frontend/.next/standalone ./frontend/
|
||||
COPY --from=frontend-builder /app/frontend/.next/static ./frontend/.next/static
|
||||
COPY --from=frontend-builder /app/frontend/public ./frontend/public
|
||||
# public dir may be empty — copy if exists
|
||||
COPY --from=frontend-builder /app/frontend/public/ ./frontend/public/
|
||||
|
||||
# Nginx config
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
Generated
+7780
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { announcementsApi } from '@/lib/api';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { attendanceApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { leavesApi, attendanceApi, reimbursementsApi, announcementsApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { leavesApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { payrollApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { employeesApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { reimbursementsApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
import { taxApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { announcementsApi, departmentsApi } from '@/lib/api';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { attendanceApi, employeesApi } from '@/lib/api';
|
||||
import { getDaysInMonth, monthNames, getStatusColor } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { employeesApi, leavesApi, reimbursementsApi, reportsApi } from '@/lib/api';
|
||||
import { formatCurrency, formatDate, getStatusColor } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { employeesApi, departmentsApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { employeesApi, departmentsApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { employeesApi, departmentsApi } from '@/lib/api';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { leavesApi } from '@/lib/api';
|
||||
import { formatDate, getStatusColor } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { payrollApi } from '@/lib/api';
|
||||
import { formatCurrency, monthNames } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { reimbursementsApi } from '@/lib/api';
|
||||
import { formatDate, formatCurrency, getStatusColor } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { reportsApi } from '@/lib/api';
|
||||
import { formatCurrency, monthNames } from '@/lib/utils';
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Inter } from 'next/font/google';
|
||||
import './globals.css';
|
||||
import { AuthProvider } from '@/lib/auth-context';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useState } from 'react';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { adminApi, departmentsApi } from '@/lib/api';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { adminApi } from '@/lib/api';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { adminApi, employeesApi } from '@/lib/api';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth-context';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { adminApi } from '@/lib/api';
|
||||
import Topbar from '@/components/layout/Topbar';
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
Generated
+1915
File diff suppressed because it is too large
Load Diff
+10
-4
@@ -1,14 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Create nginx pid directory
|
||||
mkdir -p /run/nginx
|
||||
# Create required directories
|
||||
mkdir -p /run/nginx /data/db
|
||||
|
||||
# Start MongoDB
|
||||
echo "Starting MongoDB..."
|
||||
mongod --dbpath /data/db --logpath /var/log/mongod.log --fork --bind_ip 127.0.0.1
|
||||
echo "Waiting for MongoDB to be ready..."
|
||||
sleep 3
|
||||
|
||||
# Start backend (NestJS)
|
||||
echo "Starting backend on port 3001..."
|
||||
cd /app/backend && NODE_ENV=production node dist/main.js &
|
||||
cd /app/backend && MONGODB_URI=mongodb://127.0.0.1:27017/hr_portal NODE_ENV=production node dist/main.js &
|
||||
|
||||
# Give backend a moment to start
|
||||
sleep 2
|
||||
sleep 3
|
||||
|
||||
# Start frontend (Next.js standalone)
|
||||
echo "Starting frontend on port 3000..."
|
||||
|
||||
Reference in New Issue
Block a user