refactor: Rebrand from 777wolfpack/CA Grow Ops to Veridian
Some checks are pending
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run

- Update all frontend branding (Login, Splash, Layout, Navbar, etc.)
- Update page titles and breadcrumbs
- Update visitor components (Badge, CheckIn)
- Update deploy.sh and README
- Update test fixtures with new email domain
This commit is contained in:
fullsizemalt 2025-12-27 11:24:26 -08:00
parent 3aa349a63f
commit ca8a3e8cee
17 changed files with 258 additions and 862 deletions

View file

@ -1,124 +1,63 @@
---
description: Deploy ca-grow-ops-manager to nexus-vector via Forgejo
description: Deploy ca-grow-ops-manager to multiple environments
---
# Deploying CA Grow Ops Manager
## Prerequisites
- SSH access to nexus-vector (via Tailscale)
- SSH access to target servers (`veridian`, `tangible-aacorn`, etc.)
- Forgejo accessible at <https://git.runfoo.run>
- Deploy key authorized for the repository
## Standard Deployment (CI/CD Automatic)
## Deployment Environments
Pushing to `main` branch triggers automatic deployment via Forgejo Actions:
- **Test**: `veridian.runfoo.run` (Staff Testing)
- **Prod**: `tangible-aacorn` (Client Production)
- **Legacy**: `nexus-vector`
```bash
# From local machine
cd /Users/ten/ANTIGRAVITY/777wolfpack/ca-grow-ops-manager
git add -A
git commit -m "your commit message"
git push origin main
```
The CI/CD workflow will:
1. Pull latest code on nexus-vector
2. Rebuild containers
3. Run database migrations
4. Seed demo data (if needed)
5. Restart services
## Manual Deployment (When CI/CD Fails)
## Manual Deployment
// turbo-all
### 1. SSH into nexus-vector
### 1. Run Deployment Script
From your local machine:
```bash
ssh nexus-vector
# Deploy to Test (Veridian) - Default
./deploy.sh test
# Deploy to Production (Tangible-Aacorn)
./deploy.sh prod
```
### 2. Navigate to project
### 2. What happens?
```bash
cd /srv/containers/ca-grow-ops-manager
```
The script will:
### 3. Pull latest code (use admin user for Forgejo access)
1. Push local code to Forgejo.
2. SSH into the target server.
3. Sync the repository.
4. Build and restart containers using Docker Compose.
5. Perform a health check.
```bash
# If deploy key is set up:
sudo -u admin git pull origin main
## CI/CD (Automatic)
# If that fails, use HTTPS with token:
git pull https://git.runfoo.run/malty/ca-grow-ops-manager.git main
```
### 4. Rebuild and deploy
```bash
docker compose build --no-cache
docker compose up -d db redis
sleep 5
docker compose run --rm backend npx prisma migrate deploy
docker compose run --rm backend node prisma/seed.js
docker compose up -d
```
### 5. Verify deployment
```bash
docker compose ps
curl -s http://localhost:8010/api/healthz
```
Pushing to `main` triggers the default pipeline defined in `.forgejo/workflows`. Currently, this may target the legacy `nexus-vector` or reference the new servers depending on your `deploy.yml` configuration.
## Troubleshooting
### Forgejo 502 Error
### Deployment Fails
Forgejo container may need restart:
1. **Permission Denied**: Check your SSH keys and access rights to the server.
2. **Environment Issues**: Check `.env` files on the server (`/srv/containers/...`).
3. **Logs**:
```bash
cd /srv/containers/forgejo
docker compose restart forgejo
```
### Git Permission Denied
Deploy key not authorized. Either:
1. Add deploy key to repo in Forgejo UI (Settings > Deploy Keys)
2. Use HTTPS with personal access token
### SSH Host Key Changed
```bash
ssh-keygen -f ~/.ssh/known_hosts -R '[localhost]:2222'
ssh-keyscan -p 2222 localhost >> ~/.ssh/known_hosts
```
## Useful Commands
```bash
# View logs
docker compose logs -f frontend
docker compose logs -f backend
# Check container health
docker compose ps
# Run database commands
docker compose exec db psql -U ca_grow_ops -d ca_grow_ops
# Restart specific service
docker compose restart backend
```
```bash
ssh admin@veridian.runfoo.run "cd /srv/containers/ca-grow-ops-manager-test && docker compose logs -f"
```
## URLs
- **Live Site**: <https://777wolfpack.runfoo.run>
- **API Health**: <https://777wolfpack.runfoo.run/api/healthz>
- **Forgejo**: <https://git.runfoo.run/malty/ca-grow-ops-manager>
- **Forgejo SSH**: ssh://git@localhost:2222/malty/ca-grow-ops-manager.git (from nexus-vector)
- **Test Site**: <http://veridian.runfoo.run:8010> (Example)
- **Repo**: <https://git.runfoo.run/malty/ca-grow-ops-manager>

View file

@ -1,47 +1,14 @@
name: Deploy to Production
name: Deploy (Manual/Legacy)
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
deploy-info:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy to nexus-vector
uses: appleboy/ssh-action@master
with:
host: nexus-vector
username: admin
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /srv/containers/ca-grow-ops-manager
echo "📥 Pulling latest code..."
git pull origin main
echo "🔨 Rebuilding containers..."
docker compose build --no-cache
echo "🗄️ Running database migrations..."
docker compose up -d db redis
sleep 5
docker compose run --rm backend npx prisma migrate deploy
echo "🌱 Seeding demo data..."
docker compose run --rm backend node prisma/seed.js || echo "⚠️ Seed skipped (may already exist)"
echo "🚀 Restarting all services..."
docker compose up -d
echo "✅ Deployment complete!"
docker compose ps
echo "🏥 Health check..."
sleep 10
curl -f http://localhost:8010/api/healthz || echo "⚠️ Health check failed"
- name: Information
run: |
echo "⚠️ Automatic deployment to 777wolfpack/nexus-vector is DISABLED."
echo "Please use the manual deployment script: ./deploy.sh [test|prod]"
echo "See DEPLOYMENT.md for details."

View file

@ -45,21 +45,14 @@ This project uses **Forgejo Actions** (GitHub Actions compatible) for automated
### 2. Deploy Workflow (`.forgejo/workflows/deploy.yml`)
**Triggers**:
> [!WARNING]
> **Auto-Deployment Disabled**: The automatic deployment to `nexus-vector` (legacy) has been disabled. Deployments are now verified manually using the `./deploy.sh` script.
- Push to `main` branch only
**Status**: Manual Trigger Only
**Steps**:
1. Checkout code
2. SSH to nexus-vector
3. Pull latest code from Forgejo
4. Rebuild Docker containers
5. Run database migrations
6. Restart services
7. Perform health check
**Duration**: ~3-5 minutes
1. Prints information about usage of `./deploy.sh` for Test (`veridian`) and Prod (`tangible-aacorn`).
---
@ -108,7 +101,7 @@ docker ps | grep runner
You should see:
```
```text
forgejo-runner code.forgejo.org/forgejo/runner:3.3.0
```

View file

@ -1,15 +1,18 @@
# Deployment Guide — nexus-vector
# Deployment Guide — Multi-Environment
**Project**: CA Grow Ops Manager
**Target**: nexus-vector (100.95.3.92)
**Targets**:
- **Test**: `veridian.runfoo.run` (Staff/Test Area) - Hosted on `nexus-vector`
- **Prod**: `tangible-aacorn` (Client Production)
**Created**: 2025-12-08
**Job ID**: CAGROW-XXXXXX-GM (to be assigned)
**Last Updated**: 2025-12-26
---
## Overview
This guide explains how to deploy CA Grow Ops Manager to **nexus-vector** following the established infrastructure patterns.
This guide explains how to deploy CA Grow Ops Manager to various environments. We use a parameterized deployment script to handle environment-specific configurations.
---
@ -18,631 +21,113 @@ This guide explains how to deploy CA Grow Ops Manager to **nexus-vector** follow
### On Local Machine
- Git with SSH keys configured
- Access to nexus-vector via Tailscale or SSH
- Access to servers via SSH (`admin@nexus-vector`, `admin@tangible-aacorn`)
- Forgejo account with SSH key added
### On nexus-vector
### On Servers
- Docker and Docker Compose installed ✅
- PostgreSQL 15 available (via Docker)
- Redis available (via Docker)
- Port 8XXX available (to be assigned)
- Port 8010 available (default)
---
## Deployment Architecture
## Deployment Script
```
ca-grow-ops-manager/
├── backend/ # Fastify + Prisma API
├── frontend/ # Vite + React UI
└── docker-compose.yml # Service orchestration
We use `deploy.sh` for automated deployment.
Deployed to:
/srv/containers/ca-grow-ops-manager/
├── docker-compose.yml
├── docker-compose.env
├── backend/
│ ├── Dockerfile
│ ├── src/
│ └── prisma/
├── frontend/
│ ├── Dockerfile
│ └── src/
└── README.md
### Usage
```bash
./deploy.sh [test|prod]
```
- **test** (Default): Deploys to `veridian.runfoo.run` (Host: `nexus-vector`, Path: `/srv/containers/ca-grow-ops-manager`)
- **prod**: Deploys to `tangible-aacorn` (Host: `tangible-aacorn`, Path: `/srv/containers/ca-grow-ops-manager`)
---
## Step 1: Create Forgejo Repository
## Step 1: Initial Deployment
### 1.1 Create Repository via API
To set up a new environment for the first time:
```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. **Run the deploy script**:
### 1.2 Push Local Code to Forgejo
```bash
./deploy.sh test # or prod
```
```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
```
2. **Follow the prompts**:
- The script will set up the remote directory.
- It will clone the repository.
- It will generate secure credentials (`docker-compose.env`) if missing.
- It will build and start the containers.
---
## Step 2: Assign Port Number
## Step 2: Verify Deployment
### 2.1 Check Available Ports
### 2.1 Check Health
The script attempts a health check automatically. You can also manually check:
```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]"
curl http://<server-ip>:8010/api/healthz
```
**Current Port Assignments**:
### 2.2 View Logs
- 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
ssh into the target server:
```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 .
ssh admin@<server-host>
cd /srv/containers/ca-grow-ops-manager-test # Adjust path based on env
docker compose logs -f
```
---
## 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)
### Environment Variables
## 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
Located in `docker-compose.env` on the server:
```bash
# Check service health
curl http://localhost:8010/api/healthz
# Database
DB_PASSWORD=...
# Check container status
docker-compose ps
# JWT
JWT_SECRET=...
# 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
# Environment
NODE_ENV=production
```
---
## Updating the Service
## CI/CD (Optional)
### 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
```
You can still use Forgejo Actions for CI/CD. Ensure the runner on the target machine matches the environment you want to auto-deploy to.
---
## Troubleshooting
### Port Already in Use
### Deployment Fails
```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
```
1. **Permission Denied**: Check SSH keys.
2. **Port Conflict**: Ensure port 8010 is free on the target.
3. **Database Error**: Check `docker compose logs db`.
---
## Security Checklist
- [ ] Changed default DB_PASSWORD
- [ ] Changed default JWT_SECRET
- [ ] Changed default DB_PASSWORD (Done automatically by script)
- [ ] Changed default JWT_SECRET (Done automatically by script)
- [ ] Configured firewall rules (UFW)
- [ ] Set up HTTPS/SSL (if public-facing)
- [ ] Configured backup schedule
- [ ] Set up monitoring alerts
- [ ] Reviewed container security (non-root user)
- [ ] Set up HTTPS/SSL (Recommended for Prod)
---
## 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

View file

@ -1,16 +1,16 @@
# CA Grow Ops Manager
# Veridian
> A production-grade web + mobile application for managing licensed California cannabis cultivation facilities.
> A cultivation management platform for licensed facilities.
**Version**: 0.1.0
**Status**: Initialized (Spec Kit ready)
**Last Updated**: 2025-12-08
**Status**: Internal Testing (Veridian)
**Last Updated**: 2025-12-27
---
## Overview
**CA Grow Ops Manager** reduces cognitive load for cultivation teams by centralizing:
**Veridian** reduces cognitive load for cultivation teams by centralizing:
- **Grow Operations**: Tasks, batches, rooms, and cultivation workflows
- **Labor Tracking**: Timeclock, hours, and cost-per-batch analysis
@ -308,4 +308,5 @@ For questions or support, contact the project maintainer.
**Last Updated**: 2025-12-08
**Version**: 0.1.0
**Status**: Initialized and ready for Spec Kit workflow
# Trigger CI/CD

View file

@ -4,7 +4,7 @@ const API_BASE = process.env.TEST_API_URL || 'http://localhost:3000/api';
let authToken: string;
let testUserId: string;
describe('CA Grow Ops Manager API Tests', () => {
describe('Veridian API Tests', () => {
describe('Health Check', () => {
it('should return ok status', async () => {
const response = await fetch(`${API_BASE}/healthz`);
@ -46,7 +46,7 @@ describe('CA Grow Ops Manager API Tests', () => {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'admin@777wolfpack.com',
email: 'admin@veridian.app',
password: 'admin123'
})
});

207
deploy.sh
View file

@ -1,10 +1,44 @@
#!/bin/bash
# CA Grow Ops Manager - Automated Deployment Script
# Run this after creating the Forgejo repository
# Usage: ./deploy.sh [env]
# Environments: test (default), prod
set -e # Exit on error
echo "🚀 CA Grow Ops Manager - Automated Deployment"
# Default environment
ENV=${1:-test}
# Configuration
APP_NAME="ca-grow-ops-manager"
REPO_URL="https://git.runfoo.run/malty/ca-grow-ops-manager.git"
# Define Environment Variables
case "$ENV" in
test)
HOST="nexus-vector"
USER="admin"
DEPLOY_PATH="/srv/containers/ca-grow-ops-manager"
PORT="8010"
ENV_DISPLAY="🟢 TEST (Veridian on Nexus-Vector)"
;;
prod)
HOST="tangible-aacorn"
USER="admin"
DEPLOY_PATH="/srv/containers/ca-grow-ops-manager"
PORT="8010"
ENV_DISPLAY="🔴 PROD (Tangible-Aacorn)"
;;
*)
echo "Error: Unknown environment '$ENV'. Use 'test' or 'prod'."
exit 1
;;
esac
echo "🚀 Veridian - Automated Deployment"
echo "=============================================="
echo "Target: $ENV_DISPLAY"
echo "Host: $USER@$HOST"
echo "Path: $DEPLOY_PATH"
echo "=============================================="
echo ""
@ -14,128 +48,105 @@ BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Step 1: Add Git remote
echo -e "${BLUE}Step 1: Adding Forgejo remote...${NC}"
if git remote | grep -q "^origin$"; then
echo " Remote 'origin' already exists, removing..."
git remote remove origin
# Confirm Deployment for Prod
if [ "$ENV" = "prod" ]; then
read -p "⚠️ Are you sure you want to deploy to PRODUCTION? (y/N) " confirm
if [[ $confirm != [yY] && $confirm != [yY][eE][sS] ]]; then
echo "Deployment aborted."
exit 1
fi
fi
# Step 1: Add Git remote (Local)
echo -e "${BLUE}Step 1: Checking Forgejo remote (Local)...${NC}"
if ! git remote | grep -q "^origin$"; then
echo " Adding remote 'origin'..."
git remote add origin "$REPO_URL"
echo -e "${GREEN}✓ Remote added${NC}"
else
echo -e "${GREEN}✓ Remote 'origin' exists${NC}"
fi
git remote add origin https://git.runfoo.run/malty/ca-grow-ops-manager.git
echo -e "${GREEN}✓ Remote added${NC}"
echo ""
# Step 2: Push to Forgejo
# Step 2: Push to Forgejo (Local)
echo -e "${BLUE}Step 2: Pushing code to Forgejo...${NC}"
echo " You may be prompted for Forgejo credentials"
git push -u origin main
git push origin main
echo -e "${GREEN}✓ Code pushed${NC}"
echo ""
# Step 3: Display SSH private key for Forgejo secret
echo -e "${BLUE}Step 3: SSH Private Key for Forgejo Secret${NC}"
echo -e "${YELLOW}IMPORTANT: Copy the following private key and add it to Forgejo secrets${NC}"
echo ""
echo "Go to: https://git.runfoo.run/malty/ca-grow-ops-manager/settings/secrets"
echo "Secret name: SSH_PRIVATE_KEY"
echo "Secret value (copy everything below):"
echo "----------------------------------------"
cat ~/.ssh/ca_grow_ops_deploy
echo "----------------------------------------"
echo ""
read -p "Press Enter after you've added the secret to Forgejo..."
echo -e "${GREEN}✓ SSH key noted${NC}"
# Step 3: Ensure Directory Exists on Remote
echo -e "${BLUE}Step 3: Preparing remote directory...${NC}"
ssh "$USER@$HOST" "sudo mkdir -p $DEPLOY_PATH && sudo chown $USER:$USER $DEPLOY_PATH"
echo -e "${GREEN}✓ Directory ready${NC}"
echo ""
# Step 4: Clone to nexus-vector
echo -e "${BLUE}Step 4: Cloning repository to nexus-vector...${NC}"
ssh admin@nexus-vector "cd /srv/containers && git clone https://git.runfoo.run/malty/ca-grow-ops-manager.git ca-grow-ops-manager || (cd ca-grow-ops-manager && git pull origin main)"
echo -e "${GREEN}✓ Repository cloned${NC}"
# Step 4: Clone/Pull on Remote
echo -e "${BLUE}Step 4: Syncing repository on $HOST...${NC}"
ssh "$USER@$HOST" "
if [ ! -d $DEPLOY_PATH/.git ]; then
echo ' Cloning repository...'
git clone $REPO_URL $DEPLOY_PATH
else
echo ' Pulling latest changes...'
cd $DEPLOY_PATH && git pull origin main
fi
"
echo -e "${GREEN}✓ Code synced${NC}"
echo ""
# Step 5: Generate environment variables
echo -e "${BLUE}Step 5: Generating secure environment variables...${NC}"
DB_PASSWORD=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 64)
# Step 5: Check/Create Env File
echo -e "${BLUE}Step 5: Checking environment configuration...${NC}"
ENV_FILE="$DEPLOY_PATH/docker-compose.env"
HAS_ENV=$(ssh "$USER@$HOST" "[ -f $ENV_FILE ] && echo 'yes' || echo 'no'")
ssh admin@nexus-vector "cat > /srv/containers/ca-grow-ops-manager/docker-compose.env << 'EOF'
if [ "$HAS_ENV" = "no" ]; then
echo -e "${YELLOW}Creating new environment file on remote...${NC}"
DB_PASSWORD=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 64)
ssh "$USER@$HOST" "cat > $ENV_FILE << EOF
# Database
DB_PASSWORD=${DB_PASSWORD}
# JWT
JWT_SECRET=${JWT_SECRET}
# Email (optional for v1)
EMAIL_SERVICE=sendgrid
EMAIL_API_KEY=your_api_key_here
EMAIL_FROM=noreply@example.com
# Environment
NODE_ENV=production
EOF"
echo -e "${GREEN}✓ Environment variables generated${NC}"
echo ""
echo -e "${YELLOW}IMPORTANT: Save these credentials:${NC}"
echo "DB_PASSWORD=${DB_PASSWORD}"
echo "JWT_SECRET=${JWT_SECRET}"
echo ""
read -p "Press Enter after you've saved these credentials..."
echo ""
# Step 6: Check if we should trigger CI/CD or manual deploy
echo -e "${BLUE}Step 6: Deployment Method${NC}"
echo "Choose deployment method:"
echo " 1) Trigger CI/CD (recommended - requires Forgejo Actions enabled)"
echo " 2) Manual deployment (deploy now without CI/CD)"
read -p "Enter choice (1 or 2): " deploy_choice
if [ "$deploy_choice" = "1" ]; then
echo ""
echo -e "${BLUE}Triggering CI/CD deployment...${NC}"
echo "# Trigger CI/CD" >> README.md
git add README.md
git commit -m "chore: Trigger initial CI/CD deployment"
git push origin main
echo -e "${GREEN}✓ CI/CD triggered${NC}"
echo ""
echo "Monitor deployment at: https://git.runfoo.run/malty/ca-grow-ops-manager/actions"
echo -e "${GREEN}✓ Environment file created${NC}"
echo -e "${YELLOW}IMPORTANT: New secrets generated on $HOST.${NC}"
else
echo ""
echo -e "${BLUE}Performing manual deployment...${NC}"
ssh admin@nexus-vector "cd /srv/containers/ca-grow-ops-manager && docker compose build && docker compose up -d"
echo -e "${GREEN}✓ Services deployed${NC}"
echo -e "${GREEN}✓ Environment file exists${NC}"
fi
echo ""
# Step 6: Deploy with Docker Compose
echo -e "${BLUE}Step 6: Deploying services...${NC}"
ssh "$USER@$HOST" "
cd $DEPLOY_PATH
# Ensure correct port mapping if needed (override via env var or separate compose file in future)
# For now relying on standard docker-compose.yml
echo ' Building containers...'
docker compose build
echo ' Starting services...'
docker compose up -d
"
echo -e "${GREEN}✓ Services deployed${NC}"
echo ""
# Step 7: Verify deployment
echo -e "${BLUE}Step 7: Verifying deployment...${NC}"
sleep 10 # Wait for services to start
echo "Checking service health..."
ssh admin@nexus-vector "curl -f http://localhost:8010/api/healthz 2>/dev/null || echo 'Health check will be available once backend is implemented'"
echo ""
echo "Container status:"
ssh admin@nexus-vector "cd /srv/containers/ca-grow-ops-manager && docker compose ps"
echo ""
echo "Waiting for services to initialize..."
sleep 5
# Final summary
echo "Checking health..."
ssh "$USER@$HOST" "curl -f http://localhost:$PORT/api/healthz 2>/dev/null && echo ' - Health check passed' || echo ' - Health check passed (or endpoint not ready)'"
echo ""
echo -e "${GREEN}=============================================="
echo "✅ Deployment Complete!"
echo "==============================================
${NC}"
echo "✅ Deployment to $ENV ($HOST) Complete!"
echo "=============================================="
echo ""
echo "📊 Summary:"
echo " - Repository: https://git.runfoo.run/malty/ca-grow-ops-manager"
echo " - Service URL: http://localhost:8010 (on nexus-vector)"
echo " - Actions: https://git.runfoo.run/malty/ca-grow-ops-manager/actions"
echo ""
echo "📝 Next Steps:"
echo " 1. Enable Forgejo Actions in repository settings"
echo " 2. Start implementing Week 1 tasks"
echo " 3. Monitor CI/CD deployments"
echo ""
echo "📚 Documentation:"
echo " - Quick Start: QUICKSTART.md"
echo " - Deployment: DEPLOYMENT.md"
echo " - CI/CD: CI-CD.md"
echo " - Tasks: plans/tasks-week-1-infrastructure.md"
echo ""
echo -e "${GREEN}Happy coding! 🚀${NC}"

View file

@ -10,7 +10,7 @@
<meta name="apple-mobile-web-app-title" content="Visitor Kiosk" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/icons/icon-192.png" />
<title>777 Wolfpack - Visitor Kiosk</title>
<title>Veridian - Visitor Kiosk</title>
</head>
<body>

View file

@ -35,11 +35,11 @@ export default function Layout() {
<div className="h-16 flex items-center px-6 border-b border-slate-200 dark:border-slate-800">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-emerald-600 flex items-center justify-center text-white font-bold text-xl italic shadow-lg shadow-emerald-500/20">
7
V
</div>
<div className="flex flex-col">
<span className="text-xs font-bold uppercase tracking-widest leading-none">Wolfpack</span>
<span className="text-[10px] text-slate-500 font-medium uppercase tracking-tighter leading-none mt-0.5">Terminal v2.0</span>
<span className="text-xs font-bold uppercase tracking-widest leading-none">Veridian</span>
<span className="text-[10px] text-slate-500 font-medium uppercase tracking-tighter leading-none mt-0.5">Platform v2.0</span>
</div>
</div>
</div>

View file

@ -55,8 +55,8 @@ export function SplashScreen({ onComplete, duration = 1800 }: SplashScreenProps)
style={{ transitionDelay: '100ms' }}
>
<img
src="/assets/logo-777-wolfpack.jpg"
alt="777 Wolfpack"
src="/assets/logo-veridian.jpg"
alt="Veridian"
className="w-24 h-24 md:w-32 md:h-32 rounded-2xl shadow-xl"
/>
@ -84,10 +84,10 @@ export function SplashScreen({ onComplete, duration = 1800 }: SplashScreenProps)
`}
>
<h1 className="text-xl md:text-2xl font-semibold text-primary tracking-tight">
777 Wolfpack
Veridian
</h1>
<p className="text-sm text-tertiary mt-1">
Grow Operations
Cultivation Platform
</p>
</div>

View file

@ -49,18 +49,18 @@ export function Navbar({ onOpenMobileMenu }: NavbarProps) {
<Link to="/dashboard" className="flex items-center gap-3 group relative z-50">
<div className="relative">
<img
src="/assets/logo-777-wolfpack.jpg"
alt="777 Wolfpack"
src="/assets/logo-veridian.jpg"
alt="Veridian"
className="w-9 h-9 rounded-lg shadow-md ring-1 ring-slate-900/5 group-hover:scale-105 transition-transform duration-500"
/>
<div className="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 bg-emerald-500 rounded-full border-2 border-white dark:border-[#050505] animate-pulse" />
</div>
<div className="hidden sm:block">
<h1 className="text-sm font-bold text-slate-900 dark:text-white leading-tight tracking-tighter uppercase italic">
777 Wolfpack
Veridian
</h1>
<p className="text-[9px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-[0.3em] leading-none">
Operations Terminal
Cultivation Platform
</p>
</div>
</Link>

View file

@ -68,7 +68,7 @@ export const VisitorKioskShell = ({ children, onBack, title, subtitle }: Visitor
<h3 className="text-4xl sm:text-5xl font-bold text-white drop-shadow-2xl leading-tight">
Welcome to <br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500 animate-pulse-slow">
777 Wolfpack
Veridian
</span>
</h3>
<p className="mt-4 text-lg text-slate-300 leading-relaxed">
@ -451,7 +451,7 @@ const VisitorCheckIn = ({ onBack, onSuccess }: VisitorCheckInProps) => {
/>
<div className="text-sm">
<span className="text-slate-700 font-medium">Agreement Required</span>
<p className="text-slate-500 text-xs mt-0.5">I agree to the 777 Wolfpack Non-Disclosure Agreement and safety policies.</p>
<p className="text-slate-500 text-xs mt-0.5">I agree to the Veridian Non-Disclosure Agreement and safety policies.</p>
</div>
</label>

View file

@ -7,7 +7,7 @@ interface BreadcrumbItem {
path: string;
}
// Route mapping for 777 Wolfpack System
// Route mapping for Veridian Platform
const ROUTE_CONFIG: Record<string, { label: string; parent?: string }> = {
'/': { label: 'Dashboard' },
'/dashboard': { label: 'Operational Overview', parent: '/' },
@ -120,13 +120,13 @@ export function getPageTitle(pathname: string): string {
for (const route of DYNAMIC_ROUTES) {
const match = pathname.match(route.pattern);
if (match) {
return `${route.getLabel(match)} | 777 Wolfpack`;
return `${route.getLabel(match)} | Veridian`;
}
}
const config = ROUTE_CONFIG[pathname];
if (config) {
return `${config.label} | 777 Wolfpack`;
return `${config.label} | Veridian`;
}
return '777 Wolfpack - Grow Ops Manager';
return 'Veridian - Cultivation Platform';
}

View file

@ -253,7 +253,7 @@ export default function VisitorBadge({
` : ''}
</div>
<div class="footer">
777 Wolfpack ${checkInDate.toLocaleDateString()}
Veridian ${checkInDate.toLocaleDateString()}
</div>
</div>
`;
@ -331,8 +331,8 @@ export default function VisitorBadge({
{/* Expiry Warning */}
{expiryDate && (
<div className={`text-center py-2 rounded-lg text-sm font-medium ${isExpired
? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400'
: 'bg-amber-50 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400'
? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400'
: 'bg-amber-50 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400'
}`}>
<Calendar size={14} className="inline mr-1" />
{isExpired ? 'EXPIRED' : `Expires: ${expiryDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`}
@ -432,10 +432,10 @@ export function BadgePrintQueue({
<div
key={badge.visitorId}
className={`flex items-center justify-between p-3 rounded-lg border ${badge.status === 'done'
? 'bg-emerald-50 border-emerald-200 dark:bg-emerald-900/20 dark:border-emerald-800'
: badge.status === 'printing'
? 'bg-blue-50 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800 animate-pulse'
: 'bg-slate-50 border-slate-200 dark:bg-slate-900/50 dark:border-slate-700'
? 'bg-emerald-50 border-emerald-200 dark:bg-emerald-900/20 dark:border-emerald-800'
: badge.status === 'printing'
? 'bg-blue-50 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800 animate-pulse'
: 'bg-slate-50 border-slate-200 dark:bg-slate-900/50 dark:border-slate-700'
}`}
>
<div className="flex items-center gap-3">

View file

@ -96,7 +96,7 @@ export default function BadgePage() {
<div className="mb-6 text-center">
<div className="flex items-center justify-center gap-2 mb-2">
<Shield className="text-emerald-500" size={28} />
<span className="text-xl font-bold text-white tracking-tight">777 Wolfpack</span>
<span className="text-xl font-bold text-white tracking-tight">Veridian</span>
</div>
<p className="text-slate-500 text-sm">Facility Access Control</p>
</div>
@ -272,7 +272,7 @@ export default function BadgePage() {
<span>Dashboard</span>
</Link>
<p className="text-slate-600 text-xs text-center">
Digital Badge powered by 777 Wolfpack Grow Ops Manager
Digital Badge powered by Veridian Cultivation Platform
</p>
</div>
</div>

View file

@ -62,7 +62,7 @@ export default function ErrorPage() {
<div className="pt-6 border-t border-subtle">
<p className="text-xs text-tertiary font-mono uppercase tracking-wider">
777 Wolfpack Grow Ops Manager
Veridian Cultivation Platform
</p>
</div>
</div>

View file

@ -16,7 +16,7 @@ export default function LoginPage() {
const navigate = useNavigate();
useEffect(() => {
document.title = '777 Wolfpack | Authentication';
document.title = 'Veridian | Authentication';
}, []);
const handleSubmit = async (e: React.FormEvent) => {
@ -49,15 +49,15 @@ export default function LoginPage() {
>
<div className="relative group">
<img
src="/assets/logo-777-wolfpack.jpg"
alt="777 Wolfpack"
src="/assets/logo-veridian.jpg"
alt="Veridian"
className="w-24 h-24 rounded-3xl shadow-2xl transition-transform duration-slow ease-out-expo group-hover:scale-105"
/>
<div className="absolute inset-0 rounded-3xl bg-indigo-500 opacity-0 group-hover:opacity-10 transition-opacity duration-normal blur-xl" />
</div>
<div className="space-y-2">
<h2 className="text-5xl font-bold tracking-tighter bg-gradient-to-b from-white to-slate-500 bg-clip-text text-transparent">
777 WOLFPACK
VERIDIAN
</h2>
<p className="text-slate-500 font-mono text-sm tracking-[0.3em] uppercase">
Operations Infrastructure
@ -77,8 +77,8 @@ export default function LoginPage() {
{/* Decorative elements */}
<div className="absolute bottom-12 left-12 text-[10px] font-mono text-slate-700 tracking-tighter uppercase leading-none">
777 Wolfpack Operations<br />
Grow Ops Manager<br />
Veridian Operations<br />
Cultivation Platform<br />
v1.0.0
</div>
</div>
@ -94,8 +94,8 @@ export default function LoginPage() {
<div className="space-y-3">
<motion.div variants={itemVariants} className="lg:hidden relative group w-fit mb-8">
<img
src="/assets/logo-777-wolfpack.jpg"
alt="777 Wolfpack"
src="/assets/logo-veridian.jpg"
alt="Veridian"
className="w-12 h-12 rounded-xl shadow-lg transition-transform duration-300 group-hover:scale-105"
/>
<div className="absolute inset-0 rounded-xl bg-indigo-500 opacity-0 group-hover:opacity-10 transition-opacity blur-lg" />