Generic Salesforce Prompt

Test Class

Review the Apex test class I have open (or named below):

First read the class(es) it actually tests so you judge behavior from the source, not from the test alone. Then evaluate against the points below and REPORT findings only — don’t rewrite yet.

Best practices to check:

  • @TestSetup for shared data instead of repeated setup in every method
  • Test.startTest()/Test.stopTest() wrapping the code under test (limit reset + async flush)
  • Real assertions via the Assert class with messages — asserting actual outcomes, not just “no exception thrown” or coverage-only runs
  • No SeeAllData=true; data built in-test (flag it if a test data factory exists in the org and isn’t being used)
  • System.runAs() where sharing, FLS, or profile/perm-set context matters
  • Callouts mocked with HttpCalloutMock / Test.setMock
  • No hardcoded IDs
  • Method names that describe the scenario being tested

Scenario coverage — flag anything NOT tested:

  • Bulk (200+ records) to catch governor limits and non-bulkified code
  • Negative / error paths — invalid input, exceptions asserted explicitly (assert the message/type, not just that one was thrown)
  • Null and empty inputs
  • Boundary values
  • Different user permissions / profiles
  • Recursion or re-entrant paths (if trigger-related)
  • Async paths (@future, Queueable, Batch, Schedulable) actually exercised, not just enqueued

Output:

  1. One-paragraph summary of what the class covers well.
  2. Prioritized gap list (High/Med/Low): each with the specific missing scenario and why it matters.
  3. Concrete test methods to add — signature + one line on what each asserts.

Ask before producing the full rewritten class.

Code Audit

Audit the Salesforce component(s) I have open or named below:

Read the actual source of everything referenced (classes, triggers, Flows, custom metadata, named credentials) before judging — assess real behavior, not assumptions. REPORT findings only; do not rewrite anything yet.

For EACH finding give: what’s wrong, where (file + line/element), why it matters, the concrete fix, and a severity tag (defined at the bottom). For reliability/critical items also state whether it FAILS ALWAYS, FAILS UNDER LOAD, or FAILS INTERMITTENTLY.

────────────────────────────────────────

  1. BEST PRACTICES
  • Named Credentials instead of hardcoded URLs / endpoints / session IDs
  • No hardcoded IDs anywhere (email template IDs in Flows, record type IDs, queue IDs, profile IDs, org-specific IDs)
  • Test classes: @TestSetup, startTest/stopTest, real Assert-class assertions with messages, bulk (200+), negative + null paths, System.runAs, mocked callouts, no SeeAllData=true
  • Recursion guard on triggers (static flag / handler pattern), re-entrancy safe
  • Chain Queueables for large volumes instead of hitting limits; correct async pattern (Batch vs Queueable vs future)
  • Unused code: dead methods, unreferenced variables, commented-out blocks, unused classes/fields, orphaned Flows
  • One trigger per object + handler pattern; no business logic directly in triggers
  • Bulkification — no SOQL/DML in loops
  • Separation of concerns, naming conventions

────────────────────────────────────────

  1. CRITICAL / RELIABILITY Data integrity & partial failure
  • Database.update/insert(records, false) for partial save — verify failed rows are captured via getErrors() and logged/surfaced, not silently dropped
  • allOrNone semantics mismatch: bulk DML that SHOULD be all-or-nothing running as partial (or vice versa) — silent data divergence
  • UNABLE_TO_LOCK_ROW / row-lock contention under concurrent updates (parent rollups, ownership changes, roll-up summary + trigger racing) — no retry/ordering strategy
  • Upsert on a non-unique external ID — silent wrong-record updates
  • Missing null checks on relationship traversal (a.Parent__r.Field__c when Parent is null) — NPE kills the whole transaction/batch Governor limits under real volume
  • SOQL/DML inside loops — dies at 101 queries / 150 DML on bulk
  • Non-selective query on large object (>200k rows) with non-indexed filter — full table scan timeout, not just slowness
  • Queries returning >50k rows, DML >10k rows in one transaction
  • Heap blowup: Batch stateful accumulating collections across batches; large query results held in memory
  • CPU time limit from nested loops / recursive trigger re-entry — intermittent, load-dependent, hard to reproduce Async correctness
  • Uncommitted work pending before callout (DML then callout in same transaction) — CalloutException
  • Mixed DML (setup object like User/Group + non-setup in same transaction) without async separation
  • @future called from batch, or future-from-future — runtime error
  • Queueable/future chaining with no depth or volume guard — hits async limits or stack depth; large volumes not chained into fresh Queueable transactions
  • Test.stopTest() missing/misplaced so async never flushes — tests pass but async path is untested (false coverage)
  • Non-idempotent async/integration path — retry or duplicate delivery double-processes (double charges, duplicate records, double emails) Order of execution & recursion
  • Apex trigger AND Flow/Process Builder on same object both mutating — double processing, unpredictable field values, cross-engine recursion
  • Recursion guard missing or per-transaction static not reset correctly — infinite loop / repeated DML
  • Logic depending on order-of-execution assumptions that break when new automation is added
  • Roll-up summary + trigger recalculation loops Config & metadata risks
  • Custom Metadata field manageability DeveloperControlled where it must be SubscriberControlled — subscribers can’t configure in managed context; blocks the whole feature
  • Hardcoded IDs (email template, record type, queue, profile) — breaks on deploy to any other org
  • Scheduled Apex holding a stale class version / can’t be edited while scheduled — deploy blocked or running old logic
  • Hardcoded session ID / endpoint instead of Named Credential — breaks on refresh, security exposure

────────────────────────────────────────

  1. PERFORMANCE
  • SOQL/DML in loops, non-selective queries, missing selective filters/indexes
  • Queries pulling more fields/rows than needed; SELECT of unused fields
  • Synchronous work that should be async; unnecessary recursion or re-processing
  • Heap / CPU risk on large data volumes
  • Repeated queries that could be cached/consolidated; N+1 query patterns
  • Missing LIMIT on queries that feed UI or single-record logic

────────────────────────────────────────

  1. ERROR HANDLING & LOGGING
  • Silent failures — async jobs, Flows, callouts failing with no log or user feedback
  • Empty catch blocks or catch(Exception e) that swallows everything — the #1 silent killer, especially in Queueable/Batch where there’s no UI to surface it
  • catch that only System.debug()s — invisible in production; no persisted record
  • Structured logging to a custom log object / platform event (survives rollback via platform event) — not just System.debug
  • Partial-save failures (getErrors()) actually logged with the failing record Id + reason, not just counted
  • Batch: execute() failures isolated per-batch; finish() reports what failed; errors don’t just vanish between chunks
  • Flow fault paths present on every element that can fail (DML, callout, Get with assignment) — not just the happy path
  • User-facing errors meaningful (addError with a real message on triggers, not raw stack trace to end users)
  • Exceptions re-thrown or logged before swallowing — never both caught and ignored
  • Callout failures: timeout, non-200, and malformed-response all handled distinctly, not one blanket catch

────────────────────────────────────────

  1. SECURITY
  • CRUD/FLS enforcement: WITH SECURITY_ENFORCED on SOQL, or Security.stripInaccessible, or explicit isAccessible/isUpdateable checks — especially before DML on user-supplied fields
  • Sharing declared explicitly (with sharing / without sharing / inherited sharing) on every class — and “without sharing” justified, not accidental
  • Experience Cloud / Guest user exposure: guest user sharing rules, object/field access, and “without sharing” classes reachable by guest — the most common real-world data leak; check any class an unauthenticated user can invoke
  • SOQL injection in dynamic queries — bind variables or String.escapeSingleQuotes on all user input
  • No secrets in code or debug logs; Named Credential or Protected Custom Metadata/Custom Setting for keys/tokens
  • @AuraEnabled methods: FLS/CRUD not automatically enforced — verify each one checks access; these are directly callable by the client
  • Serialized data / VF view state not exposing sensitive fields
  • Object/field access assumptions that hold for admin but break for the actual running-user profile

────────────────────────────────────────
OUTPUT FORMAT — group every finding under one of these three headers:

🔴 CRITICAL — data loss, security hole, silent failure in production, or breaks under real volume. Must fix before ship.
🟠 BLOCKING — violates a hard standard (hardcoded IDs, DeveloperControlled metadata that must be Subscriber, missing recursion guard, no error logging, missing FLS/sharing). Fix before audit sign-off.
🟢 NICE TO HAVE — style, minor cleanup, unused code, naming, low-impact optimization.

Within each header, order by impact. Line format for each item:
[dimension] file:line — problem (FAILS ALWAYS/UNDER LOAD/INTERMITTENTLY where relevant) → fix

End with a one-line count: X critical, Y blocking, Z nice-to-have.
Do not fix anything yet — wait for me to pick which items to action.

If you’re auditing a single component in isolation and can’t see something it depends on (handler class, referenced Flow, custom metadata), say so explicitly rather than assuming — flag it as “unverified: needs in workspace” instead of passing or failing it.

Audit as architect
You are a senior Salesforce Technical Architect doing a deep technical audit of the org whose metadata is in this workspace (SFDX project). Find real problems, prove each one with evidence, and recommend concrete fixes with corrected code where useful.

GROUND RULES
- Read-only. Do NOT modify, delete, deploy, or run anonymous Apex. Do NOT run Apex tests unless I explicitly approve.
- Allowed against the org: read-only `sf` commands and SOQL/Tooling API queries (e.g. `sf data query -q "..." --use-tooling-api -o <alias>`). Ask me for the org alias before the first query.
- Every finding needs evidence: file path + line numbers + short excerpt, or the query you ran + result.
- If something can't be verified from metadata or queries, list it under "Needs confirmation". Don't guess.
- Skip namespaced managed package code except to list dependencies.
- Work folder by folder on large orgs. Keep notes in /audit/_progress.md so you can resume.

==================================================
PHASE 0 — INVENTORY & ORG BASELINE
==================================================
1. Count and list: Apex classes, triggers, test classes, LWC, Aura, VF pages/components, flows by type (record-triggered before/after save, scheduled, platform event, screen, autolaunched), Process Builders, Workflow Rules, validation rules, custom objects/fields, permission sets, permission set groups, profiles, named credentials, external credentials, remote site settings, connected apps, auth providers, certificates, platform events, CDC entities, custom metadata types, custom settings, static resources.
2. API versions: list every component's apiVersion, flag anything below current minus 3 years (~v55).
3. Run if available and save to /audit/scanner/:
   - `sf code-analyzer run --workspace force-app --rule-selector Recommended --output-file audit/scanner/results.html` (PMD, ESLint, RetireJS, Flow scanner, Graph engine for CRUD/FLS path analysis). If not installed, give me the install command and continue manually.
4. Read-only org queries (Tooling API where noted):
   - Coverage: `SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate` (tooling) → flag anything under 75% and overall org coverage
   - `SELECT Name, ApiVersion, LengthWithoutComments, Status FROM ApexClass WHERE NamespacePrefix = null` (tooling) → largest classes = refactor candidates
   - Failed async jobs last 30 days: `SELECT ApexClass.Name, JobType, Status, ExtendedStatus, NumberOfErrors, CreatedDate FROM AsyncApexJob WHERE Status = 'Failed' AND CreatedDate = LAST_N_DAYS:30`
   - Scheduled jobs: `SELECT CronJobDetail.Name, CronExpression, State, NextFireTime FROM CronTrigger`
   - `SELECT Action, Section, CreatedBy.Name, CreatedDate FROM SetupAuditTrail WHERE CreatedDate = LAST_N_DAYS:90` → direct-in-prod changes
   - `sf org list limits -o <alias>` → flag any limit over 70% used (API requests, data/file storage, async Apex executions, platform events)
   - Record counts on key objects (Account, Contact, Opportunity, Case, Task, custom objects) → mark anything over 1M as LDV

==================================================
PHASE 1 — APEX
==================================================
Bulkification & limits
- SOQL/DML/callouts inside for/while loops (incl. inside methods called from loops — trace the call chain)
- Nested loops over lists where a Map<Id, SObject> lookup should be used (O(n²))
- Schema.getGlobalDescribe() or describe calls inside loops; repeated describes without caching
- Queries without WHERE/LIMIT on large objects; SELECT of many unused fields (heap)
- Large result sets not using SOQL for-loops; heavy JSON/String building in loops (heap/CPU)
- Aggregate work done in Apex that should be AggregateResult / GROUP BY

Triggers
- More than one trigger per object; logic in trigger body; no handler framework (e.g. fflib, Kevin O'Hara, TDTM in NPSP)
- Recursion guards using a static Boolean (breaks on 200-record chunking and multi-chunk DML) instead of Set<Id> of processed records
- Modifying Trigger.new in after context; DML on same records in after trigger instead of before-save field updates
- No bypass mechanism (custom permission / custom metadata switch) for data loads
- Missing handling for all contexts that matter (undelete, after delete for rollups)

Query performance / selectivity
- Filters on non-indexed fields, leading-% LIKE, !=, NOT IN, NULL comparisons, formula fields in WHERE on large objects
- Suggest custom indexes / External ID fields where needed; flag queries likely to hit "non-selective query against large object" (>200k rows)
- Data skew risk: code or automation that updates many children of one parent (UNABLE_TO_LOCK_ROW), single owner of >10k records, lookup skew
- FOR UPDATE usage and lock contention

Security in Apex
- Classes without `with sharing` / `inherited sharing`; `without sharing` with no comment justifying it
- No CRUD/FLS enforcement: missing `WITH USER_MODE`, `AccessLevel.USER_MODE` on Database methods, or `Security.stripInaccessible`; old `WITH SECURITY_ENFORCED` usage
- Dynamic SOQL built with string concatenation of user input → SOQL injection. Recommend `Database.queryWithBinds` or bind variables; `String.escapeSingleQuotes` only as fallback
- @AuraEnabled / @RemoteAction / @RestResource / global / webservice methods: list every one, check sharing + CRUD/FLS + input validation; flag `cacheable=true` methods that perform DML
- Sensitive data written to System.debug (tokens, PII)

Hardcoding & config
- Hardcoded Ids (15/18-char patterns like '001', '005', '00G', '012'), record type names/Ids, profile names, usernames, emails, org URLs, endpoints
- Config that should live in Custom Metadata Types (deployable) vs Custom Settings vs Custom Labels

Async
- @future used where Queueable is better; @future called from batch/future (runtime error)
- Queueable chains with no depth control; no Transaction Finalizer for retry/error capture
- Batch: scope size, Database.Stateful misuse (heap), start() using Iterable instead of QueryLocator for large data, no error logging in finish()
- Schedulers that enqueue batches without checking for already-running jobs
- Mixed DML (setup + non-setup objects) not isolated

Error handling & logging
- Empty catch blocks, catch(Exception e) that swallow, generic error messages to users
- No logging framework (e.g. Nebula Logger) or a custom log object; Database.insert(records, false) results never inspected

Code quality
- Classes over ~500 lines, methods over ~80 lines, god classes, no service/selector/domain separation
- Dead code: classes/methods with zero references (search across Apex, LWC, Aura, VF, flows, custom metadata)
- Test.isRunningTest() branches in production code

Tests
- Tests with no System.assert*/Assert.* calls, or only asserting not-null (coverage padding)
- SeeAllData=true; no @TestSetup; no test data factory; hardcoded Ids in tests
- No bulk test (200+ records), no negative tests, no System.runAs for permission scenarios
- Callout classes without HttpCalloutMock / StaticResourceCalloutMock
- Missing Test.startTest()/stopTest() around async code

==================================================
PHASE 2 — LWC / AURA / VISUALFORCE
==================================================
- Imperative Apex where @wire with cacheable=true or Lightning Data Service (getRecord, getFieldValue, updateRecord, lightning-record-form) would do
- Missing refreshApex / notifyRecordUpdateAvailable after DML → stale UI
- @wire with reactive params that change often (no debounce) → excessive server calls
- Apex calls in renderedCallback or loops; heavy logic in getters re-running every render
- lightning-datatable / lists with no pagination or infinite loading on large data
- Mutating @api properties; events with bubbles+composed overused; no Lightning Message Service where cross-DOM communication is needed
- innerHTML / lwc:dom="manual" with unsanitized data; third-party JS libs (check versions via RetireJS for known CVEs); oversized static resources
- Is Lightning Web Security enabled vs Locker? Any components that depend on Locker behavior
- No error handling on Apex promises; console.log left in; missing Jest tests
- Aura and VF components that should be migrated to LWC (list with effort estimate)
- VF: missing escape="false" review, unescaped merge fields, controllers without sharing, CSRF on GET actions

==================================================
PHASE 3 — AUTOMATION (FLOW / PB / WFR)
==================================================
- Active Process Builders and Workflow Rules → retired, list each with suggested Flow replacement
- Per object: map all triggers + before/after-save flows + validation rules + duplicate rules + assignment/escalation rules and assess order-of-execution conflicts and recursion
- Multiple record-triggered flows per object without Trigger Order set
- Get Records / Create / Update / Delete inside Loop elements (should collect into collection then single DML)
- Get Records storing all fields when a few are needed
- Missing fault paths on DML, callout, and Apex action elements
- Field updates on the triggering record done in after-save (should be before-save)
- Entry criteria missing or not using "only when record is updated to meet criteria" / $Record__Prior → runs on every edit
- Flows running in System Context Without Sharing — justify each, especially screen flows exposed in Experience Cloud
- Hardcoded Ids in flows (record types, queues, users)
- Invocable Apex not bulk-safe (must accept and return List<>)
- Scheduled flows / scheduled paths on large record sets
- Same business logic in both Flow and Apex
- Old flow API versions; inactive flow versions piling up

==================================================
PHASE 4 — DATA MODEL & LDV
==================================================
- Objects with high field counts (>300 near limit), fields unused anywhere (code, flows, layouts, reports where visible, formulas)
- Cross-object formula spanning near the 10-relationship limit; roll-up summary count near limit; DLRS usage
- Lookup vs master-detail choices causing sharing or rollup problems
- External ID fields missing on objects that are integrated (needed for upsert)
- Validation rules without bypass (custom permission) → break integrations and data loads
- Field history tracking near the 20-field limit on key objects
- LDV objects without archiving strategy (Big Objects, external archive, data retention)
- Picklists that should be Global Value Sets; restricted picklist settings

==================================================
PHASE 5 — SECURITY & ACCESS
==================================================
- Sharing model: OWD per object, number of sharing rules, role hierarchy depth, Apex managed sharing usage
- Profiles holding permissions that should be in permission sets / permission set groups
- Dangerous permissions and who has them: Modify All Data, View All Data, Author Apex, Customize Application, Manage Users, View Setup, API Enabled, Export Reports
  Query: `SELECT Assignee.Name, PermissionSet.Name FROM PermissionSetAssignment WHERE PermissionSet.PermissionsModifyAllData = true`
- Integration users: should be API-only, using the Salesforce Integration user license / Minimum Access profile with scoped permission sets — flag integrations running as a named admin user
- Connected apps: "All users may self-authorize", "Relax IP restrictions", overly broad OAuth scopes (full, refresh_token with no expiry), no IP ranges for integration users
- Session settings, MFA enforcement, login IP ranges, password policy, Health Check score (ask me to share it if it can't be read)
- Experience Cloud / guest user: guest-accessible Apex classes, guest sharing rules, "Secure guest user record access", public pages exposing records
- CSP Trusted Sites with unsafe-inline / wildcard; CORS allowlist with wildcards; clickjack protection settings
- Secrets in code, custom settings, custom metadata, custom labels, static resources (API keys, passwords, tokens, client secrets)
- Platform Encryption / Shield usage on sensitive fields; Event Monitoring if available

==================================================
PHASE 6 — INTEGRATIONS (go deep here)
==================================================
Endpoints & credentials
- Any HttpRequest.setEndpoint() with a literal https:// URL instead of `callout:NamedCredential/...` → flag as High
- Remote Site Settings in use → each one usually means a hardcoded endpoint; map each to the code using it
- Legacy Named Credentials vs new Named Credential + External Credential + Principal model; recommend migration
- Auth headers built manually in Apex (Basic auth, Bearer tokens, API keys concatenated into headers) instead of Named/External Credential with custom headers and formula merge fields
- Tokens or secrets stored in custom settings/metadata/labels; OAuth token refresh logic handwritten in Apex
- Certificates: list them with expiry dates, flag anything expiring within 90 days; self-signed certs in production
- Same endpoint hardcoded differently across sandbox/prod (no environment switching)

Callout patterns
- Callouts from triggers (not allowed synchronously), callouts after uncommitted DML ("You have uncommitted work pending")
- No explicit setTimeout (default 10s; max 120s); no retry/backoff; no idempotency key on retried POSTs
- Over 100 callouts per transaction risk; synchronous callouts in UI where Continuation or async would be better
- Response handling: no status code checks, no handling of 4xx/5xx/timeouts, JSON.deserializeUntyped with blind casts, large payloads hitting heap (6MB sync / 12MB async)
- Wrapper classes vs untyped maps; no request/response logging (or logging that stores PII/tokens)
- No HttpCalloutMock tests covering error responses

Inbound
- @RestResource / webservice classes: auth model, running user, sharing, CRUD/FLS, bulk handling (array payloads), input validation, consistent error response format
- Inbound integrations doing record-by-record API calls instead of Composite / Composite Graph / sObject Collections / Bulk API 2.0
- Upserts without External ID → duplicate risk

Events & async integration
- Platform Events: publish behavior (Publish After Commit vs Immediately) appropriate? Subscriber triggers with no error handling, no setResumeCheckpoint, no retry via EventBus.RetryableException
- CDC: which entities enabled, subscribers' error handling, event allocation usage
- Outbound Messages still active (legacy)
- Middleware (MuleSoft, Boomi, Zapier, Workato, etc.) — identify from integration users, connected apps, and named credentials; flag unknown connected apps with recent usage

API consumption
- API request usage vs limit; identify top consumers (connected app / user) if accessible
- Integrations polling Salesforce on a short interval where CDC/Platform Events fit better

==================================================
PHASE 7 — DEVOPS & MAINTAINABILITY
==================================================
- sfdx-project.json structure, .forceignore, package directories; unlocked packages or monolith
- CI/CD present? (GitHub Actions, Bitbucket Pipelines, Copado, Gearset config files); test level used in deployments
- Prettier/ESLint/PMD configs present; PR checks
- Signs of direct-in-prod changes (SetupAuditTrail vs repo)
- Naming conventions consistency; documentation/README; apex doc comments

==================================================
DELIVERABLES (write to /audit/)
==================================================
1. audit-report.md
   - Executive summary (plain language, 1 page): health score /10 per area with one-line reason, overall score, top 5 risks with business impact
   - Findings table: ID | Area | Severity | File:Line or Query | Issue | Evidence | Fix | Effort (S/M/L)
   - Detailed findings by phase with code excerpt + corrected example
   - Needs confirmation list
   - Remediation roadmap: Quick wins (<1 day), Short term (1–4 weeks), Strategic (framework adoption, PB/WFR migration, Named Credential migration, LWC migration)
2. findings.csv — same columns as the table
3. automation-map.md — per object: triggers, flows (with trigger order), validation rules, and execution order
4. integration-inventory.md — every integration: direction, endpoint, auth method, Named Credential (Y/N), running user, error handling (Y/N), test mock (Y/N), risk rating
5. security-access.md — high-risk permissions and who holds them, connected apps, guest exposure

Severity:
- Critical: security exposure, secrets in code, data loss risk, likely to fail in production now
- High: governor limit risk at realistic volume, hardcoded endpoints/credentials, non-selective queries on LDV, missing CRUD/FLS on exposed methods
- Medium: tech debt, retired automation, weak tests, missing error handling
- Low: style, naming, minor cleanup

Start with Phase 0. Ask me for the org alias, then show the inventory and baseline summary before moving on. After each phase, give a short summary and continue to the next.