Maintenance & Operations Guide
Table of Contents
- 1. Security Rotation Policy (CI/CD)
- 2. Environment Hygiene (The “Clean Sweep”)
- 3. DevOps Architecture
- 4. Disaster Recovery
- 5. Observability & Monitoring
Project: Salesforce Platform Architect Portfolio
Owner: Ryan Bumstead
Version: 1.0
Date: MVP – Q1 2026
This document outlines the operational procedures required to maintain the security, stability, and “Green Build” status of the portfolio architecture.
1. Security Rotation Policy (CI/CD)
To demonstrate enterprise compliance standards, the JWT authentication keys used for GitHub Actions must be rotated annually.
- Rotation Schedule: Every 13 months (400-day certificate validity) with mandatory 30-day overlap window.
- Execution window: within 30 days of certificate expiry or during Q4 maintenance, whichever comes first
- Key Strength: 4096-bit RSA.
- Rationale: Eliminates calendar creep and guarantees zero risk of expired credentials
1.1 Rotation Procedure
1. Generate New Keys
Run the following OpenSSL commands in your terminal:
Click to view OpenSSL Commands
```bash # 1. Generate 4096-bit Private Key openssl genrsa -des3 -passout pass:SomePassword -out portfolio.pass.key 4096 # 2. Strip Password (for CI/CD Server) openssl rsa -passin pass:SomePassword -in portfolio.pass.key -out portfolio.key # 3. Generate Certificate (Valid for ~13 Months) openssl req -new -key portfolio.key -x509 -days 400 -out portfolio.crt ```2. Update Salesforce Connected App
- Log in to the Dev Hub Org.
- Navigate to App Manager > GitHub Actions CI > Manage.
- Click Edit Policies.
- Under Digital Signatures, upload the new portfolio.crt file.
- Save. (Note: Updates can take 2-10 minutes to propagate).
3. Update GitHub Secrets
- Navigate to Repo Settings > Secrets and variables > Actions.
- Update
SFDX_JWT_KEYwith the content of the new portfolio.key.
3. Gemini API Key: Rotate every 90 days. Update Named Credential Gemini_API
2. Environment Hygiene (The “Clean Sweep”)
The Developer Edition org shares space with Trailhead challenges and standard Salesforce metadata. To prevent “Pollution” from failing the CI/CD pipeline, strict separation is enforced.
2.1 Organization Rules
- Authorized Code: Only metadata present in
packages/is authorized. - Standard Sites: The “Portfolio” site must not utilize standard controllers (e.g., SiteLogin, CommunitiesSelfReg) as Authenticated Users are Out of Scope.
2.2 Emergency Cleanup Protocol
If standard Visualforce pages or Apex classes lock the deployment (Dependency Hell), use the “Lobotomy Strategy”:
- Decouple: Overwrite the blocking Visualforce Page with empty code to remove Apex references:
<apex:page>
<h1>Feature Disabled</h1>
</apex:page>
- Deploy: Push the empty page to break the dependency.
- Delete: Run the
sf project delete sourcecommand for the Apex Class.
3. DevOps Architecture
3.1 Local Development Commands
To prevent “Commit Shame” (failing pipelines after pushing), developers must execute validation scripts locally before pushing to GitHub. The project uses npm scripts to abstract complex CLI commands:
npm run scan: Executes the Salesforce Code Analyzer (PMD/ESLint) and outputs a human-readable scan-results.html report (visualized in browser). Success Criteria: 0 Critical Violationsnpm run delta: Generates the incremental package.xml in thechanged/folder by comparing local changes against origin/main.npm run validate: The “Golden Command”. It runs the delta generation and immediately triggers a check-only deployment to the org.- Note: Uses scripts/validate.js to handle “Empty Package” scenarios gracefully on Windows.
3.2 Pipeline Triggers
- PR Validation (pr.yml): Runs on Pull Requests modifying
packages/**.- Quality Gate: Apex Coverage > 90% (Hard Gate).
- Security Gate: Zero Critical PMD Violations.
- Production Deploy (deploy.yml): Runs on Push to main modifying
packages/**.
3.3 Pipeline Strategy: Delta Deployment
To ensure efficiency and avoid hitting Salesforce Metadata API limits, the pipeline utilizes a “Delta Deployment” strategy using sfdx-git-delta.
- Validation (pr.yml): Calculates the diff between the PR branch and origin/main. It generates a temporary package of only the changed components and runs a “Dry Run” deployment with RunLocalTests to ensure validity without altering the org.
- Production (deploy.yml): Calculates the diff between the current commit and the previous commit (HEAD~1). It deploys strictly the changed metadata to the Production environment.
- Destructive Changes: The pipeline is configured to respect
destructiveChanges.xml. If metadata is deleted from the repo, sfdx-git-delta will generate the destructive manifest, and the pipeline will automatically delete those components from the Org during deployment. - Cross-Platform Compatibility: The
package.jsonscripts leverageshxandrimrafto ensure all shell commands (mkdir, rm) execute consistently on both Windows (Local Development) and Ubuntu Linux (GitHub Actions Runners).
3.4 Org Persistence
- Heartbeat (keep-alive.yml): Runs daily at 08:00 UTC to execute a SOQL query against the org.
- Purpose: Prevents the Developer Edition from being marked inactive and deleted by Salesforce.
4. Disaster Recovery
4.1 Scenario: Deployment Failure
- Revert main branch to previous commit SHA.
- Trigger fresh deployment.
- Verify site health via Smoke Test suite / Manual Verification.
4.2 Scenario: Security Misconfiguration (Guest User)
- Symptom: PMD Scan or Health Check fails due to “Guest User Open Access”.
- Mitigation:
- Immediate Rollback: Revert
force-app/main/default/permissionsets/Guest_User.permissionset-meta.xmlto the previous commit. - Nuke & Rebuild: If unsure, delete the Permission Set from the org (
sf project delete source) and redeploy themainbranch version.
- Immediate Rollback: Revert
4.3 Scenario: GitHub Rate Limit Exhaustion
- The system uses
GitHub_Cache__cto store API responses. If the API fails (429/500), the ApexGitHubServicewill automatically serve cached data.
5. Observability & Monitoring
5.1 Quota Monitoring (Automated)
- Scheduled Apex Job runs at 23:00 UTC.
- Logic: Checks
local.AIMetrics. - Alert: Emails
Owner_Email__cif Gemini usage > 1,000 requests.
// Check Org Cache for Gemini usage
Cache.Org orgCache = Cache.Org.getPartition('local.AIMetrics');
Integer todayCount = (Integer) orgCache.get('GeminiDailyCount_' + System.today().format());
if (todayCount != null && todayCount > 1200) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[]{ Portfolio_Config__mdt.getInstance('Default').Owner_Email__c });
mail.setSubject('Gemini Quota Alert: ' + todayCount + ' requests today');
Messaging.sendEmail(new Messaging.SingleEmailMessage[]{ mail });
}