diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f8b438e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +Dockerfile +docker-compose.yml +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git +.gitignore +.env*.local +.env.development diff --git a/.env.prod b/.env.prod new file mode 100644 index 0000000..3c7c3ab --- /dev/null +++ b/.env.prod @@ -0,0 +1,3 @@ +PORT=3000 +NODE_ENV=production +NEXT_TELEMETRY_DISABLED=1 diff --git a/.gitignore b/.gitignore index dfb192b..67f3f55 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +!.env.prod # vercel .vercel diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..34ef2fa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# syntax=docker/dockerfile:1.7 + +# ────────────────────────────────────────────────────────────────────────── +# مرحلهٔ ۱ — deps: آماده‌سازی وابستگی‌ها با کش npm +# ────────────────────────────────────────────────────────────────────────── +FROM node:22-alpine AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +COPY package.json package-lock.json* ./ +RUN --mount=type=cache,target=/root/.npm npm ci --prefer-offline --no-audit --fund=false + +# ────────────────────────────────────────────────────────────────────────── +# مرحلهٔ ۲ — builder: ساخت خروجی بهینه‌شده standalone برای Next.js +# ────────────────────────────────────────────────────────────────────────── +FROM node:22-alpine AS builder +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NODE_ENV=production + +RUN npm run build + +# ────────────────────────────────────────────────────────────────────────── +# مرحلهٔ ۳ — runner: سرور مینیمال، سبک و امن standalone در محیط پروداکشن +# ────────────────────────────────────────────────────────────────────────── +FROM node:22-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +# ایجاد کاربر غیر روت برای امنیت کانتینر +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +# هلث‌چک کانتینر +HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ + CMD wget -qO- http://127.0.0.1:3000/ || exit 1 + +CMD ["node", "server.js"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..9f1d030 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,52 @@ +pipeline { + environment { + develop_server_ip = '' + develop_server_name = '' + production_server_ip = "88.99.212.243" + production_server_name = "newhorizon_germany_001_server" + project_path = "/projects/teamby/teamby_landing" + version = "master" + gitBranch = "origin/master" + } + agent any + stages { + stage('deploy') { + steps { + script { + if (gitBranch == "origin/master") { + try { + withCredentials([usernamePassword(credentialsId: production_server_name, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + sh 'sshpass -p $PASSWORD ssh -p 1782 $USERNAME@$production_server_ip -o StrictHostKeyChecking=no "cd $project_path && ./runner.sh"' + } + } catch (Exception e) { + def lastCommit = sh(script: 'git log -1 --pretty=format:"%h - %s (%an)"', returnStdout: true).trim() + sh """ + curl -s -F chat_id=-1002316394394 \ + -F message_thread_id=1629 \ + -F document=@/var/jenkins_home/jobs/${env.JOB_NAME}/builds/${env.BUILD_NUMBER}/log \ + -F caption='Project name: #${env.JOB_NAME} \ +Build status is FAILED \ +Build url: ${BUILD_URL} \ +Last Commit: ${lastCommit}' \ + https://api.telegram.org/bot7207581748:AAH1y1pW8L9K_jWlKx3Xj_xV3pZl4Zq9V1Y/sendDocument || true + """ + currentBuild.result = 'FAILURE' + throw e + } + def lastCommit = sh(script: 'git log -1 --pretty=format:"%h - %s (%an)"', returnStdout: true).trim() + sh """ + curl -s -F chat_id=-1002316394394 \ + -F message_thread_id=1629 \ + -F document=@/var/jenkins_home/jobs/${env.JOB_NAME}/builds/${env.BUILD_NUMBER}/log \ + -F caption='Project name: #${env.JOB_NAME} \ +Build status is SUCCESS \ +Build url: ${BUILD_URL} \ +Last Commit: ${lastCommit}' \ + https://api.telegram.org/bot7207581748:AAH1y1pW8L9K_jWlKx3Xj_xV3pZl4Zq9V1Y/sendDocument || true + """ + } + } + } + } + } +} diff --git a/README.md b/README.md index e215bc4..645b60b 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,4 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +# TeamBy Landing Page - Automated CI/CD Enabled diff --git a/app/apple-icon.png b/app/apple-icon.png new file mode 100644 index 0000000..65f62af Binary files /dev/null and b/app/apple-icon.png differ diff --git a/app/favicon.ico b/app/favicon.ico index 718d6fe..bc64c2a 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/icon.png b/app/icon.png new file mode 100644 index 0000000..65f62af Binary files /dev/null and b/app/icon.png differ diff --git a/app/icon.svg b/app/icon.svg new file mode 100644 index 0000000..4ebb7c4 --- /dev/null +++ b/app/icon.svg @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/layout.tsx b/app/layout.tsx index c004173..edbebdc 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -19,6 +19,13 @@ export const metadata: Metadata = { title: "TeamBy.ai - AI-Powered Management for Team Leads", description: "TeamBy unifies your work and uses AI to optimize workflows, meetings, and costs—so you can manage smarter without chasing updates.", + icons: { + icon: [ + { url: "/assets/images/logo_icon.svg", type: "image/svg+xml" }, + { url: "/favicon.ico", sizes: "any" }, + ], + apple: "/assets/images/logo_icon.png", + }, }; export default function RootLayout({ @@ -28,11 +35,9 @@ export default function RootLayout({ }>) { return ( - {children} ); } - diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9acadbc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +services: + web: + build: + context: . + dockerfile: Dockerfile + image: teamby-landing:latest + container_name: teamby_landing + restart: unless-stopped + env_file: + - .env.prod + ports: + - "8065:3000" + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + networks: + - teamby_backend_teamby + +networks: + teamby_backend_teamby: + external: true diff --git a/next.config.ts b/next.config.ts index e9ffa30..68a6c64 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", }; export default nextConfig; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..bc64c2a Binary files /dev/null and b/public/favicon.ico differ diff --git a/runner.sh b/runner.sh new file mode 100755 index 0000000..04e450b --- /dev/null +++ b/runner.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -e +git pull origin master --rebase && docker compose up -d --build