From 5511ed5d91a78e31969a4846dadb2afe059158c3 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Wed, 20 May 2026 10:10:11 +0330 Subject: [PATCH] feat(frontend): migrate frontend service to Next.js --- .gitignore | 3 ++ README.md | 4 ++- certs/fullchain.example.pem | 64 ------------------------------------ certs/privateKey.examole.pem | 52 ----------------------------- docker-compose.yml | 4 ++- frontend/Dockerfile | 34 +++++++++++-------- 6 files changed, 29 insertions(+), 132 deletions(-) delete mode 100644 certs/fullchain.example.pem delete mode 100644 certs/privateKey.examole.pem diff --git a/.gitignore b/.gitignore index 44b143b..5edce2a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ data/ certs/fullchain.pem certs/privateKey.pem .vscode/ + +backend/guilan-ace-backend +frontend/guilan-ace-frontend diff --git a/README.md b/README.md index 952caed..6048c47 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,11 @@ parent-directory/ 3. On the deployment server, place the backend repo at `guilan-ace-deployment/backend/guilan-ace-backend`. 4. On the deployment server, place the frontend repo at `guilan-ace-deployment/frontend/guilan-ace-frontend`. 5. Create `backend/guilan-ace-backend/.env` from the backend repo sample. -6. Run `docker compose up -d --build`. +6. Create `frontend/guilan-ace-frontend/.env` from the frontend repo sample. +7. Run `docker compose up -d --build`. ## Notes - Traefik terminates TLS and routes frontend, API, admin, static, media, Grafana, Prometheus, and Uptime Kuma. +- The frontend is a Next.js standalone Node runtime behind Traefik on internal port `3000`. - Alertmanager has been removed from this stack. Prometheus scraping and Grafana provisioning remain intact. - Dockerfiles live only in this deployment repository, and compose is intentionally wired only for the nested production layout. diff --git a/certs/fullchain.example.pem b/certs/fullchain.example.pem deleted file mode 100644 index 90fa9fb..0000000 --- a/certs/fullchain.example.pem +++ /dev/null @@ -1,64 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGEzCCBPugAwIBAgISBZf+U3m3Aftq6nyZTh1KZD6tMA0GCSqGSIb3DQEBCwUA -MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD -EwNSMTIwHhcNMjYwNTE4MTQyOTI0WhcNMjYwODE2MTQyOTIzWjAeMRwwGgYDVQQD -DBMqLmVhc3QtZ3VpbGFuLWNlLmlyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAx0eyNPO1YVzOZGiC19l5IEedFeMe1Yf2T1srJUr9MSpDKKiE8n3AY0Jq -9WgUou9E8ZViu3cYjE8UEuP6s4W+U1iXYWMwqc6hAkSejn8mb4vSdIO1dVEW9BNM -spDgXZvbwSs6UWm+sUpxwot4hV9RlzIdSoZ4nrLRJnu7OSW/fO7xU8UNPAgPHarH -e/xBPPTeYKq+CcDb7HJUdJMYxDd1oRtZQm/Uz5rDrqf0R4DxAhUBcZXgp8zn4yH1 -nPjIR+2XUCB2n4QlOfNqhiPa9JwD6ZVrUImaFBdDTZjenE/HHVJ94k1LzMTGgHRv -Cp/avx5fw4lYlY8J72eKKFK77fHQpUUk7F7klZ+CHDlrLi+RDyqiJezhVJlPuXXn -ivEWvrrVN0EZ+1pO+Xn1xqBDjJ2KP+VbGzSveGgxsO5XHy2BaGumYx7nQwhqynXk -BMKC5PCufu8zfvsd2ODSGUvIhihgsXbFRaWEWOQiLqFq3z/4GORnn09DvBqnIsKQ -LGI4xDrnb/JYmkCs5zxLey1kDWOtqRjzZ/aVzSUM8h1UOmofXKPGg/ucM1SMEqe5 -qLyifgYsxZ/OUnrx6OZt1xW4eROGxovyehscaCIIMeIAhKZ4oiJhWfZ4mgb9teiF -RylJST+YXqN9/DydVe6AyIUInKAQZL5PsY36B/QK6Fckb2GnOK8CAwEAAaOCAjQw -ggIwMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMB -Af8EAjAAMB0GA1UdDgQWBBTU6TZIKc65xcaDLlCRk8padrq7yjAfBgNVHSMEGDAW -gBQAtSnyLY5vMeibTK14Pvrc6QzR0jAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUH -MAKGF2h0dHA6Ly9yMTIuaS5sZW5jci5vcmcvMDEGA1UdEQQqMCiCEyouZWFzdC1n -dWlsYW4tY2UuaXKCEWVhc3QtZ3VpbGFuLWNlLmlyMBMGA1UdIAQMMAowCAYGZ4EM -AQIBMC4GA1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly9yMTIuYy5sZW5jci5vcmcvNDYu -Y3JsMIIBDAYKKwYBBAHWeQIEAgSB/QSB+gD4AHcAwjF+V0UZo0XufzjespBB68fC -IVoiv3/Vta12mtkOUs0AAAGeO7NpVgAABAMASDBGAiEAmxz+oc1QeAR1J/yEe1jZ -W2hT/U3XF+5q63O+kRjQWO0CIQCGI+xwY/hhPjJr9HkPRTI5NXGt9EeVe0vMAu1s -+TMtxgB9ABqLnWsP/r+BtHk5xtIxCobW0QLU8EbiGCyd419eJiXvAAABnjuza0wA -CAAABQAUIto1BAMARjBEAiAPAyeQN4zkD/vUAAqo/8sF5uKicaul9fS9y0bUv+8d -hgIgQxClI5FycnYL6GTwBxpNWS0uWbDhoTAtj+Mw6NOGOD8wDQYJKoZIhvcNAQEL -BQADggEBAHt+R9Da16AbLPZqC5BelK6prKdmeaqkDIDO6aE1aZyuS0xxK228fPAr -zcopyWI4Onm29bAYxaeFtUwZurDyqb+jHf0AD8PC2zOFxQCvDyEO9l28yQ51hSR2 -6KlTNfsUaBAdZctSseZI1wcqJ3cwZLGAJjrTXaMDDDc83UeG/bJ8syU+iGlUhhWu -e/hEFTtIQ14U6lvNLwgtsC3Ptwe5gGIauJ+wtTIkavulGrWpGLgEUQPqNFz/NmwM -+Nis+oB2qKMJfQBoQgNIVFahsnOvUTJZbx3nEKQfI/OAGQHH2fr6xpg09zbi0j/5 -Y8q58R3hzVyBdJHytdcI5W/pEJmYzSE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFBjCCAu6gAwIBAgIRAMISMktwqbSRcdxA9+KFJjwwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw -WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDEMMAoGA1UEAxMDUjEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2pgodK2+lP474B7i5Ut1qywSf+2nAzJ+Npfs6DGPpRONC5kuHs0BUT1M -5ShuCVUxqqUiXXL0LQfCTUA83wEjuXg39RplMjTmhnGdBO+ECFu9AhqZ66YBAJpz -kG2Pogeg0JfT2kVhgTU9FPnEwF9q3AuWGrCf4yrqvSrWmMebcas7dA8827JgvlpL -Thjp2ypzXIlhZZ7+7Tymy05v5J75AEaz/xlNKmOzjmbGGIVwx1Blbzt05UiDDwhY -XS0jnV6j/ujbAKHS9OMZTfLuevYnnuXNnC2i8n+cF63vEzc50bTILEHWhsDp7CH4 -WRt/uTp8n1wBnWIEwii9Cq08yhDsGwIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB -/wIBADAdBgNVHQ4EFgQUALUp8i2ObzHom0yteD763OkM0dIwHwYDVR0jBBgwFoAU -ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC -hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG -A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN -AQELBQADggIBAI910AnPanZIZTKS3rVEyIV29BWEjAK/duuz8eL5boSoVpHhkkv3 -4eoAeEiPdZLj5EZ7G2ArIK+gzhTlRQ1q4FKGpPPaFBSpqV/xbUb5UlAXQOnkHn3m -FVj+qYv87/WeY+Bm4sN3Ox8BhyaU7UAQ3LeZ7N1X01xxQe4wIAAE3JVLUCiHmZL+ -qoCUtgYIFPgcg350QMUIWgxPXNGEncT921ne7nluI02V8pLUmClqXOsCwULw+PVO -ZCB7qOMxxMBoCUeL2Ll4oMpOSr5pJCpLN3tRA2s6P1KLs9TSrVhOk+7LX28NMUlI -usQ/nxLJID0RhAeFtPjyOCOscQBA53+NRjSCak7P4A5jX7ppmkcJECL+S0i3kXVU -y5Me5BbrU8973jZNv/ax6+ZK6TM8jWmimL6of6OrX7ZU6E2WqazzsFrLG3o2kySb -zlhSgJ81Cl4tv3SbYiYXnJExKQvzf83DYotox3f0fwv7xln1A2ZLplCb0O+l/AK0 -YE0DS2FPxSAHi0iwMfW2nNHJrXcY3LLHD77gRgje4Eveubi2xxa+Nmk/hmhLdIET -iVDFanoCrMVIpQ59XWHkzdFmoHXHBV7oibVjGSO7ULSQ7MJ1Nz51phuDJSgAIU7A -0zrLnOrAj/dfrlEWRhCvAgbuwLZX1A2sjNjXoPOHbsPiy+lO1KF8/XY7 ------END CERTIFICATE----- diff --git a/certs/privateKey.examole.pem b/certs/privateKey.examole.pem deleted file mode 100644 index 326a49c..0000000 --- a/certs/privateKey.examole.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -Fsu0vT7dhy5GJP6Qmrt7ogjJ9K4grQ== ------END PRIVATE KEY----- diff --git a/docker-compose.yml b/docker-compose.yml index 253c6ff..fa0398e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -130,12 +130,14 @@ services: build: context: ./frontend/guilan-ace-frontend dockerfile: ./frontend/Dockerfile + env_file: + - ./frontend/guilan-ace-frontend/.env labels: - traefik.enable=true - traefik.http.routers.frontend.rule=Host(`${NEXT_HOST}`) - traefik.http.routers.frontend.entrypoints=websecure - traefik.http.routers.frontend.tls.certresolver=le - - traefik.http.services.frontend.loadbalancer.server.port=80 + - traefik.http.services.frontend.loadbalancer.server.port=3000 static: image: nginx:1.27-alpine diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 7aa53d0..8f45a04 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,30 +1,36 @@ -FROM node:20-alpine AS builder +FROM node:20-alpine AS deps WORKDIR /app RUN npm config set registry https://package-mirror.liara.ir/repository/npm/ --global -# Copy package files COPY package*.json ./ -# Install dependencies -RUN npm install +RUN npm ci -# Copy source code +FROM node:20-alpine AS builder + +WORKDIR /app + +ENV NODE_ENV=production + +COPY --from=deps /app/node_modules ./node_modules COPY . . -# Build the application RUN npm run build -# Production image -FROM nginx:alpine +FROM node:20-alpine AS runner -# Copy built files to nginx -COPY --from=builder /app/dist /usr/share/nginx/html +WORKDIR /app -# Copy nginx configuration -COPY nginx.conf /etc/nginx/conf.d/default.conf +ENV NODE_ENV=production +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 -EXPOSE 80 +COPY --from=builder /app/public ./public +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static -CMD ["nginx", "-g", "daemon off;"] +EXPOSE 3000 + +CMD ["node", "server.js"]