From d7252f1d213d58702c85ab87354efdd18c67ad84 Mon Sep 17 00:00:00 2001 From: Shayan Azadi Date: Wed, 1 Jul 2026 00:32:25 +0330 Subject: [PATCH] Add Docker support with multi-stage Vite build and nginx serving Co-authored-by: Cursor --- .dockerignore | 13 +++++++++++++ Dockerfile | 31 +++++++++++++++++++++++++++++++ README.md | 16 ++++++++++++++++ docker-compose.yml | 18 ++++++++++++++++++ nginx.conf | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..db05ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +node_modules +dist +dist-ssr +*.local +.env +.env.* +!.env.example +npm-debug.log* +.git +.gitignore +README.md +tsconfig.tsbuildinfo +tsconfig.node.tsbuildinfo diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e85d3f4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# FunZone Accounting Frontend Dockerfile +FROM node:18-alpine AS build + +WORKDIR /app + +ARG VITE_API_BASE_URL=http://localhost:8001/api +ARG VITE_ACCOUNTING_BASE_URL=http://localhost:8010/api +ARG VITE_BASE_PATH=/ +ENV VITE_API_BASE_URL=$VITE_API_BASE_URL +ENV VITE_ACCOUNTING_BASE_URL=$VITE_ACCOUNTING_BASE_URL +ENV VITE_BASE_PATH=$VITE_BASE_PATH + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM nginx:alpine + +RUN apk add --no-cache curl + +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost/health || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 73d800a..5579aac 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,22 @@ npm run preview # پیش‌نمایش بیلد روی پورت 5176 npm run lint # بررسی نوع‌ها (type-check) ``` +## Docker + +```bash +docker compose up -d --build +``` + +The container serves the production build on **http://localhost:3006**. + +Build-time API URLs (FunZone backend + accounting service): + +```bash +VITE_API_BASE_URL=http://localhost:8001/api \ +VITE_ACCOUNTING_BASE_URL=http://localhost:8010/api \ +docker compose up -d --build +``` + ## معماری - `src/types` — مدل‌های دامنه با تایپ قوی diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..887e589 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +services: + accounting-frontend: + build: + context: . + dockerfile: Dockerfile + args: + VITE_API_BASE_URL: ${VITE_API_BASE_URL:-http://localhost:8001/api} + VITE_ACCOUNTING_BASE_URL: ${VITE_ACCOUNTING_BASE_URL:-http://localhost:8010/api} + VITE_BASE_PATH: ${VITE_BASE_PATH:-/} + container_name: funzone_accounting_frontend + ports: + - "127.0.0.1:3006:80" + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/health"] + interval: 30s + timeout: 10s + retries: 3 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..318499a --- /dev/null +++ b/nginx.conf @@ -0,0 +1,40 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied expired no-cache no-store private auth; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/xml+rss + application/json; + + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; + + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +}