ca-grow-ops-manager/DEPLOYMENT.md
fullsizemalt da7729d6e4
Some checks failed
Deploy to Production / deploy (push) Failing after 0s
Test / backend-test (push) Failing after 0s
Test / frontend-test (push) Failing after 0s
Initial commit: Spec Kit foundation complete
- Constitution and project spec (spec.yml)
- 7 comprehensive feature specs (tasks, batches, labor, compliance, inventory, integrations, comms)
- Phase 1 implementation plan (6-week roadmap)
- Week 1 task breakdown (15 concrete tasks)
- Architecture and compliance documentation
- Backend and frontend setup guides
- Deployment guide for nexus-vector
- CI/CD workflows (Forgejo Actions)
- Quick start guide for developers

Project is ready for implementation with:
- Automated testing on every push
- Automatic deployment to nexus-vector on push to main
- Database migrations handled automatically
- Health checks and monitoring

Stack: TypeScript, Fastify, React, Vite, PostgreSQL, Prisma, Docker
2025-12-08 23:54:12 -08:00

12 KiB

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

# 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

# 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:

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

# 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

# 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

# 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

cd /srv/containers/ca-grow-ops-manager

Create docker-compose.yml:

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:

# 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:

# 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:

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:

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:

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

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

# 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

# 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:

# 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

# 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

# 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

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

# Check what's using port 8010
sudo netstat -tlnp | grep 8010

# Or use lsof
sudo lsof -i :8010

Database Connection Issues

# 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

# 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