Add complete automation SOP system for BlackRoad ERP

This implements the "Automate The Company" initiative with comprehensive
Standard Operating Procedures for GitHub + Salesforce + Asana integration.

New directory: sop/
├── workflows/ - End-to-end process documentation
│   ├── new-client-kickoff.md - Flagship workflow from deal → repos → Asana
│   └── release-pipeline.md - Deploy → update Salesforce + Asana
├── playbooks/ - Human-friendly checklists
│   └── brenda-new-client-checklist.md - Non-technical operator guide
├── salesforce/ - Salesforce automation specifications
│   ├── flows/opp-automation-onstagechange.md - Trigger on Closed Won
│   └── orchestrations/new-client-kickoff-orchestration.md - Multi-stage process
├── integrations/ - API integration specifications
│   ├── salesforce-to-github.md - Create repos from Salesforce
│   ├── github-to-salesforce.md - Update Salesforce after deploy
│   └── salesforce-to-asana.md - Create Asana projects from Salesforce
└── templates/ - Reusable templates
    ├── github-actions/ - CI/CD workflows (ci.yml, deploy.yml, safety.yml)
    └── repo-template/ - Standard repo config (PR template, labels, branch protection)

Key Features:
- Event-driven automation (Closed Won → repos + Asana creation)
- GitHub Actions templates for CI/CD baseline
- Salesforce Flow & Orchestration specs
- Complete API integration documentation
- Operator-friendly playbooks
- Two-view approach (operator + engineer)
- No manual status syncing across systems

This provides the complete backbone for next-gen ERP automation.
This commit is contained in:
Claude
2025-11-17 08:17:51 +00:00
parent 9b137af555
commit 7cde897040
18 changed files with 6077 additions and 0 deletions

View File

@@ -0,0 +1,556 @@
# Release Pipeline Workflow
**Owner:** Engineering + DevOps
**Systems:** GitHub → Railway/Cloudflare → Salesforce → Asana
**Status:** Active
**Last Updated:** 2025-11-17
---
## Overview
This workflow automates the **entire release and deployment lifecycle**, from code commit to production deployment to updating all stakeholders automatically.
**Key Principle:** Merge to `main` should feel like magic. Everything else happens automatically.
---
## The Pipeline
```
Developer pushes code
GitHub Actions: CI pipeline (test + lint + build)
PASS → Ready for PR
PR created + reviewed + approved
PR merged to `main`
GitHub Actions: Deploy pipeline
├─→ Deploy to Railway (backend)
├─→ Deploy to Cloudflare Pages (frontend)
└─→ Update configs (ops)
Deploy succeeds
GitHub Actions: Notify stakeholders
├─→ Update Salesforce Project (deploy metadata)
├─→ Complete Asana tasks (deployment checklist)
└─→ Post to Slack #deploys
```
---
## Stage 1: Continuous Integration (CI)
**Trigger:**
- Every push to any branch
- Every pull request opened/updated
**GitHub Action:** `.github/workflows/ci.yml`
**Jobs:**
### 1.1 Test
```yaml
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.11, 3.12]
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run tests
run: pytest --cov=. --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.12'
```
### 1.2 Lint
```yaml
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install linters
run: pip install ruff black isort mypy
- name: Run ruff
run: ruff check .
- name: Check formatting
run: black --check .
- name: Check import order
run: isort --check-only .
- name: Type check
run: mypy . --ignore-missing-imports
```
### 1.3 Build
```yaml
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t test-build .
- name: Test container starts
run: |
docker run -d --name test-container test-build
sleep 5
docker logs test-container
docker stop test-container
```
**Outputs:**
✅ All checks pass → PR can be merged
❌ Any check fails → PR blocked until fixed
---
## Stage 2: Pull Request Flow
**Process:**
1. **Developer creates PR** with standardized template:
```markdown
## What
Brief description of changes
## Why
Business/technical justification
## How
Implementation approach
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed
## Screenshots/Logs
(if applicable)
## Related
- Asana Task: [link]
- Salesforce Project: [link]
```
2. **Automated checks run:**
- CI pipeline (test + lint + build)
- CODEOWNERS review assignment
- Label auto-applied based on files changed
3. **Human review:**
- At least 1 approval required
- No unresolved conversations
- All checks green
4. **Merge:**
- Squash and merge (clean history)
- Auto-delete branch after merge
---
## Stage 3: Continuous Deployment (CD)
**Trigger:**
- Push to `main` branch
- GitHub Release created (for versioned deploys)
**GitHub Action:** `.github/workflows/deploy.yml`
### 3.1 Deploy Backend (Railway)
```yaml
deploy-backend:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Install Railway CLI
run: |
curl -fsSL https://railway.app/install.sh | sh
- name: Deploy to Railway
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
run: |
railway up --service backend --environment production
- name: Wait for deployment
run: |
railway status --service backend --environment production --wait
- name: Run post-deploy health check
run: |
BACKEND_URL=$(railway variables get BACKEND_URL --service backend --environment production)
curl -f "$BACKEND_URL/health" || exit 1
- name: Save deploy metadata
run: |
echo "DEPLOY_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_ENV
echo "DEPLOY_SHA=${{ github.sha }}" >> $GITHUB_ENV
echo "DEPLOY_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
```
### 3.2 Deploy Frontend (Cloudflare Pages)
```yaml
deploy-frontend:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build frontend
env:
VITE_API_URL: ${{ secrets.PROD_API_URL }}
VITE_ENV: production
run: npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: blackroad-frontend
directory: dist
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
- name: Verify deployment
run: |
sleep 30 # Wait for propagation
curl -f "https://blackroad.app" || exit 1
```
### 3.3 Update Infrastructure (if ops repo)
```yaml
update-infra:
runs-on: ubuntu-latest
if: contains(github.repository, '-ops')
steps:
- uses: actions/checkout@v4
- name: Apply Terraform changes
env:
TF_VAR_railway_token: ${{ secrets.RAILWAY_TOKEN }}
TF_VAR_cloudflare_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
cd terraform
terraform init
terraform plan -out=tfplan
terraform apply -auto-approve tfplan
- name: Update Cloudflare DNS
if: contains(github.event.head_commit.message, '[dns]')
run: |
# Apply DNS changes from dns-config.json
python scripts/update_cloudflare_dns.py
```
---
## Stage 4: Stakeholder Notification
**Trigger:**
Deploy jobs complete successfully
**GitHub Action:** `.github/workflows/notify-stakeholders.yml`
### 4.1 Update Salesforce
```yaml
update-salesforce:
needs: [deploy-backend, deploy-frontend]
runs-on: ubuntu-latest
steps:
- name: Get Project Key from repo
run: |
# Extract from repo name: blackroad-ACME-X7K9-backend → ACME-X7K9
REPO_NAME="${{ github.repository }}"
PROJECT_KEY=$(echo "$REPO_NAME" | sed -n 's/.*blackroad-\([A-Z0-9-]*\)-.*/\1/p')
echo "PROJECT_KEY=$PROJECT_KEY" >> $GITHUB_ENV
- name: Update Salesforce Project record
env:
SF_INSTANCE_URL: ${{ secrets.SALESFORCE_INSTANCE_URL }}
SF_ACCESS_TOKEN: ${{ secrets.SALESFORCE_ACCESS_TOKEN }}
run: |
curl -X PATCH \
"$SF_INSTANCE_URL/services/data/v58.0/sobjects/Project__c/Project_Key__c/$PROJECT_KEY" \
-H "Authorization: Bearer $SF_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"Last_Deploy_At__c": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
"Last_Deploy_SHA__c": "${{ github.sha }}",
"Last_Deploy_Branch__c": "${{ github.ref_name }}",
"Last_Deploy_Actor__c": "${{ github.actor }}",
"Deploy_Status__c": "Success",
"Environment__c": "Production",
"Release_Notes_URL__c": "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
}'
- name: Create Salesforce deployment record
run: |
curl -X POST \
"$SF_INSTANCE_URL/services/data/v58.0/sobjects/Deployment__c" \
-H "Authorization: Bearer $SF_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"Project__c": "'"$PROJECT_KEY"'",
"Deployed_At__c": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
"Git_SHA__c": "${{ github.sha }}",
"Git_Branch__c": "${{ github.ref_name }}",
"Deployed_By__c": "${{ github.actor }}",
"Status__c": "Success",
"Repository__c": "${{ github.repository }}",
"Commit_URL__c": "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
}'
```
### 4.2 Update Asana
```yaml
update-asana:
needs: [deploy-backend, deploy-frontend]
runs-on: ubuntu-latest
steps:
- name: Get Asana project and task IDs
env:
ASANA_PAT: ${{ secrets.ASANA_PAT }}
PROJECT_KEY: ${{ env.PROJECT_KEY }}
run: |
# Find project by name containing PROJECT_KEY
PROJECT_GID=$(curl -s "https://app.asana.com/api/1.0/projects?workspace=${{ secrets.ASANA_WORKSPACE_GID }}&opt_fields=name,gid" \
-H "Authorization: Bearer $ASANA_PAT" | \
jq -r '.data[] | select(.name | contains("'$PROJECT_KEY'")) | .gid')
echo "ASANA_PROJECT_GID=$PROJECT_GID" >> $GITHUB_ENV
- name: Find and complete deploy task
run: |
# Find "Deploy to production" task
TASK_GID=$(curl -s "https://app.asana.com/api/1.0/projects/$ASANA_PROJECT_GID/tasks?opt_fields=name,gid,completed" \
-H "Authorization: Bearer $ASANA_PAT" | \
jq -r '.data[] | select(.name | contains("Deploy") and (.completed == false)) | .gid' | head -n 1)
if [ -n "$TASK_GID" ]; then
# Mark as complete
curl -X PUT "https://app.asana.com/api/1.0/tasks/$TASK_GID" \
-H "Authorization: Bearer $ASANA_PAT" \
-H "Content-Type: application/json" \
-d '{"data": {"completed": true}}'
# Add comment with deploy details
curl -X POST "https://app.asana.com/api/1.0/tasks/$TASK_GID/stories" \
-H "Authorization: Bearer $ASANA_PAT" \
-H "Content-Type: application/json" \
-d '{
"data": {
"text": "✅ Deployed to production\n\n**Commit:** ${{ github.sha }}\n**By:** ${{ github.actor }}\n**Time:** '"$(date -u)"'\n**Link:** https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
}
}'
fi
```
### 4.3 Notify Slack
```yaml
notify-slack:
needs: [update-salesforce, update-asana]
runs-on: ubuntu-latest
if: always()
steps:
- name: Post to #deploys channel
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_DEPLOYS }}
run: |
STATUS_EMOJI="${{ job.status == 'success' && '✅' || '❌' }}"
curl -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "'"$STATUS_EMOJI"' *Deploy to Production*\n\n*Project:* '"$PROJECT_KEY"'\n*Repo:* `${{ github.repository }}`\n*Commit:* <https://github.com/${{ github.repository }}/commit/${{ github.sha }}|'"${GITHUB_SHA:0:7}"'>\n*By:* ${{ github.actor }}\n*Status:* ${{ job.status }}"
}
}
]
}'
```
---
## Stage 5: Rollback (if needed)
**Trigger:** Manual action or automated health check failure
**GitHub Action:** `.github/workflows/rollback.yml`
```yaml
name: Rollback Deployment
on:
workflow_dispatch:
inputs:
target_sha:
description: 'Git SHA to rollback to'
required: true
reason:
description: 'Reason for rollback'
required: true
jobs:
rollback:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.target_sha }}
- name: Rollback backend
run: |
railway up --service backend --environment production
- name: Rollback frontend
run: |
npm ci
npm run build
# Deploy to Cloudflare...
- name: Update Salesforce
run: |
curl -X POST "$SF_INSTANCE_URL/services/data/v58.0/sobjects/Deployment__c" \
-H "Authorization: Bearer $SF_ACCESS_TOKEN" \
-d '{
"Project__c": "'"$PROJECT_KEY"'",
"Status__c": "Rollback",
"Git_SHA__c": "${{ github.event.inputs.target_sha }}",
"Rollback_Reason__c": "${{ github.event.inputs.reason }}"
}'
- name: Notify team
run: |
curl -X POST "$SLACK_WEBHOOK_URL" \
-d '{
"text": "⚠️ *ROLLBACK PERFORMED*\n\nProject: '"$PROJECT_KEY"'\nRolled back to: '"${{ github.event.inputs.target_sha }}"'\nReason: '"${{ github.event.inputs.reason }}"'\nBy: '"${{ github.actor }}"'"
}'
```
---
## Human Touch Points
**What Developers Do:**
1. Write code in feature branch
2. Create PR when ready
3. Address review feedback
4. Merge PR (or approve auto-merge)
5. **That's it.** Everything else is automatic.
**What Ops/Brenda Sees:**
1. Slack notification: "✅ Deploy to production: ACME-X7K9"
2. Asana task auto-completes
3. Salesforce shows updated "Last Deploy" timestamp
4. No manual status updates needed
**When to Intervene:**
- Deploy fails (red X in GitHub Actions)
- Health check fails post-deploy
- Customer reports issue immediately after deploy
- → Use rollback workflow
---
## Metrics Dashboard
Track these in Salesforce or a monitoring tool:
| Metric | Target | Current |
|--------|--------|---------|
| **Deploy Frequency** | > 5/week per project | - |
| **Lead Time** (commit → production) | < 30 minutes | - |
| **Change Failure Rate** | < 15% | - |
| **MTTR** (Mean Time to Recovery) | < 1 hour | - |
| **Deploy Success Rate** | > 95% | - |
---
## Validation Checklist
After each deploy, verify:
- [ ] CI pipeline passed all checks
- [ ] Backend health check returns 200
- [ ] Frontend loads without errors
- [ ] Database migrations applied (if any)
- [ ] Salesforce Project record updated
- [ ] Asana task marked complete
- [ ] Slack notification sent
- [ ] No alerts in monitoring
---
## Troubleshooting
| Symptom | Likely Cause | Fix |
|---------|-------------|-----|
| CI fails on test | Code issue | Fix tests, push again |
| Deploy fails on Railway | Token expired | Refresh `RAILWAY_TOKEN` secret |
| Salesforce not updating | Wrong project key | Verify repo name matches `blackroad-{PROJECT_KEY}-*` |
| Asana task not completing | Task name doesn't match | Ensure task name contains "Deploy" |
| Health check fails | Backend not fully started | Increase sleep time in workflow |
---
## Related Docs
- [GitHub Actions: CI Workflow](../templates/github-actions/ci.yml)
- [GitHub Actions: Deploy Workflow](../templates/github-actions/deploy.yml)
- [GitHub Actions: Notify Stakeholders](../templates/github-actions/notify-stakeholders.yml)
- [Integration: GitHub → Salesforce](../integrations/github-to-salesforce.md)
- [New Client Kickoff Workflow](./new-client-kickoff.md)
---
## Philosophy
**"Deploy should be boring."**
The goal is to make deployments so reliable, automated, and well-monitored that they become **non-events**.
Every commit to `main` is a potential release. Every release updates all stakeholders automatically. No human should ever ask "Did this deploy?" or "What version is in production?"
The system should always know.