- 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
648 lines
12 KiB
Markdown
648 lines
12 KiB
Markdown
# 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
|