Files
Mahi 80566bf0a2 feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation
Complete implementation of the Goa Government e-Licensing platform with:

Backend:
- NestJS API with JWT authentication
- PostgreSQL database with Knex ORM
- Redis caching and session management
- MinIO document storage
- Hyperledger Besu blockchain integration
- Multi-department workflow system
- Comprehensive API tests (266/282 passing)

Frontend:
- Angular 21 with standalone components
- Angular Material + TailwindCSS UI
- Visual workflow builder
- Document upload with progress tracking
- Blockchain explorer integration
- Role-based dashboards (Admin, Department, Citizen)
- E2E tests with Playwright (37 tests)

Infrastructure:
- Docker Compose orchestration
- Blockscout blockchain explorer
- Development and production configurations
2026-02-07 10:23:29 -04:00

9.6 KiB

🚀 Deployment Guide - Goa-GEL Documentation Service

Complete guide to deploy the documentation service in various environments.


📋 Prerequisites

  • Docker 20.10+ or Docker Desktop
  • Docker Compose 1.29+ (if using compose)
  • Port 8080 available (or configure different port)

Quick Deploy

# From the Documentation directory
docker build -t goa-gel-docs .
docker run -d -p 8080:80 --name goa-gel-docs goa-gel-docs

# Verify it's running
docker ps | grep goa-gel-docs

# Access the documentation
open http://localhost:8080

Docker Compose Deploy

# Start the service
docker-compose up -d

# Check logs
docker-compose logs -f documentation

# Stop the service
docker-compose down

🌐 Production Deployment

1. Build Production Image

# Build with version tag
docker build -t goa-gel-docs:1.0.0 .

# Tag for production registry
docker tag goa-gel-docs:1.0.0 your-registry.com/goa-gel-docs:1.0.0
docker tag goa-gel-docs:1.0.0 your-registry.com/goa-gel-docs:latest

# Push to registry
docker push your-registry.com/goa-gel-docs:1.0.0
docker push your-registry.com/goa-gel-docs:latest

2. Deploy to Server

# Pull image on production server
docker pull your-registry.com/goa-gel-docs:1.0.0

# Run with production settings
docker run -d \
  --name goa-gel-docs \
  -p 8080:80 \
  --restart always \
  --memory="256m" \
  --cpus="0.5" \
  -l "service=documentation" \
  your-registry.com/goa-gel-docs:1.0.0

3. Health Check

# Check if service is healthy
curl http://localhost:8080

# Expected output: HTML of homepage

# Check Docker health status
docker inspect --format='{{.State.Health.Status}}' goa-gel-docs
# Expected: healthy

☸️ Kubernetes Deployment

Create Kubernetes Manifests

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goa-gel-docs
  namespace: goa-gel
spec:
  replicas: 2
  selector:
    matchLabels:
      app: goa-gel-docs
  template:
    metadata:
      labels:
        app: goa-gel-docs
    spec:
      containers:
      - name: goa-gel-docs
        image: your-registry.com/goa-gel-docs:1.0.0
        ports:
        - containerPort: 80
        resources:
          limits:
            memory: "256Mi"
            cpu: "500m"
          requests:
            memory: "128Mi"
            cpu: "250m"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 5

service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: goa-gel-docs
  namespace: goa-gel
spec:
  selector:
    app: goa-gel-docs
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  type: ClusterIP

ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: goa-gel-docs
  namespace: goa-gel
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - docs.goa-gel.gov.in
    secretName: goa-gel-docs-tls
  rules:
  - host: docs.goa-gel.gov.in
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: goa-gel-docs
            port:
              number: 80

Deploy to Kubernetes

# Create namespace
kubectl create namespace goa-gel

# Apply manifests
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

# Check deployment
kubectl get pods -n goa-gel
kubectl get svc -n goa-gel
kubectl get ingress -n goa-gel

# Check logs
kubectl logs -f deployment/goa-gel-docs -n goa-gel

🔒 HTTPS/SSL Setup

Option 1: Let's Encrypt (Certbot)

# Install certbot
sudo apt-get install certbot python3-certbot-nginx

# Get certificate
sudo certbot --nginx -d docs.goa-gel.gov.in

# Auto-renewal is configured automatically
# Test renewal
sudo certbot renew --dry-run

Option 2: Custom Certificate

# Add to nginx.conf
server {
    listen 443 ssl http2;
    server_name docs.goa-gel.gov.in;

    ssl_certificate /etc/ssl/certs/goa-gel-docs.crt;
    ssl_certificate_key /etc/ssl/private/goa-gel-docs.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # ... rest of config
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name docs.goa-gel.gov.in;
    return 301 https://$server_name$request_uri;
}

🔄 Reverse Proxy Setup

Nginx Reverse Proxy

# /etc/nginx/sites-available/goa-gel-docs

upstream docs_backend {
    server localhost:8080;
}

server {
    listen 80;
    server_name docs.goa-gel.gov.in;

    location / {
        proxy_pass http://docs_backend;
        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;
    }
}
# Enable site
sudo ln -s /etc/nginx/sites-available/goa-gel-docs /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Apache Reverse Proxy

# /etc/apache2/sites-available/goa-gel-docs.conf

<VirtualHost *:80>
    ServerName docs.goa-gel.gov.in

    ProxyPreserveHost On
    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/

    ErrorLog ${APACHE_LOG_DIR}/goa-gel-docs-error.log
    CustomLog ${APACHE_LOG_DIR}/goa-gel-docs-access.log combined
</VirtualHost>
# Enable modules and site
sudo a2enmod proxy proxy_http
sudo a2ensite goa-gel-docs
sudo systemctl reload apache2

📊 Monitoring

Health Check Endpoint

# Check if service is running
curl -f http://localhost:8080/ || echo "Service down"

# Check response time
time curl -s http://localhost:8080/ > /dev/null

Docker Stats

# Monitor resource usage
docker stats goa-gel-docs

# Expected:
# CPU: < 1% idle, < 10% under load
# Memory: ~20-50MB

Logs

# View logs
docker logs -f goa-gel-docs

# Last 100 lines
docker logs --tail 100 goa-gel-docs

# Logs since timestamp
docker logs --since 2024-01-01T00:00:00 goa-gel-docs

🔧 Troubleshooting

Service Won't Start

# Check if port is in use
lsof -i :8080

# Check Docker logs
docker logs goa-gel-docs

# Try different port
docker run -d -p 9090:80 --name goa-gel-docs goa-gel-docs

High Memory Usage

# Set memory limit
docker update --memory="256m" goa-gel-docs

# Or recreate with limit
docker stop goa-gel-docs
docker rm goa-gel-docs
docker run -d \
  -p 8080:80 \
  --memory="256m" \
  --name goa-gel-docs \
  goa-gel-docs

Slow Performance

# Check resource usage
docker stats goa-gel-docs

# Increase CPU allocation
docker update --cpus="1.0" goa-gel-docs

# Enable gzip compression (already enabled in nginx.conf)
# Check if compression is working
curl -H "Accept-Encoding: gzip" -I http://localhost:8080/
# Should see: Content-Encoding: gzip

🔄 Updates

Update Documentation Content

# Update markdown files in docs/
# Then rebuild and redeploy

docker build -t goa-gel-docs:1.0.1 .
docker stop goa-gel-docs
docker rm goa-gel-docs
docker run -d -p 8080:80 --name goa-gel-docs goa-gel-docs:1.0.1

Zero-Downtime Update (with 2+ instances)

# Build new version
docker build -t goa-gel-docs:1.0.1 .

# Start new container on different port
docker run -d -p 8081:80 --name goa-gel-docs-new goa-gel-docs:1.0.1

# Test new version
curl http://localhost:8081/

# Update load balancer to point to 8081
# Then stop old container
docker stop goa-gel-docs
docker rm goa-gel-docs

# Rename new container
docker rename goa-gel-docs-new goa-gel-docs

🔐 Security Best Practices

1. Run as Non-Root User

Update Dockerfile:

# Add after FROM nginx:alpine
RUN adduser -D -u 1000 docsuser
USER docsuser

2. Read-Only Filesystem

docker run -d \
  -p 8080:80 \
  --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  --tmpfs /var/cache/nginx \
  --name goa-gel-docs \
  goa-gel-docs

3. Network Isolation

# Create isolated network
docker network create goa-gel-network

# Run with network
docker run -d \
  -p 8080:80 \
  --network goa-gel-network \
  --name goa-gel-docs \
  goa-gel-docs

4. Security Scanning

# Scan image for vulnerabilities
docker scan goa-gel-docs

# Or use Trivy
trivy image goa-gel-docs

📈 Performance Optimization

CDN Setup

Use a CDN like Cloudflare for static assets:

  1. Point domain to Cloudflare
  2. Enable caching for:
    • /css/*
    • /js/*
    • /docs/*
  3. Enable Brotli compression
  4. Enable HTTP/3

Caching Headers

Already configured in nginx.conf:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

🧪 Testing Deployment

# 1. Test homepage
curl -I http://localhost:8080/
# Expected: 200 OK

# 2. Test viewer
curl -I http://localhost:8080/viewer.html
# Expected: 200 OK

# 3. Test documentation
curl http://localhost:8080/docs/USER_GUIDE.md
# Expected: Markdown content

# 4. Test 404 handling
curl -I http://localhost:8080/nonexistent
# Expected: 404 Not Found

# 5. Load test (requires Apache Bench)
ab -n 1000 -c 10 http://localhost:8080/
# Should handle 1000 requests easily

📞 Support

For deployment issues:

  • Email: devops@goa.gov.in
  • Documentation: README.md in this directory
  • Source: GitHub repository

Version: 1.0.0 Last Updated: February 2026