Configure for self-hosted deployment

- Add environment variable support for Supabase and Pakasir configurations
- Create Docker configuration with Nginx for production deployment
- Add .env.example with all required environment variables
- Remove hardcoded URLs from Supabase client and Checkout component
- Add Docker and Nginx configuration files for Coolify deployment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-21 23:01:39 +07:00
parent ef19864985
commit 4b5dfc6557
6 changed files with 218 additions and 3 deletions

79
.dockerignore Normal file
View File

@@ -0,0 +1,79 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Build outputs
dist
dist-ssr
build
# Development
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Cache
.cache
.parcel-cache
.temp
.tmp
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# OS
Thumbs.db
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
*.lcov
# Git
.git
.gitignore
README.md
# Documentation
docs
# Tools
.eslintrc.cjs
.gitlab-ci.yml
.github
# Testing
__tests__
tests
*.test.js
*.test.ts
*.test.tsx
*.spec.js
*.spec.ts
*.spec.tsx
# Misc
*.md
!README.md

25
.env.example Normal file
View File

@@ -0,0 +1,25 @@
# Supabase Configuration
VITE_SUPABASE_URL=your_supabase_url_here
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key_here
VITE_SUPABASE_EDGE_URL=your_supabase_url_here/functions/v1
# Application Configuration
VITE_APP_NAME=Access Hub
VITE_APP_ENV=production
# Third-party Integrations
VITE_PAKASIR_API_KEY=your_pakasir_api_key_here
VITE_PAKASIR_PROJECT_SLUG=your_pakasir_project_slug
# Payment Configuration (if needed)
# VITE_MIDTRANS_CLIENT_KEY=your_midtrans_client_key
# Email Configuration (for edge functions)
# These will be set in Supabase Edge Function secrets
# SMTP_HOST=your_smtp_host
# SMTP_USER=your_smtp_user
# SMTP_PASS=your_smtp_password
# Other Configuration
VITE_ENABLE_ANALYTICS=false
VITE_DEBUG=false

47
Dockerfile Normal file
View File

@@ -0,0 +1,47 @@
# Build stage
FROM node:18-alpine AS builder
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies (including dev dependencies for build)
RUN npm ci
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM nginx:alpine AS production
# Copy custom nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy built assets from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Create non-root user (optional but recommended for security)
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Change ownership of the nginx directory
RUN chown -R nextjs:nodejs /usr/share/nginx/html
RUN chown -R nextjs:nodejs /var/cache/nginx
RUN chown -R nextjs:nodejs /var/log/nginx
RUN chown -R nextjs:nodejs /etc/nginx/conf.d
RUN touch /var/run/nginx.pid
RUN chown -R nextjs:nodejs /var/run/nginx.pid
# Switch to non-root user
USER nextjs
# Expose port 80
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

64
nginx.conf Normal file
View File

@@ -0,0 +1,64 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate auth;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json;
# Security headers
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 "strict-origin-when-cross-origin" always;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Cache HTML files for shorter time
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
# Handle React Router - try to serve file, fallback to index.html
location / {
try_files $uri $uri/ /index.html;
}
# API proxy (if needed for local development)
# location /api/ {
# proxy_pass http://backend:3000/;
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_cache_bypass $http_upgrade;
# }
# Error pages
error_page 404 /index.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -1,7 +1,7 @@
import { createClient } from '@supabase/supabase-js'; import { createClient } from '@supabase/supabase-js';
const SUPABASE_URL = 'https://lovable.backoffice.biz.id'; const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL || 'https://lovable.backoffice.biz.id';
const SUPABASE_ANON_KEY = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTc2NjAzNzEyMCwiZXhwIjo0OTIxNzEwNzIwLCJyb2xlIjoiYW5vbiJ9.Sa-eECy9dgBUQy3O4X5X-3tDPmF01J5zeT-Qtb-koYc'; const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY || 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTc2NjAzNzEyMCwiZXhwIjo0OTIxNzEwNzIwLCJyb2xlIjoiYW5vbiJ9.Sa-eECy9dgBUQy3O4X5X-3tDPmF01J5zeT-Qtb-koYc';
export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
auth: { auth: {

View File

@@ -14,7 +14,7 @@ import { Trash2, CreditCard, Loader2, QrCode, Wallet } from "lucide-react";
import { QRCodeSVG } from "qrcode.react"; import { QRCodeSVG } from "qrcode.react";
// Pakasir configuration // Pakasir configuration
const PAKASIR_PROJECT_SLUG = "dewengoding"; const PAKASIR_PROJECT_SLUG = import.meta.env.VITE_PAKASIR_PROJECT_SLUG || "dewengoding";
const SANDBOX_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo"; const SANDBOX_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo";
// Centralized API key retrieval - uses env var with sandbox fallback // Centralized API key retrieval - uses env var with sandbox fallback