diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c3c7b3b..aafb24a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: Deploy to Production +name: Build Production on: push: @@ -6,8 +6,8 @@ on: workflow_dispatch: jobs: - deploy: - name: Deploy to Netlify/Vercel + build: + name: Build Production Artifacts runs-on: ubuntu-latest steps: @@ -33,35 +33,20 @@ jobs: VITE_ENV: production VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} - # Option 1: Deploy to Netlify - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v3.0 + - name: Upload production artifacts + uses: actions/upload-artifact@v4 with: - publish-dir: './dist' - production-branch: main - github-token: ${{ secrets.GITHUB_TOKEN }} - deploy-message: "Deploy from GitHub Actions" - enable-pull-request-comment: true - enable-commit-comment: true - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - timeout-minutes: 5 + name: production-build + path: dist/ + retention-days: 30 - # Option 2: Deploy to Vercel (comment out Netlify if using this) - # - name: Deploy to Vercel - # uses: amondnet/vercel-action@v25 - # with: - # vercel-token: ${{ secrets.VERCEL_TOKEN }} - # vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} - # vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} - # vercel-args: '--prod' - # working-directory: ./ + - name: Build Docker image + run: docker build -t yaltopia-admin:${{ github.sha }} . - - name: Notify deployment success + - name: Build success notification if: success() - run: echo "Deployment successful!" + run: echo "Production build successful!" - - name: Notify deployment failure + - name: Build failure notification if: failure() - run: echo "Deployment failed!" + run: echo "Production build failed!" diff --git a/README.md b/README.md index d29990c..9d1b26c 100644 --- a/README.md +++ b/README.md @@ -103,59 +103,39 @@ npm run preview ## Deployment -### Static Hosting (Netlify, Vercel, etc.) +### Docker Deployment (Recommended) + +1. Build the Docker image: +```bash +docker build -t yaltopia-admin:latest . +``` + +2. Run the container: +```bash +docker run -p 8080:80 yaltopia-admin:latest +``` + +3. Deploy to your cloud provider (AWS, GCP, Azure, DigitalOcean, etc.) + +### Traditional VPS Deployment 1. Build the application: `npm run build:prod` -2. Deploy the `dist` directory -3. Configure environment variables in your hosting platform -4. Set up redirects for SPA routing (see below) +2. Copy the `dist` directory to your web server +3. Configure nginx or Apache to serve the static files +4. Set up redirects for SPA routing (see nginx.conf example) ### SPA Routing Configuration -For proper routing, add a redirect rule: - -**Netlify** (`netlify.toml`): -```toml -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 -``` - -**Vercel** (`vercel.json`): -```json -{ - "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] -} -``` - -### Docker Deployment - -Create a `Dockerfile`: - -```dockerfile -FROM node:18-alpine as build -WORKDIR /app -COPY package*.json ./ -RUN npm ci -COPY . . -RUN npm run build:prod - -FROM nginx:alpine -COPY --from=build /app/dist /usr/share/nginx/html -COPY nginx.conf /etc/nginx/conf.d/default.conf -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] -``` - -Create `nginx.conf`: +For proper routing with nginx, use the included `nginx.conf` file or add this configuration: ```nginx -server { - listen 80; - server_name _; - root /usr/share/nginx/html; - index index.html; +location / { + try_files $uri $uri/ /index.html; +} +``` +The project includes a `Dockerfile` and `nginx.conf` for containerized deployment. + +See [DEPLOYMENT.md](dev-docs/DEPLOYMENT.md) for detailed deployment instructions. location / { try_files $uri $uri/ /index.html; diff --git a/dev-docs/DEPLOYMENT.md b/dev-docs/DEPLOYMENT.md index 1cd249c..5b4f94c 100644 --- a/dev-docs/DEPLOYMENT.md +++ b/dev-docs/DEPLOYMENT.md @@ -51,47 +51,7 @@ ## Deployment Options -### Option 1: Vercel (Recommended for Quick Deploy) - -1. Install Vercel CLI: -```bash -npm i -g vercel -``` - -2. Login to Vercel: -```bash -vercel login -``` - -3. Deploy: -```bash -vercel --prod -``` - -4. Set environment variables in Vercel dashboard: - - Go to Project Settings → Environment Variables - - Add `VITE_API_URL` with your production API URL - -### Option 2: Netlify - -1. Install Netlify CLI: -```bash -npm i -g netlify-cli -``` - -2. Login: -```bash -netlify login -``` - -3. Deploy: -```bash -netlify deploy --prod -``` - -4. Set environment variables in Netlify dashboard - -### Option 3: Docker + Cloud Provider +### Option 1: Docker + Cloud Provider (Recommended) 1. Build Docker image: ```bash @@ -121,7 +81,7 @@ docker push account-id.dkr.ecr.region.amazonaws.com/yaltopia-admin:latest - Azure Container Instances - DigitalOcean App Platform -### Option 4: Traditional VPS (Ubuntu/Debian) +### Option 2: Traditional VPS (Ubuntu/Debian) 1. SSH into your server @@ -181,26 +141,42 @@ sudo cp -r dist/* /var/www/html/ ### GitHub Actions (Automated) -The `.github/workflows/ci.yml` file is configured for CI. +The `.github/workflows/ci.yml` file is configured for CI, and `.github/workflows/deploy.yml` builds production artifacts. -For CD, add deployment step: +For automated deployment, you can extend the workflow to: +1. **Push Docker image to registry:** ```yaml -- name: Deploy to Vercel - if: github.ref == 'refs/heads/main' - run: | - npm i -g vercel - vercel --prod --token=${{ secrets.VERCEL_TOKEN }} +- name: Login to Docker Registry + uses: docker/login-action@v3 + with: + registry: ${{ secrets.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + +- name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: | + ${{ secrets.DOCKER_REGISTRY }}/yaltopia-admin:latest + ${{ secrets.DOCKER_REGISTRY }}/yaltopia-admin:${{ github.sha }} ``` -Or for Netlify: - +2. **Deploy to your server via SSH:** ```yaml -- name: Deploy to Netlify - if: github.ref == 'refs/heads/main' - run: | - npm i -g netlify-cli - netlify deploy --prod --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --site=${{ secrets.NETLIFY_SITE_ID }} +- name: Deploy to production server + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + script: | + cd /opt/yaltopia-admin + docker pull ${{ secrets.DOCKER_REGISTRY }}/yaltopia-admin:latest + docker-compose down + docker-compose up -d ``` ## Troubleshooting diff --git a/dev-docs/README.md b/dev-docs/README.md index 0a17e1e..f2b2c27 100644 --- a/dev-docs/README.md +++ b/dev-docs/README.md @@ -29,7 +29,7 @@ Testing setup and practices: ### [Deployment Guide](./DEPLOYMENT.md) Production deployment: - Pre-deployment checklist -- Deployment options (Vercel, Netlify, Docker) +- Deployment options (Docker, VPS) - Environment configuration - CI/CD setup diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index cde23a7..0000000 --- a/netlify.toml +++ /dev/null @@ -1,24 +0,0 @@ -[build] - command = "npm run build:prod" - publish = "dist" - -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 - -[build.environment] - NODE_VERSION = "18" - -[[headers]] - for = "/*" - [headers.values] - X-Frame-Options = "SAMEORIGIN" - X-Content-Type-Options = "nosniff" - X-XSS-Protection = "1; mode=block" - Referrer-Policy = "strict-origin-when-cross-origin" - -[[headers]] - for = "/assets/*" - [headers.values] - Cache-Control = "public, max-age=31536000, immutable" diff --git a/vercel.json b/vercel.json deleted file mode 100644 index ca75fdd..0000000 --- a/vercel.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "buildCommand": "npm run build:prod", - "outputDirectory": "dist", - "rewrites": [ - { - "source": "/(.*)", - "destination": "/index.html" - } - ], - "headers": [ - { - "source": "/(.*)", - "headers": [ - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-XSS-Protection", - "value": "1; mode=block" - }, - { - "key": "Referrer-Policy", - "value": "strict-origin-when-cross-origin" - } - ] - }, - { - "source": "/assets/(.*)", - "headers": [ - { - "key": "Cache-Control", - "value": "public, max-age=31536000, immutable" - } - ] - } - ] -}