# Deployment Guide — nexus-vector **Project**: CA Grow Ops Manager **Target**: nexus-vector (100.95.3.92) **Created**: 2025-12-08 **Job ID**: CAGROW-XXXXXX-GM (to be assigned) --- ## Overview This guide explains how to deploy CA Grow Ops Manager to **nexus-vector** following the established infrastructure patterns. --- ## Prerequisites ### On Local Machine - Git with SSH keys configured - Access to nexus-vector via Tailscale or SSH - Forgejo account with SSH key added ### On nexus-vector - Docker and Docker Compose installed ✅ - PostgreSQL 15 available (via Docker) - Redis available (via Docker) - Port 8XXX available (to be assigned) --- ## Deployment Architecture ``` ca-grow-ops-manager/ ├── backend/ # Fastify + Prisma API ├── frontend/ # Vite + React UI └── docker-compose.yml # Service orchestration Deployed to: /srv/containers/ca-grow-ops-manager/ ├── docker-compose.yml ├── docker-compose.env ├── backend/ │ ├── Dockerfile │ ├── src/ │ └── prisma/ ├── frontend/ │ ├── Dockerfile │ └── src/ └── README.md ``` --- ## Step 1: Create Forgejo Repository ### 1.1 Create Repository via API ```bash # From nexus-vector or local machine with Tailscale curl -X POST "https://git.runfoo.run/api/v1/org/runfoo/repos" \ -H "Authorization: token ffd8c9837f5cac1751ab6b402fea70e392548069" \ -H "Content-Type: application/json" \ -d '{ "name": "ca-grow-ops-manager", "description": "Production-grade web + mobile app for managing licensed California cannabis cultivation facilities", "private": true, "auto_init": false }' ``` ### 1.2 Push Local Code to Forgejo ```bash # From local machine (current directory: ca-grow-ops-manager) cd /Users/ten/ANTIGRAVITY/777wolfpack/ca-grow-ops-manager # Initialize Git if not already done git init git add . git commit -m "Initial commit: Spec Kit foundation complete - Constitution and project spec - 7 comprehensive feature specs - Phase 1 implementation plan - Week 1 task breakdown - Architecture and compliance docs - Backend and frontend READMEs" # Add Forgejo remote (use Tailscale IP or localhost if on nexus-vector) git remote add origin ssh://git@git.runfoo.run:2222/runfoo/ca-grow-ops-manager.git # Push to Forgejo git push -u origin main ``` **Note**: If SSH to git.runfoo.run:2222 is blocked, use HTTPS: ```bash git remote add origin https://git.runfoo.run/runfoo/ca-grow-ops-manager.git git push -u origin main ``` --- ## Step 2: Assign Port Number ### 2.1 Check Available Ports ```bash # SSH to nexus-vector ssh admin@nexus-vector # Check currently used ports docker ps --format "table {{.Names}}\t{{.Ports}}" | grep "8[0-9][0-9][0-9]" ``` **Current Port Assignments**: - 8000: Syncthing Exporter & Ingestion API - 8001: Location Pipeline API - 8003: Paperless-NGX - 8005: Pinwheel - 8020: Awesome MCP Servers **Assign**: **8010** for CA Grow Ops Manager --- ## Step 3: Create Service Directory ### 3.1 Create Directory Structure ```bash # On nexus-vector ssh admin@nexus-vector # Create service directory sudo mkdir -p /srv/containers/ca-grow-ops-manager sudo chown admin:admin /srv/containers/ca-grow-ops-manager cd /srv/containers/ca-grow-ops-manager ``` ### 3.2 Clone Repository ```bash # Clone from Forgejo (use localhost on nexus-vector) git clone ssh://git@localhost:2222/runfoo/ca-grow-ops-manager.git . # Or via HTTPS git clone https://git.runfoo.run/runfoo/ca-grow-ops-manager.git . ``` --- ## Step 4: Create Docker Compose Configuration ### 4.1 Create docker-compose.yml ```bash cd /srv/containers/ca-grow-ops-manager ``` Create `docker-compose.yml`: ```yaml version: '3.8' services: db: image: postgres:15-alpine environment: POSTGRES_DB: ca_grow_ops POSTGRES_USER: ca_grow_ops POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - db_data:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U ca_grow_ops"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 backend: build: context: ./backend dockerfile: Dockerfile environment: DATABASE_URL: postgresql://ca_grow_ops:${DB_PASSWORD}@db:5432/ca_grow_ops REDIS_URL: redis://redis:6379 JWT_SECRET: ${JWT_SECRET} JWT_ACCESS_EXPIRY: 15m JWT_REFRESH_EXPIRY: 7d NODE_ENV: production PORT: 3000 depends_on: db: condition: service_healthy redis: condition: service_healthy restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 40s frontend: build: context: ./frontend dockerfile: Dockerfile environment: VITE_API_URL: /api ports: - "8010:80" depends_on: - backend restart: unless-stopped volumes: db_data: ``` ### 4.2 Create Environment File Create `docker-compose.env`: ```bash # Database DB_PASSWORD=CHANGE_THIS_SECURE_PASSWORD # JWT JWT_SECRET=CHANGE_THIS_SECURE_SECRET_KEY # Email (optional for v1) EMAIL_SERVICE=sendgrid EMAIL_API_KEY=your_api_key_here EMAIL_FROM=noreply@example.com ``` **Security**: Generate secure passwords: ```bash # Generate DB password openssl rand -base64 32 # Generate JWT secret openssl rand -base64 64 ``` --- ## Step 5: Create Dockerfiles ### 5.1 Backend Dockerfile Create `backend/Dockerfile`: ```dockerfile FROM node:20-alpine AS builder WORKDIR /app # Copy package files COPY package*.json ./ COPY prisma ./prisma/ # Install dependencies RUN npm ci --only=production # Copy source COPY . . # Generate Prisma Client RUN npx prisma generate # Build TypeScript RUN npm run build # Production image FROM node:20-alpine WORKDIR /app # Copy built files COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/package*.json ./ # Run as non-root USER node EXPOSE 3000 CMD ["node", "dist/server.js"] ``` ### 5.2 Frontend Dockerfile Create `frontend/Dockerfile`: ```dockerfile FROM node:20-alpine AS builder WORKDIR /app # Copy package files COPY package*.json ./ # Install dependencies RUN npm ci # Copy source COPY . . # Build for production RUN npm run build # Production image with Nginx FROM nginx:alpine # Copy built files COPY --from=builder /app/dist /usr/share/nginx/html # Copy Nginx config COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ### 5.3 Frontend Nginx Config Create `frontend/nginx.conf`: ```nginx server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # API proxy 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_cache_bypass $http_upgrade; 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; } # Frontend SPA routing location / { try_files $uri $uri/ /index.html; } # 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; } ``` --- ## Step 6: Deploy Service ### 6.1 Build and Start ```bash cd /srv/containers/ca-grow-ops-manager # Load environment variables set -a source docker-compose.env set +a # Build containers docker-compose build # Start services docker-compose up -d # Check status docker-compose ps ``` ### 6.2 Run Database Migrations ```bash # Run Prisma migrations docker-compose exec backend npx prisma migrate deploy # Seed initial data (if seed script exists) docker-compose exec backend npx prisma db seed ``` ### 6.3 Verify Deployment ```bash # Check all containers are running docker-compose ps # Check backend health curl http://localhost:8010/api/healthz # Check frontend curl -I http://localhost:8010/ # View logs docker-compose logs -f --tail=100 ``` --- ## Step 7: Configure Domain (Optional) ### 7.1 DNS Configuration Point domain to nexus-vector: ``` ca-grow-ops.runfoo.run → 216.158.230.94:8010 ``` ### 7.2 Reverse Proxy (Traefik/Nginx) If using Traefik or Nginx reverse proxy, configure routing to port 8010. --- ## Step 8: Create Service Documentation ### 8.1 Create README Create `/srv/containers/ca-grow-ops-manager/DEPLOYMENT.md`: ```markdown # CA Grow Ops Manager — Deployment **Job ID**: CAGROW-XXXXXX-GM **Port**: 8010 **Purpose**: Cannabis cultivation facility management platform ## Quick Start \`\`\`bash cd /srv/containers/ca-grow-ops-manager docker-compose up -d curl http://localhost:8010/api/healthz \`\`\` ## Configuration Environment variables in `docker-compose.env`: - `DB_PASSWORD`: PostgreSQL password - `JWT_SECRET`: JWT signing secret - `EMAIL_API_KEY`: SendGrid API key (optional) ## API Endpoints - `GET /api/healthz` - Health check - `POST /api/auth/login` - User login - `GET /api/batches` - List batches - `GET /api/tasks` - List tasks ## Health Monitoring \`\`\`bash # Check service health curl http://localhost:8010/api/healthz # Check container status docker-compose ps # View logs docker-compose logs -f \`\`\` ## Database Migrations \`\`\`bash # Apply migrations docker-compose exec backend npx prisma migrate deploy # View migration status docker-compose exec backend npx prisma migrate status \`\`\` ## Troubleshooting ### Backend won't start - Check database connection: `docker-compose logs db` - Verify environment variables: `docker-compose config` ### Frontend 404 errors - Check Nginx config: `docker-compose exec frontend cat /etc/nginx/conf.d/default.conf` - Verify build: `docker-compose exec frontend ls /usr/share/nginx/html` \`\`\` --- ## Monitoring and Maintenance ### Daily Checks ```bash # Check service health curl http://localhost:8010/api/healthz # Check container status docker-compose ps # Check disk usage docker system df ``` ### Log Monitoring ```bash # View all logs docker-compose logs -f # View specific service docker-compose logs -f backend docker-compose logs -f frontend docker-compose logs -f db ``` ### Backup Database ```bash # Backup PostgreSQL docker-compose exec db pg_dump -U ca_grow_ops ca_grow_ops > backup_$(date +%Y%m%d).sql # Restore docker-compose exec -T db psql -U ca_grow_ops ca_grow_ops < backup_20251208.sql ``` --- ## Updating the Service ### Pull Latest Code ```bash cd /srv/containers/ca-grow-ops-manager # Pull from Forgejo git pull origin main # Rebuild and restart docker-compose down docker-compose build docker-compose up -d # Run migrations docker-compose exec backend npx prisma migrate deploy ``` --- ## Troubleshooting ### Port Already in Use ```bash # Check what's using port 8010 sudo netstat -tlnp | grep 8010 # Or use lsof sudo lsof -i :8010 ``` ### Database Connection Issues ```bash # Check database is running docker-compose ps db # Check database logs docker-compose logs db # Test connection docker-compose exec backend npx prisma db pull ``` ### Container Won't Start ```bash # Check logs docker-compose logs backend # Check resource usage docker stats # Rebuild from scratch docker-compose down -v docker-compose build --no-cache docker-compose up -d ``` --- ## Security Checklist - [ ] Changed default DB_PASSWORD - [ ] Changed default JWT_SECRET - [ ] Configured firewall rules (UFW) - [ ] Set up HTTPS/SSL (if public-facing) - [ ] Configured backup schedule - [ ] Set up monitoring alerts - [ ] Reviewed container security (non-root user) --- ## Next Steps 1. **Complete Week 1 tasks** (infrastructure setup) 2. **Implement authentication** (Week 2) 3. **Build core features** (Week 3-5) 4. **Test and polish** (Week 6) 5. **Deploy to production** --- **Created**: 2025-12-08 **Last Updated**: 2025-12-08 **Maintained By**: Development team