Skip to content

tilman-d/salesforce-webtocase

Repository files navigation

Web-to-Case with Attachments

A Salesforce app that lets you create public web forms that submit Cases with file attachments. Built for the AppExchange.


Next Steps

Blocked: Remove "Approve Third-Party Access" Install Prompt

Status: Partner Community case filed (2026-02-15), awaiting Salesforce response.

The package contains a deactivated RemoteSiteSetting (Google_reCAPTCHA) that triggers an "Approve Third-Party Access" prompt on every install, even though isActive=false. We can't remove the component from the 2GP managed package without Salesforce granting removal permission.

Once Salesforce responds:

  1. Delete force-app/main/default/remoteSiteSettings/Google_reCAPTCHA.remoteSite-meta.xml
  2. Create new package version, promote, install — verify prompt is gone
  3. Update install URL in this README

What we tried that didn't work:

  • Changing the URL to login.salesforce.com (first-party) — prompt still fires for any RemoteSiteSetting regardless of URL
  • Setting isActive=false — prompt still fires

Test Install in Dev Hub (Manual)

The package v1.9.0.1 has been installed in the dev hub org (devhub / dietrich-dev-ed).

  1. Log in to the dev hub: https://dietrich-dev-ed.develop.my.salesforce.com
  2. Assign the Web-to-Case Admin permission set to your user (Setup → Permission Sets → Web-to-Case Admin → Manage Assignments)
  3. Open the Web-to-Case Forms app from the App Launcher
  4. Run through the Setup Wizard (select/create a Site, configure Guest User permissions)
  5. Create a test form in Form Manager and verify end-to-end submission
  6. Test the embeddable widget on an external page (add domain to Allowed Domains, use embed snippet)

AppExchange Submission

  1. Submit for AppExchange security review via the Salesforce Partner Community
  2. Address any security review feedback

Deferred to v2

  • Multi-file upload (drag & drop)
  • Custom field types (picklist, date, checkbox)
  • Form analytics / submission tracking
  • Email notifications on submission
  • Re-enable reCAPTCHA (uncomment code across 12+ files — see Re-enabling reCAPTCHA for v2)
  • reCAPTCHA v3 testing (create v3 keys, test score-based blocking, test type switching)
  • Raise image compression target from 0.7MB to ~3MB (chunked uploads now support up to 4MB — no need to crush image quality to avoid chunking)

Completed: AppExchange Release Checklist

  • Increase test coverage for WebToCaseNonceService (51% → 81%)
  • Increase test coverage for SetupWizardController (50% → 86%)
  • Register namespace prefixcaseform
  • Create managed package — Package ID 0Hod20000000XlZCAU
  • Create package version04td2000000KAPpAAO (v1.7.0.1, all classes pass)
  • Promote package version — Released (v1.7.0.1)
  • Test install in dev hub — Successfully installed/upgraded in dietrich-dev-ed

v1.9.0 (Released)

  • reCAPTCHA code removed — all captcha logic commented out with /* v2: reCAPTCHA ... */ markers; Remote Site Setting deactivated (eliminates "Approve Third-Party Access" install prompt)
  • File upload fixessubmitForm() uses FirstPublishLocationId for Guest User access; SYNC_CHUNK_LIMIT reduced 3 → 2 to avoid 6MB heap limit; FileAssemblyQueueable uses FirstPublishLocationId; removed invalid CRUD checks on Content objects
  • Setup banner real-time updatesformAdminApp.js uses imperative Apex + LMS subscription so banner updates without page refresh after wizard completion
  • Package version04td2000000KDAnAAO (v1.9.0.1), promoted, installed in devhub

Done (Earlier Sessions)

  • Security fixes deployed (IDOR on uploadFileChunk, nonce replay, SOQL injection, chunk validation)
  • checkUploadStatus IDOR check added (authorization required before status polling)
  • authorizeCaseForUpload made conditional on Enable_File_Upload__c
  • SOQL injection false positives resolved (converted dynamic SOQL to static queries)
  • Empty catch blocks fixed (added System.debug logging)
  • ESLint violations fixed in caseFormScript.js and caseFormWidget.js
  • Org-specific metadata removed (CORS origins, CSP trusted sites, Site config)
  • .forceignore created to prevent re-pulling org-specific metadata
  • WebToCaseNonceService test coverage: 51% → 81% (14 new tests)
  • SetupWizardController test coverage: 50% → 86% (12 new tests)
  • 257/257 tests passing
  • FlexiPage deployment blocker fixed (namespace caseform: component references)
  • DOM XSS sinks eliminated (innerHTMLtextContent for error messages)
  • Server error message leakage fixed (generic messages to client)
  • Explicit sharing declarations added (ErrorLogger, WebToCaseRateLimiter)
  • AggregateResult namespace robustness fix (FormAdminController)

Scanner Notes

  • 0 Critical/High violations on custom code (Apex SOQL injection + empty catch blocks fixed, JS ESLint clean)
  • 59 pmd:ApexCRUDViolation remaining — all false positives (PMD can't detect manual assertAccessible/assertCreateable/stripInaccessible enforcement). Won't fail security review.
  • 19 violations in imageCompression.js — third-party minified library, not our code

🧪 MANUAL TESTING REQUIRED: Custom HTML Connect Mode + Extended CSS Variables (v0.6.0)

The following items need manual verification in the dev org:

Connect Mode (WebToCaseForm.connect())

  • Create a standalone HTML page with a custom form layout
  • Include the widget script and call WebToCaseForm.connect() with correct apiBase/formName
  • Verify form submission creates a Case with correct field values
  • Verify file upload works via fileInputSelector option
  • Verify CAPTCHA renders in the user-provided container (if enabled)
  • Verify validation errors appear in the user's error container and use aria-invalid
  • Verify success state hides the form and shows the success container with case number in [data-wtc-case-number]
  • Verify destroy() cleans up event listeners (test re-initialization in SPA-like scenario)
  • Verify console warnings appear for missing name attributes on required fields

Extended CSS Variables (Widget Mode)

  • Embed the widget on a test page and set --wtc-container-max-width, --wtc-container-padding — verify they take effect
  • Test title variables: --wtc-title-font-size, --wtc-title-font-weight, --wtc-title-margin
  • Test description variables: --wtc-description-color, --wtc-description-font-size
  • Test label variables: --wtc-label-font-size, --wtc-label-font-weight, --wtc-label-color
  • Test input variables: --wtc-input-padding, --wtc-input-font-size
  • Test field gap: --wtc-field-gap
  • Test submit button: --wtc-submit-color, --wtc-submit-background, --wtc-submit-padding, --wtc-submit-font-size, --wtc-submit-border-radius
  • Test success/error: --wtc-success-background, --wtc-success-border, --wtc-error-background, --wtc-error-border

Admin UI (Embed Code Section)

  • Verify scoped tabs (Widget / Custom HTML / iframe) render with light blue active background
  • Verify "Generate Embed Code" button is required before tabs appear
  • Verify tabs show immediately when loading a saved form with existing allowed domains
  • Verify Custom HTML tab generates correct HTML snippet with actual form fields
  • Verify Custom HTML tab generates correct CSS snippet scoped to form ID
  • Verify Custom HTML tab generates correct JS snippet with connect() call
  • Verify all Copy buttons work in all three tabs

Regression

  • Verify existing WebToCaseForm.render() widget still works identically after the mixin refactor
  • Verify iframe embed still works

🧪 MANUAL TESTING REQUIRED: reCAPTCHA Issues

Note: reCAPTCHA UI is hidden for v1 MVP (v0.7.0). These tests apply only after re-enabling for v2.

reCAPTCHA v3 Testing (deferred to v2)

  • Create reCAPTCHA v3 keys at Google Admin Console (select "v3")
  • Configure v3 in Setup Wizard (select "v3 Score-based" type)
  • Test form submission with v3 - verify invisible badge appears
  • Verify low-score submissions are blocked (use VPN/incognito to simulate bot-like behavior)
  • Test switching between v2 Checkbox, v2 Invisible, and v3 Score-based

Quick Status

Namespace caseform
Version v1.9.0.1 (Released)
Phases Complete 0-4 (MVP, Admin UI, Setup Wizard, reCAPTCHA, Embeddable Widget)
Next Up Manual test install verification → AppExchange security review submission
Dev Org devorg (tilman.dietrich@gmail.com.dev)
GitHub https://github.com/tilman-d/salesforce-webtocase
Dev Hub devhub (tilman.dietrich@gmail.com.freelance)
Package ID 0Hod20000000XlZCAU
Package Version 04td2000000KDAnAAO (v1.9.0.1)
Install URL https://login.salesforce.com/packaging/installPackage.apexp?p0=04td2000000KDAnAAO
Last Change v1.9.0 — reCAPTCHA removal, file upload fixes, setup banner real-time updates

Why This Exists

Salesforce's native Web-to-Case doesn't support file attachments. This app solves that problem with:

  • Configurable forms stored as custom objects
  • Public Visualforce page for form rendering
  • File attachments via ContentVersion/ContentDocumentLink
  • LWC Admin UI for managing forms without using Setup
  • Google reCAPTCHA v2/v3 for spam protection (hidden in v1 MVP, re-enable for v2)
  • Error logging for debugging

Project Status

Phase Description Status
Phase 0 MVP - Core form submission ✅ Complete
Phase 1 Admin UI (LWC form builder) ✅ Complete
Phase 2 Post-Install Setup Wizard ✅ Complete
Phase 3 reCAPTCHA integration (code commented out for v1, re-enable for v2) ✅ Complete
Phase 4 Embeddable widget for external websites ✅ Complete
Phase 5 Multi-file upload, custom field types 🔜 Next up

What's Built (Phase 0)

Custom Objects

  • Form__c - Form configuration (name, title, description, file upload settings)
  • Form_Field__c - Field definitions (label, type, Case field mapping, required, sort order)
  • Error_Log__c - Error logging for debugging

Apex Classes

  • CaseFormController - Main controller for form rendering and submission
  • ErrorLogger - Utility for logging errors

Visualforce

  • CaseFormPage - Public form page that renders dynamically based on Form__c configuration

Static Resources

  • caseFormStyles.css - Clean, responsive form styling
  • caseFormScript.js - Client-side validation and form submission

What's Built (Phase 1)

LWC Admin UI

Access via the Form Manager tab in Salesforce.

Features:

  • List all forms with field counts and created date
  • Sortable columns - click column headers to sort (Form Name, Title, Fields, Active, Created)
  • Create new forms
  • Edit existing forms (click form name to edit)
  • Delete forms with confirmation modal
  • Toggle form active/inactive status
  • Add, edit, delete, and reorder fields
  • Preview forms with "View Live" button
  • URL hash routing for bookmarkable links (#new, #edit/{formId})
  • Form name validation (unique, URL-safe)
  • Toast notifications for success/error feedback

Apex Classes

  • FormAdminController - CRUD operations for Form__c and Form_Field__c with wrapper classes
  • FormAdminControllerTest - 33 unit tests, 94%+ code coverage

LWC Components

  • formAdminApp - Main container with list view, routing, and delete modal
  • formDetail - Form settings editor with inline field management

Metadata

  • Form_Manager.flexipage-meta.xml - Lightning App Page
  • Form_Manager.tab-meta.xml - Navigation tab

Permission Set Updates

  • Added FormAdminController class access
  • Added Form_Manager tab visibility

What's Built (Phase 2)

Post-Install Setup Wizard

Access via the Setup Wizard tab or the Web-to-Case Forms app in the App Launcher.

5-Step Wizard Flow (v1 MVP):

  1. Welcome - Precondition checks (My Domain, admin permissions, Sites enabled)
  2. Select Site - Choose from existing Sites or get instructions to create one
  3. Configure - Auto-configure Guest User object/field permissions with security acknowledgment
  4. Verify - Manual configuration instructions for Apex class and VF page access with validation
  5. Complete - Success message + "What's Next" box with link to Form Manager
    • "Test Your Setup" box hidden for v1 (re-enable via showTestSetupBox getter)

Note: The reCAPTCHA step (previously step 5) is hidden for v1 MVP. All reCAPTCHA code is commented out (v0.8.2) with /* v2: reCAPTCHA ... */ markers — see Re-enabling reCAPTCHA for v2 to restore.

Features:

  • Automatic detection of active Salesforce Sites
  • One-click permission configuration for Guest User profile
  • Support for both Enhanced Profile UI and Classic Profile UI instructions
  • Validation to ensure all permissions are correctly configured
  • reCAPTCHA configuration UI - Enter Site Key and Secret Key without Anonymous Apex (hidden in v1 MVP)
  • Sample "Contact Support" form creation
  • Dynamic public URL generation (works with Enhanced Domains)

Apex Classes

  • SetupWizardController - Site detection, permission configuration, validation, sample form creation, reCAPTCHA settings management
  • SetupWizardControllerTest - Unit tests with coverage (41 tests)

LWC Components

  • setupWizard - Multi-step wizard with progress indicator
  • setupStatus - Configuration Status Dashboard (embedded in Setup Wizard page, hidden when unconfigured, auto-refreshes via LMS when wizard completes)

Metadata

  • Setup_Wizard.flexipage-meta.xml - Lightning App Page
  • Setup_Wizard.tab-meta.xml - Navigation tab
  • Web_to_Case_Forms.app-meta.xml - Lightning App (consolidates all functionality)
  • SetupStatusRefresh.messageChannel-meta.xml - LMS channel for wizard→dashboard communication

Permission Set Updates

  • Added SetupWizardController class access
  • Added Setup_Wizard tab visibility
  • Added Web_to_Case_Forms app visibility

What's Built (Phase 3)

Google reCAPTCHA v2/v3 Integration

v1 MVP Note: All reCAPTCHA executable code has been commented out (v0.8.2) for the v1 AppExchange release. This eliminates the "Approve Third-Party Access" install prompt (caused by the Remote Site Setting), removes HTTP callouts to external services (simplifies security review), and reduces onboarding friction. Metadata fields (Enable_Captcha__c, reCAPTCHA_Settings__c) are kept for v2 re-enablement. All commented code is marked with /* v2: reCAPTCHA ... */. See Re-enabling reCAPTCHA for v2 below.

Protects public forms from spam and bot submissions with "I'm not a robot" checkbox verification.

Features:

  • Per-form CAPTCHA toggle (Enable_Captcha__c field on Form__c)
  • Protected Custom Setting for API keys (reCAPTCHA_Settings__c)
  • Client-side reCAPTCHA widget rendering
  • Server-side token verification via Google API
  • Graceful error handling with user-friendly messages
  • Admin UI toggle in Form Manager

Custom Setting

  • reCAPTCHA_Settings__c - Protected hierarchy Custom Setting
    • Site_Key__c - Public key for widget rendering
    • Secret_Key__c - Private key for server-side verification

Form__c Field

  • Enable_Captcha__c - Checkbox to enable/disable CAPTCHA per form

Remote Site Setting

  • Google_reCAPTCHA - Allows callouts to https://www.google.com for token verification Deleted in v0.8.2 (caused "Approve Third-Party Access" install prompt)

Updated Components

  • CaseFormController.cls - verifyCaptcha(), getCaptchaSiteKey(), getCaptchaEnabled() (commented out in v0.8.2, return stubs)
  • CaseFormPage.page - reCAPTCHA script loading and widget rendering (commented out in v0.8.2)
  • caseFormScript.js - CAPTCHA token extraction and submission (commented out in v0.8.2)
  • caseFormWidget.js - CAPTCHA widget rendering and token handling (commented out in v0.8.2)
  • caseFormStyles.css - Styling for CAPTCHA widget and error messages
  • formDetail LWC - Added "Enable CAPTCHA" toggle in form settings (hidden in v0.7.0)
  • setupWizard.js - reCAPTCHA imports and methods (commented out in v0.8.2)
  • setupStatus.js - CAPTCHA_TYPE_LABELS constant (commented out in v0.8.2)
  • WebToCaseRestAPI.cls - Captcha config in REST response (commented out in v0.8.2)
  • SetupWizardController.cls - reCAPTCHA settings methods (commented out in v0.8.2)

Permission Set Updates

  • Enable_Captcha__c field permission removed from permission set in v0.8.2

Test Coverage

  • CaseFormControllerTest - CAPTCHA-specific tests and HTTP mocks commented out in v0.8.2
  • SetupWizardControllerTest - ~25 reCAPTCHA test methods commented out in v0.8.2
  • 88% code coverage on CaseFormController

What's Built (Phase 4)

Embeddable Widget for External Websites

Allows users to embed Web-to-Case forms on external websites using a <script> tag.

Three Embed Modes:

Mode 1: Inline Widget (Recommended)

  • Uses Shadow DOM for CSS isolation
  • Customizable via 28 CSS variables (container, title, description, labels, inputs, submit button, success/error)
  • Form rendered directly in the host page

Mode 2: Custom HTML Connect Mode

  • WebToCaseForm.connect() binds submission logic to user's own HTML form
  • No Shadow DOM, no rendered HTML — full design control
  • Validates against form config using aria-invalid attributes
  • Collects only config-defined fields by name attribute
  • Supports file upload, CAPTCHA, chunked uploads, and all existing features
  • destroy() method for SPA re-initialization
  • Init-time console warnings for missing required field inputs

Mode 3: iframe Embed

  • Full DOM isolation
  • Automatic height resizing via postMessage
  • Best for sites with strict CSP policies

REST API Endpoints

Method Path Description
GET /webtocase/v1/form/{formName} Get form configuration + nonce
POST /webtocase/v1/submit Submit form data
POST /webtocase/v1/upload-chunk Upload file chunk
OPTIONS /* CORS preflight

Security Features

  • Origin validation: Strict domain allowlist per form
  • One-time nonce: Prevents replay attacks (15-min TTL)
  • Rate limiting: 100 submissions/hour per origin
  • Field allowlist: Server ignores unknown fields

New Files

Apex Classes:

  • WebToCaseRestAPI.cls - REST API with CORS support
  • WebToCaseNonceService.cls - Nonce generation/validation
  • WebToCaseRateLimiter.cls - Rate limiting logic
  • WebToCaseRestAPITest.cls - Unit tests

Static Resources:

  • caseFormWidget.js - Embeddable widget script

Custom Objects:

  • Rate_Limit_Counter__c - Tracks rate limits per origin

New Fields:

  • Form__c.Allowed_Domains__c - Newline-separated domain allowlist

Admin UI Updates

  • Embed Code section in Form Detail with:
    • Allowed Domains textarea with "Generate Embed Code" confirmation button
    • SLDS scoped tabs: Widget | Custom HTML | iframe
    • Widget tab: Inline script snippet + CSS variables snippet
    • Custom HTML tab: Generated HTML/CSS/JS snippets from actual form fields
    • iframe tab: iframe embed snippet
    • Copy buttons for all code snippets
    • reCAPTCHA domain warning (above tabs, applies to all methods)

CSS Variables for Styling (28 variables)

#support-form {
  /* Base */
  --wtc-primary-color: #0176d3;
  --wtc-font-family: system-ui, -apple-system, sans-serif;
  --wtc-text-color: #181818;
  --wtc-border-radius: 4px;
  --wtc-error-color: #c23934;
  --wtc-success-color: #2e844a;
  /* Container */
  --wtc-container-max-width: 100%;
  --wtc-container-padding: 0;
  /* Title */
  --wtc-title-font-size: 1.5rem;
  --wtc-title-font-weight: 600;
  --wtc-title-margin: 0 0 8px 0;
  /* Description */
  --wtc-description-color: #666;
  --wtc-description-font-size: 0.875rem;
  /* Labels */
  --wtc-label-font-size: 0.875rem;
  --wtc-label-font-weight: 500;
  --wtc-label-color: var(--wtc-text-color);
  /* Inputs */
  --wtc-input-border: 1px solid #c9c9c9;
  --wtc-input-background: #ffffff;
  --wtc-input-padding: 10px 12px;
  --wtc-input-font-size: 1rem;
  /* Field layout */
  --wtc-field-gap: 20px;
  /* Submit button */
  --wtc-submit-color: #fff;
  --wtc-submit-background: var(--wtc-primary-color);
  --wtc-submit-padding: 12px 24px;
  --wtc-submit-font-size: 1rem;
  --wtc-submit-border-radius: var(--wtc-border-radius);
  /* Success/Error */
  --wtc-success-background: #d4edda;
  --wtc-success-border: 1px solid #c3e6cb;
  --wtc-error-background: #f8d7da;
  --wtc-error-border: 1px solid #f5c6cb;
}

Embedding Forms on External Websites

Quick Start

  1. Configure allowed domains in Form Manager:

    • Edit your form
    • Go to "Embed Code" section
    • Add your website domain (e.g., example.com)
    • Save the form
  2. Add embed code to your website:

<div id="support-form"></div>
<script src="https://yoursite.salesforce-sites.com/support/resource/caseFormWidget"></script>
<script>
  WebToCaseForm.render({
    formName: 'support',
    containerId: 'support-form',
    apiBase: 'https://yoursite.salesforce-sites.com/support/services/apexrest',
    onSuccess: function(caseNumber) {
      console.log('Case created:', caseNumber);
    },
    onError: function(error) {
      console.error('Error:', error);
    }
  });
</script>

Custom HTML (Connect Mode)

Use WebToCaseForm.connect() for full control over form HTML and styling:

<form id="wtc-support">
  <div>
    <label for="SuppliedName">Your Name *</label>
    <input type="text" id="SuppliedName" name="SuppliedName" required />
  </div>
  <div>
    <label for="SuppliedEmail">Email *</label>
    <input type="email" id="SuppliedEmail" name="SuppliedEmail" required />
  </div>
  <div>
    <label for="Subject">Subject *</label>
    <input type="text" id="Subject" name="Subject" required />
  </div>
  <div>
    <label for="Description">Message *</label>
    <textarea id="Description" name="Description" required></textarea>
  </div>
  <div id="wtc-error" hidden></div>
  <button type="submit">Submit</button>
</form>

<div id="wtc-success" hidden>
  <p>Your request has been submitted successfully.</p>
  <p>Reference: <span data-wtc-case-number></span></p>
</div>

<script src="https://yoursite.salesforce-sites.com/support/resource/caseFormWidget"></script>
<script>
  WebToCaseForm.connect({
    formName: 'support',
    formSelector: '#wtc-support',
    apiBase: 'https://yoursite.salesforce-sites.com/support/services/apexrest',
    errorContainerId: 'wtc-error',
    successContainerId: 'wtc-success',
    onSuccess: function(caseNumber) {
      console.log('Case created:', caseNumber);
    },
    onError: function(error) {
      console.error('Error:', error);
    }
  });
</script>

Input name attributes must match Case field API names from your form config. You can rearrange elements, add classes, and style freely — the script only touches elements it needs.

iframe Alternative

Use iframe if you need full DOM isolation:

<iframe
  src="https://yoursite.salesforce-sites.com/support/apex/CaseFormPage?form=support&embed=1"
  style="width:100%; border:none; min-height:500px;"
  id="wtc-frame">
</iframe>
<script>
  window.addEventListener('message', function(e) {
    if (e.data && e.data.type === 'wtc:resize') {
      document.getElementById('wtc-frame').style.height = e.data.height + 'px';
    }
  });
</script>

CSP Requirements

Add these to your Content-Security-Policy if using the inline widget:

script-src: https://yoursite.salesforce-sites.com
connect-src: https://yoursite.salesforce-sites.com
frame-src: https://www.google.com https://yoursite.salesforce-sites.com

reCAPTCHA Setup for Embedded Forms

If your form uses CAPTCHA, add your embedding domain to Google reCAPTCHA:

  1. Go to Google reCAPTCHA Admin Console
  2. Select your reCAPTCHA site
  3. Add your embedding domain (e.g., example.com) to the allowed domains list

Troubleshooting Embedded Forms

Issue Solution
"Origin not allowed" error Add your domain to Allowed Domains in Form Manager
CORS errors Verify the apiBase URL is correct
CAPTCHA not loading Add your domain to Google reCAPTCHA allowed domains
Form not rendering Check browser console for JavaScript errors
Rate limit exceeded Wait 1 hour or contact the form administrator

Manual Testing Checklist (Phase 3)

v1 MVP Note: reCAPTCHA admin UI is hidden in v0.7.0. These tests apply only after re-enabling for v2 (see changelog).

Use this checklist to verify reCAPTCHA integration in your org:

1. Configure reCAPTCHA API Keys

  • Go to Google reCAPTCHA Admin Console
  • Create a new site with reCAPTCHA v2 "I'm not a robot" checkbox
  • Add your Salesforce Site domain (e.g., yourorg.my.salesforce-sites.com)
  • Copy the Site Key and Secret Key

2. Add Keys to Salesforce (via Setup Wizard)

  • Go to Setup Wizard tab (or run the wizard from App Launcher → "Web-to-Case Forms")
  • If you already completed setup, navigate to Step 5 (reCAPTCHA)
  • Enter your Site Key and Secret Key
  • Click Save reCAPTCHA Settings
  • Proceed to Complete step

Alternative (Anonymous Apex):

reCAPTCHA_Settings__c settings = reCAPTCHA_Settings__c.getOrgDefaults();
settings.Site_Key__c = 'YOUR_SITE_KEY_HERE';
settings.Secret_Key__c = 'YOUR_SECRET_KEY_HERE';
upsert settings;

3. Create a Test Form with CAPTCHA

  • Go to Form Manager tab
  • Click New Form or edit an existing form
  • Check the Enable CAPTCHA checkbox
  • Add at least one required field (e.g., Name, Email, Subject)
  • Check Active
  • Click Save

4. Test the Public Form

  • Click View Live to open the form in a new tab
  • Verify the reCAPTCHA widget ("I'm not a robot") appears below the form fields
  • Test 1: Submit without CAPTCHA
    • Fill in all required fields
    • Do NOT click the CAPTCHA checkbox
    • Click Submit
    • Verify error message: "Please complete the CAPTCHA verification."
  • Test 2: Submit with CAPTCHA
    • Fill in all required fields
    • Click the reCAPTCHA checkbox (wait for green checkmark)
    • Click Submit
    • Verify success message with case number

5. Verify Case Creation

  • Go to Cases tab in Salesforce
  • Find the newly created case
  • Verify the case fields match your form submission

6. Test Form WITHOUT CAPTCHA

  • Create or edit a form with Enable CAPTCHA unchecked
  • View the form publicly
  • Verify NO reCAPTCHA widget appears
  • Submit the form and verify it works without CAPTCHA

7. Test Admin UI

  • Go to Form Manager tab
  • Verify the Enable CAPTCHA checkbox appears in form settings
  • Verify the help text explains reCAPTCHA requirements
  • Toggle CAPTCHA on/off and save - verify it persists

Troubleshooting

Issue Solution
reCAPTCHA widget doesn't appear Check that reCAPTCHA_Settings__c has Site Key configured
"CAPTCHA verification failed" on submit Verify Secret Key is correct in Custom Settings
Form hangs on submit Check browser console for errors; verify Remote Site Setting exists
Error: "Unauthorized endpoint" Add Remote Site Setting for https://www.google.com

Deployment

Prerequisites

  • Salesforce CLI (sf) installed
  • Access to a Salesforce org (Developer Edition or Sandbox)

1. Deploy Code

sf org login web --alias myorg
sf project deploy start --target-org myorg
sf apex run test --target-org myorg --test-level RunLocalTests

2. Create Test Data

Run this anonymous Apex to create a sample form:

Form__c form = new Form__c(
    Form_Name__c = 'support',
    Title__c = 'Contact Support',
    Description__c = 'We\'ll get back to you within 24 hours.',
    Success_Message__c = 'Thank you! Your case has been submitted.',
    Active__c = true,
    Enable_File_Upload__c = true,
    Enable_Captcha__c = true  // Enable CAPTCHA
    // Note: File limits are fixed (Images: 25MB auto-compressed, Documents: 4MB)
);
insert form;

List<Form_Field__c> fields = new List<Form_Field__c>{
    new Form_Field__c(Form__c = form.Id, Field_Label__c = 'Your Name', Field_Type__c = 'Text', Case_Field__c = 'SuppliedName', Required__c = true, Sort_Order__c = 1),
    new Form_Field__c(Form__c = form.Id, Field_Label__c = 'Email Address', Field_Type__c = 'Email', Case_Field__c = 'SuppliedEmail', Required__c = true, Sort_Order__c = 2),
    new Form_Field__c(Form__c = form.Id, Field_Label__c = 'Subject', Field_Type__c = 'Text', Case_Field__c = 'Subject', Required__c = true, Sort_Order__c = 3),
    new Form_Field__c(Form__c = form.Id, Field_Label__c = 'Message', Field_Type__c = 'Textarea', Case_Field__c = 'Description', Required__c = true, Sort_Order__c = 4)
};
insert fields;

Or use the Form Manager tab to create forms via the UI (Phase 1).

3. Create Salesforce Site

  1. Setup → Sites → Register your domain
  2. Create new site:
    • Site Label: Support
    • Site Name: support (or s for shorter URL)
    • Active Site Home Page: CaseFormPage
  3. Activate the site

4. Configure Guest User Profile

On the Site detail page → Public Access Settings:

Object Permissions:

Object Read Create
Form__c
Form_Field__c
Case
ContentVersion
ContentDocumentLink
Error_Log__c

Field Permissions (Form__c): Read access to Description__c, Enable_File_Upload__c, Success_Message__c, Enable_Captcha__c

Field Permissions (Form_Field__c): Read access to Required__c

Apex Class Access: CaseFormController, ErrorLogger

VF Page Access: CaseFormPage

5. Configure reCAPTCHA (Phase 3) — Deferred in v1 MVP

reCAPTCHA admin UI is hidden in v0.7.0. To enable, see Re-enabling reCAPTCHA for v2 in the changelog.

  1. Get API keys from Google reCAPTCHA Admin
  2. Setup → Custom Settings → reCAPTCHA Settings → Manage → New
  3. Enter Site Key and Secret Key

6. Test

Access: https://[your-domain].my.salesforce-sites.com/support/CaseFormPage?name=support


Using the Form Manager (Phase 1)

  1. Navigate to the Form Manager tab in Salesforce
  2. Click New Form to create a form
  3. Fill in form settings:
    • Form Name: URL-safe identifier (lowercase, hyphens only)
    • Title: Display title shown on the form
    • Description: Instructions shown at the top
    • Success Message: Shown after submission
    • Active: Toggle to enable/disable the form
    • Enable File Upload: Allow file attachments
    • Enable CAPTCHA: Require reCAPTCHA verification (Phase 3, hidden in v1 MVP)
  4. Add fields in the Form Fields section
  5. Click Save
  6. Use View Live to preview the form

Roadmap

Phase 5: Advanced Features (NEXT)

  • Multi-file upload (drag & drop)
  • Custom field types (picklist, date, checkbox)
  • Form analytics/submission tracking
  • Email notifications on submission

Project Structure

force-app/main/default/
├── applications/
│   └── Web_to_Case_Forms.app-meta.xml   # Phase 2 - Lightning App
├── cachePartitions/
│   └── WebToCase.cachePartition-meta.xml # Platform Cache for nonces
├── # corsWhitelistOrigins/ — removed (org-specific, excluded via .forceignore)
├── # cspTrustedSites/ — removed (org-specific, excluded via .forceignore)
├── objects/
│   ├── Form__c/                         # Form configuration
│   │   └── fields/
│   │       ├── Enable_Captcha__c        # Phase 3
│   │       ├── Site_Id__c               # URL Display Feature
│   │       ├── Allowed_Domains__c       # Phase 4 - Embed allowlist
│   │       └── Default_Case_Values__c   # JSON defaults for hidden Case fields
│   ├── Form_Field__c/                   # Field definitions
│   ├── Error_Log__c/                    # Error logging
│   ├── Rate_Limit_Counter__c/           # Phase 4 - Rate limiting
│   └── reCAPTCHA_Settings__c/           # Phase 3 - API keys + Site settings
│       └── fields/
│           ├── Site_Key__c
│           ├── Secret_Key__c
│           ├── Captcha_Type__c
│           ├── Score_Threshold__c
│           ├── Default_Site_Id__c       # URL Display Feature
│           └── Default_Site_Base_Url__c # URL Display Feature
├── classes/
│   ├── CaseDefaultFieldConfig.cls       # Shared allowlist for default Case fields
│   ├── CaseFormController.cls
│   ├── CaseFormControllerTest.cls
│   ├── ErrorLogger.cls
│   ├── ErrorLoggerTest.cls
│   ├── FileAssemblyQueueable.cls        # Async chunk assembly (4MB support)
│   ├── FileAssemblyQueueableTest.cls
│   ├── FormAdminController.cls          # Phase 1
│   ├── FormAdminControllerTest.cls      # Phase 1
│   ├── SetupWizardController.cls        # Phase 2
│   ├── SetupWizardControllerTest.cls    # Phase 2
│   ├── WebToCaseRestAPI.cls             # Phase 4 - REST endpoints
│   ├── WebToCaseNonceService.cls        # Phase 4 - Nonce management
│   ├── WebToCaseRateLimiter.cls         # Phase 4 - Rate limiting
│   └── WebToCaseRestAPITest.cls         # Phase 4 - Tests
├── messageChannels/
│   └── SetupStatusRefresh.messageChannel-meta.xml  # LMS channel
├── lwc/
│   ├── formAdminApp/                    # Phase 1 - Main admin container
│   ├── formDetail/                      # Phase 1 - Form editor (+ CAPTCHA toggle)
│   ├── setupStatus/                     # Configuration Status Dashboard (+ LMS subscriber)
│   └── setupWizard/                     # Phase 2 - Setup wizard (+ LMS publisher)
├── flexipages/
│   ├── Form_Manager.flexipage-meta.xml  # Phase 1
│   └── Setup_Wizard.flexipage-meta.xml  # Phase 2
├── tabs/
│   ├── Form_Manager.tab-meta.xml        # Phase 1
│   └── Setup_Wizard.tab-meta.xml        # Phase 2
├── pages/
│   └── CaseFormPage.page                # + reCAPTCHA widget (Phase 3)
├── staticresources/
│   ├── caseFormStyles.css               # + CAPTCHA styles (Phase 3)
│   ├── caseFormScript.js                # + compression, validation, postMessage
│   ├── caseFormWidget.js                # Phase 4 - Embeddable widget
│   └── imageCompression.js              # browser-image-compression library
├── # remoteSiteSettings/ — Google_reCAPTCHA deleted in v0.8.2 (re-create for v2)
├── # sites/ — removed (org-specific, excluded via .forceignore)
└── permissionsets/
    └── Web_to_Case_Admin.permissionset-meta.xml

Troubleshooting

Form shows "Form Not Available"

  • Verify Form__c record exists with matching Form_Name__c
  • Verify Active__c = true
  • Check Guest User has Read access to Form__c
  • For preview mode, add ?preview=true to bypass Active check

File upload not showing

  • Verify Enable_File_Upload__c = true on the Form__c record
  • Check Guest User has Read access to Enable_File_Upload__c field

Submission fails

  • Check Error_Log__c for error details
  • Verify Guest User has Create access to Case, ContentVersion, ContentDocumentLink
  • Enable debug logs for the Guest User

Form Manager tab not visible

  • Assign the Web_to_Case_Admin permission set to your user
  • Verify Form_Manager tab is set to Visible in the permission set

reCAPTCHA not showing (Phase 3)

  • Verify Enable_Captcha__c = true on the Form__c record
  • Check that reCAPTCHA_Settings__c has a valid Site Key
  • Guest User needs Read access to Enable_Captcha__c field

CAPTCHA verification fails (Phase 3)

  • Verify Secret Key is correct in reCAPTCHA_Settings__c
  • Check Remote Site Setting Google_reCAPTCHA is active
  • Review Error_Log__c for detailed error messages

Changelog

v0.8.3 (2026-02-14) - Fix Chunked File Upload Assembly Bugs

Fixed three bugs in the chunked file upload pipeline discovered during end-to-end upload limit testing:

  • Heap limit crash on sync assembly: SYNC_CHUNK_LIMIT reduced from 3 → 2. Synchronous assembly of 3 chunks (~2MB file) caused ~8MB peak heap during base64 concatenation + blob decode, exceeding the 6MB synchronous limit (LimitException, uncatchable). Files with 3+ chunks now route through the Queueable path (12MB async heap).
  • "Private library" error in FileAssemblyQueueable: Final ContentVersion was created without FirstPublishLocationId, causing INVALID_STATUS: Documents in a user's private library must always be owned by that user when the Queueable runs as Automated Process User. Fixed by using FirstPublishLocationId = caseId (same pattern as chunk uploads) and removing manual ContentDocumentLink creation. Same fix applied to assembleSynchronous for consistency.
  • Overly strict CRUD checks for Guest Users: Removed assertDeletable(ContentDocument) and assertCreateable(ContentDocumentLink) checks from assembly methods. Guest Users get implicit Content object access via FirstPublishLocationId; explicit ObjectPermissions cannot be granted for Content standard objects (INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST on DML).

Files changed: CaseFormController.cls, FileAssemblyQueueable.cls Status: Deployed to devorg, all tests pass. Needs 2GP package workflow (v1.9.0) to reach devhub.

v0.8.2 (2026-02-13) - Comment Out All reCAPTCHA Code for v1 AppExchange

Commented out all reCAPTCHA/captcha executable code across 12+ files for the v1 AppExchange release. This eliminates the "Approve Third-Party Access" install prompt (caused by the Google_reCAPTCHA Remote Site Setting) and removes HTTP callouts to external services (simplifies security review). All commented code is marked with /* v2: reCAPTCHA ... */ for easy re-enablement.

Deleted:

  • Google_reCAPTCHA.remoteSite-meta.xml — Remote Site Setting that caused the install prompt

Apex changes (methods return stubs):

  • CaseFormController.cls — 6 methods: getCaptchaSiteKey() returns '', getCaptchaType() returns 'V2_Checkbox', getCaptchaEnabled() returns false, captcha verification block in submitForm() commented out, verifyCaptchaWithDetails() returns empty map, verifyCaptcha() returns false
  • WebToCaseRestAPI.cls — hardcoded enableCaptcha=false in response, captcha config block commented out
  • SetupWizardController.clsgetReCaptchaSettings() returns empty result, saveReCaptchaSettings() returns error "reCAPTCHA is disabled in v1", clearReCaptchaSettings() returns empty result, reCAPTCHA block in getFullStatus() commented out

Frontend changes:

  • CaseFormPage.page — reCAPTCHA script loading (v2+v3), widget rendering (3 types), and formConfig captcha vars commented out
  • caseFormScript.jsonCaptchaSuccess callback, captchaResolve, token extraction, grecaptcha refs commented out
  • caseFormWidget.js — captcha rendering in FormWidget, token handling in SubmissionMixin, captcha rendering in ConnectedForm commented out
  • setupWizard.jsgetReCaptchaSettings/saveReCaptchaSettings imports, tracked properties, 8 handler methods commented out
  • setupStatus.jsCAPTCHA_TYPE_LABELS constant commented out

Permission set:

  • Web_to_Case_Admin.permissionset-meta.xml — removed Enable_Captcha__c FLS entry

Tests commented out:

  • CaseFormControllerTest.cls — ~16 captcha test methods and 5 HTTP mock classes
  • SetupWizardControllerTest.cls — ~25 reCAPTCHA test methods across 5 sections

Not modified (kept for v2 re-enablement):

  • Enable_Captcha__c field on Form__c (defaults to false)
  • reCAPTCHA_Settings__c object and fields (also stores non-captcha Default_Site_Id__c, Default_Site_Base_Url__c)
  • formDetail.jsshowCaptchaToggle already returns false (v0.7.0)

Status: Deployed to devorg, all tests pass. Needs 2GP package workflow (v1.9.0) to reach devhub.

v0.8.1 (2026-02-12) - Fix Configuration Status & Form Manager Banner

  • Fixed: Configuration Status dashboard no longer shows prematurely when only Step 2 (site selection) is completed — now requires all permissions to pass before appearing
  • Fixed: Form Manager "setup incomplete" banner now checks permissions, not just site selection — isSetupComplete() calls getSetupStatus() to verify allPassed
  • Both surfaces now correctly hide until the wizard is fully completed (all steps including Verify)

v0.8.0 (2026-02-11) - 2GP Managed Package Creation

Created 2GP managed package for AppExchange submission. Package ID: 0Hod20000000XlZCAU.

Org setup:

  • Authenticated Dev Hub org (devhub) and linked caseform namespace via Namespace Registries (App Launcher, not Setup)
  • Created package with sf package create

2GP test compatibility fixes (5 retries to resolve all issues):

  1. stripInaccessible removal: Removed Security.stripInaccessible() from FormAdminController and WebToCaseRestAPI for package-owned objects. In 2GP packaging scratch orgs, the admin profile lacks FLS on namespace-prefixed custom fields, causing stripInaccessible to silently remove fields and crash downstream code. CRUD checks remain; FLS controlled by package permission set.
  2. Permission set completeness: Added all missing non-required field FLS entries, removed required fields (Salesforce rejects them), fixed Error_Log__c.allowCreate.
  3. Test setup PS assignment: Added PermissionSetAssignment for Web_to_Case_Admin in @TestSetup of 3 test classes.
  4. Profile query resilience: Changed SetupWizardControllerTest from hardcoded 'Standard User' profile to flexible query with graceful skip.
  5. Cache partition: Set WebToCase partition isDefaultPartition=false (can't package default partitions).

Blocked: Daily package version create limit (6/day) exhausted. Version create command ready to run next session.

v0.7.3 (2026-02-11) - AppExchange Security Review Fixes

Fixes three blockers identified during pre-submission security audit.

1. FlexiPage deployment failure (hard blocker):

  • Root cause: Org has registered namespace caseform, but FlexiPage XML referenced components with default c: prefix
  • Fixed Form_Manager.flexipage-meta.xmlcaseform:formAdminApp
  • Fixed Setup_Wizard.flexipage-meta.xmlcaseform:setupStatus, caseform:setupWizard
  • Added targetConfigs with supportedFormFactors to formAdminApp.js-meta.xml for consistency

2. DOM XSS sink elimination (security review risk):

  • Replaced innerHTML with textContent for all error message rendering:
    • caseFormScript.js (VF Remoting error display)
    • caseFormWidget.js (widget + connect mode error display)
  • Replaced raw e.getMessage() in CaseFormController.uploadFileChunk catch block with generic message — exception details now logged server-side only via ErrorLogger

3. Explicit sharing declarations (security review risk):

  • ErrorLoggerpublic without sharing class (must always insert Error_Log__c regardless of caller context; has CRUD checks)
  • WebToCaseRateLimiterpublic without sharing class (must always access Rate_Limit_Counter__c for accurate rate limiting; has CRUD checks)

4. AggregateResult namespace robustness:

  • Added field alias in FormAdminController aggregate query (SELECT Form__c formId, COUNT(Id) cnt) to avoid namespace-dependent key resolution in AggregateResult.get()

Test results: 255/257 tests passing. 2 failures are LeadConversionServiceTest (non-package class, broken org Flow — pre-existing). All package tests pass.

v0.7.2 (2026-02-11) - Fix Setup Wizard Guest User Permission Error

Fixed "INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST" error when clicking "Configure Permissions" in the Setup Wizard (Step 3).

Root cause: Error_Log__c.Timestamp__c is a required field (<required>true</required>). Salesforce automatically grants FLS (Read/Edit) on required fields to all profiles, so they don't appear in the FieldPermissions restricted picklist. The wizard was trying to upsert a FieldPermissions record for this field, which Salesforce rejected.

Fix: Removed Timestamp__c from the REQUIRED_FIELD_READ map in SetupWizardController — no FLS configuration needed for required fields.

v0.7.1 (2026-02-10) - Test Coverage for AppExchange Submission

Increased test coverage for the two classes that were below the 75% AppExchange threshold.

WebToCaseNonceService: 51% → 81% (14 new tests in WebToCaseRestAPITest):

  • Nonce generate + validate/consume round-trip, one-time use enforcement
  • Validation failures: formId mismatch, origin mismatch, expired nonce
  • Blank origin matching (nonce with blank origin accepts any requester)
  • Multiple independent nonces, empty allowedFields edge case
  • Case upload authorization: full round-trip, blank/null IDs, non-authorized case
  • Platform Cache code paths (generate, validate, authorize, check via cache)
  • isCacheAvailable() cached result path, NonceData wrapper defaults

SetupWizardController: 50% → 86% (12 new tests in SetupWizardControllerTest):

  • Real Site tests covering private helpers: checkObjectPermission, checkFieldPermission, checkApexAccess, checkVfPageAccess, configureObjectPermission, configureFieldPermission, getSiteBaseUrl
  • getSetupStatus, configurePermissions, validateConfiguration, getPublicUrl, getConfigSummary, getFullStatus, saveDefaultSite — all with real active Site
  • CRUD denial for saveDefaultSite and configurePermissions
  • No Guest User error paths for getSetupStatus and configurePermissions
  • getFullStatus with reCAPTCHA configured + real Site (end-to-end dashboard)

Test results: 257/257 Apex tests passed (100%). Org-wide coverage: 64%.

v0.7.0 (2026-02-10) - v1 MVP: Hide reCAPTCHA for AppExchange Release

Hides all reCAPTCHA admin UI surfaces for the v1 AppExchange submission. reCAPTCHA adds onboarding friction (customers must get Google API keys), introduces an external HTTP dependency (complicates security review), and increases support burden. The feature is well-built but not essential for v1. All code remains intact and conditional — Enable_Captcha__c defaults to false and all frontend/backend logic is gated on it.

Changes:

  • Setup Wizard (setupWizard.js/html): Reduced from 6 steps to 5 — reCAPTCHA step commented out, Complete step renumbered from 6 to 5. reCAPTCHA status messages hidden on Complete step.
  • Form Editor (formDetail.js/html): "Enable CAPTCHA" checkbox hidden via showCaptchaToggle getter (returns false)
  • Setup Status Dashboard (setupStatus.js/html): reCAPTCHA panel hidden via showRecaptchaPanel getter (returns false). Dashboard now shows 3 panels: Site, Permissions, URL.
  • Remote Site Setting (Google_reCAPTCHA.remoteSite-meta.xml): Deactivated (isActive=false)

Not modified (all remain intact):

  • CaseFormController.cls — captcha logic conditional on Enable_Captcha__c
  • WebToCaseRestAPI.cls — API gates captcha config on the same flag
  • CaseFormPage.page — VF rendering conditional on captchaEnabled
  • caseFormScript.js / caseFormWidget.js — JS conditional on enableCaptcha
  • CaseFormControllerTest.cls — all captcha tests pass (use mocks + explicit Enable_Captcha__c = true)
  • reCAPTCHA_Settings__c and Form__c.Enable_Captcha__c — metadata stays in package

Re-enabling for v2 — 4 toggles in 4 files, each marked with v1 MVP / v2 comments:

  1. setupWizard.js — Uncomment reCAPTCHA step, renumber back to 6 steps
  2. formDetail.jsshowCaptchaToggle returns true
  3. setupStatus.jsshowRecaptchaPanel returns true
  4. Google_reCAPTCHA.remoteSite-meta.xmlisActive back to true

Test results: 227/227 Apex tests passed (100%). Playwright verified: 5 wizard steps, no CAPTCHA toggle in form editor, no reCAPTCHA panel in dashboard, form submission works without captcha (Case 00001114 created).

v0.6.3 (2026-02-10) - CSS Bug Fixes, Nonce Retry, iframe Embed Support

  • 6 CSS bug fixes in caseFormWidget.js:
    1. Added box-sizing: border-box to inputs and submit button (prevents overflow with padding)
    2. Focus ring now respects --wtc-primary-color (was hardcoded Salesforce blue)
    3. Case number color uses --wtc-success-color (was hardcoded green)
    4. Disabled button uses opacity: 0.6 instead of hardcoded gray (respects custom --wtc-submit-background)
    5. Removed self-referencing CSS variable declarations from :host (dead code per CSS spec)
    6. Error focus ring respects --wtc-error-color (was hardcoded red)
  • Added explicit fallbacks to all bare var(--wtc-*) references throughout widget CSS
  • Transparent nonce retry: On expired nonce errors, widget auto-fetches fresh config and resubmits once (no user action needed)
  • iframe embed support: Changed Site clickjack protection from SameOriginOnly to AllowAllFraming to allow iframe embedding on external domains
  • CORS headers before errors: Moved CORS header setting before error responses in all REST API endpoints so browsers can read error messages
  • Nonce service fix: Fixed Platform Cache API to use partition-qualified calls; reduced nonce key from 256-bit to 128-bit to fit 50-char cache key limit
  • Snippet ID collisions fix: Custom HTML tab in Admin UI now uses form-scoped IDs ({formId}-file, {formId}-error) instead of generic IDs
  • New metadata:
    • WebToCase.cachePartition — Platform Cache partition for nonces
    • dietrich_ai.corsWhitelistOrigin / dietrich_ai_bare.corsWhitelistOrigin — CORS whitelist for dietrich.ai
    • dietrich_ai.cspTrustedSite — CSP trusted site for iframe embedding
    • Support.site — Salesforce Site metadata with AllowAllFraming

v0.6.2 (2026-02-10) - Configuration Status Dashboard: Hide When Unconfigured + Auto-Refresh

  • setupStatus hidden when unconfigured: Dashboard renders nothing when the org has no configuration, eliminating the redundant "Setup Not Complete" message
  • Auto-refresh via LMS: When the Setup Wizard completes (Step 6), setupStatus automatically refreshes and appears without a page reload
  • New Lightning Message Channel: SetupStatusRefresh for sibling component communication between setupWizard and setupStatus
  • Immediate card display: Card shows loading spinner immediately on page load (no 2-second lag on configured orgs)

v0.6.1 (2026-02-10) - Configuration Status Dashboard + Setup Wizard UI Fix

  • New LWC: setupStatus - Configuration Status Dashboard showing real-time setup health
    • Displays Site configuration, Guest User permissions, reCAPTCHA status, and public form URL
    • Embedded in the Setup Wizard Lightning page alongside the wizard
    • Uses SetupWizardController.getFullStatus() for live status checks
    • Copy-to-clipboard for public form URL
    • Collapsible permission details section
  • Setup Wizard progress indicator: Reverted from type="path" (chevron/arrow) to type="base" (standard dot stepper)

v0.6.0 (2026-02-10) - Custom HTML Connect Mode + Extended CSS Variables

  • Connect mode (WebToCaseForm.connect()): Bind submission logic to user's own HTML form — no Shadow DOM, full design control
    • Validates against form config using aria-invalid attributes
    • Collects only config-defined fields by name attribute
    • Supports file upload, CAPTCHA, chunked uploads, polling — all existing features
    • destroy() method for clean SPA re-initialization
    • Init-time console warnings for missing required field inputs
  • Extended CSS variables: Expanded from 8 to 28 variables covering container, title, description, labels, inputs, field gap, submit button, success, and error styling
  • SubmissionMixin: Internal refactor extracting shared submission-pipeline methods from FormWidget — no behavior change, enables code reuse by ConnectedForm
  • Admin UI: Embed Code section redesigned:
    • SLDS scoped tabs (Widget / Custom HTML / iframe) replacing sequential layout
    • "Generate Embed Code" button — domains must be confirmed before snippets appear
    • Custom HTML tab generates HTML, CSS, and JS snippets from the form's actual fields
    • All tabs have Copy buttons for each snippet
  • Updated files: caseFormWidget.js (CSS variables, SubmissionMixin, ConnectedForm, connect()), formDetail.js/html/css (snippets, handlers, scoped tabs)
  • No backend (Apex) changes — connect mode uses the same REST endpoints

v0.5.2 (2026-02-09) - Default Case Values for Form Admin

  • Default Case Values: Admins can configure hidden Case field defaults per form (e.g., Priority=High, Type=Problem)
  • JSON storage: Defaults stored as JSON on Form__c.Default_Case_Values__c (LongTextArea)
  • Allowlisted fields: Priority, Status, Origin, Type, Reason — enforced server-side via CaseDefaultFieldConfig
  • Config-time validation: FormAdminController.saveForm() validates JSON structure, allowlist, and non-blank string values
  • Submit-time application: CaseFormController.submitForm() applies defaults between hardcoded fallbacks and user fields
  • DML retry resilience: If invalid picklist values cause DML failure, system retries with a fresh Case (no defaults), logs error
  • Admin UI: New "Default Case Values" accordion section in Form Detail with picklist-aware field/value selectors
  • New Apex class: CaseDefaultFieldConfig — shared allowlist constant used by both controllers
  • New field: Form__c.Default_Case_Values__c — LongTextArea(32768) for JSON defaults
  • New method: FormAdminController.getCaseFieldsForDefaults() — returns field metadata with active picklist values
  • Updated permission set: Web_to_Case_Admin — added read/edit for Default_Case_Values__c
  • Test coverage: 12 new test methods (7 in FormAdminControllerTest, 5 in CaseFormControllerTest)

v0.5.1 (2026-02-07) - 4MB Document Upload Limit

  • Increased document upload limit from 2MB to 4MB using async Queueable assembly
  • New Apex class: FileAssemblyQueueable - Assembles file chunks asynchronously using 12MB Queueable heap
    • Files <= 2MB (3 chunks): Assembled synchronously in CaseFormController (6MB heap)
    • Files 2-4MB (4+ chunks): Assembled asynchronously via Queueable (12MB heap)
  • Updated frontends: caseFormScript.js (VF Remoting) and caseFormWidget.js (REST API) both enforce 4MB limit
  • Updated backend: CaseFormController and WebToCaseRestAPI enforce 4MB hard cap server-side
  • Updated Admin UI: Form Manager help text now reads "Documents: up to 4MB"
  • Chunk pattern: __chunk__{uploadKey}__{chunkIndex}__{totalChunks}__{fileName} (750KB chunks)

v0.5.0 (2026-02-03) - Phase 4: Embeddable Widget

  • Embeddable widget for external websites with Shadow DOM isolation
  • Two embed modes: Inline widget (recommended) and iframe embed
  • REST API for cross-origin form operations (/webtocase/v1/*)
  • Security features:
    • Origin validation with per-form domain allowlist
    • One-time nonces (15-min TTL) prevent replay attacks
    • Rate limiting (100 submissions/hour per origin)
    • Server-side field allowlist enforcement
  • CSS variable theming for widget customization
  • postMessage API for iframe height auto-resize
  • New Apex classes:
    • WebToCaseRestAPI - REST endpoints with CORS support
    • WebToCaseNonceService - Nonce generation/validation
    • WebToCaseRateLimiter - Rate limiting logic
  • New static resource: caseFormWidget.js - Embeddable widget script
  • New custom object: Rate_Limit_Counter__c for rate limit tracking
  • New field: Form__c.Allowed_Domains__c - Domain allowlist
  • Admin UI: Embed Code section with code snippets and copy buttons
  • Test coverage: WebToCaseRestAPITest with nonce, rate limit, and origin validation tests

v0.4.8 (2026-02-02) - reCAPTCHA Type Change UX Fix

  • Fixed: Users can now change reCAPTCHA type (v2 Checkbox, v2 Invisible, v3 Score) without re-entering the secret key
  • Previously, the Setup Wizard required both Site Key and Secret Key to save any changes
  • Now, when reCAPTCHA is already configured, users can change just the type and click Save
  • Backend already supported partial updates (null values preserve existing) - this fix updates frontend validation to match
  • First-time setup still requires both keys (unchanged behavior)

v0.4.7 (2026-02-02) - Image Compression & Fixed File Limits

  • Image compression: Images up to 25MB are automatically compressed to ~0.7MB before upload
    • Uses browser-image-compression library for client-side compression
    • Converts HEIC/PNG/WebP/BMP to JPEG for optimal size
    • Shows "Optimizing..." progress during compression
    • Compression target (0.7MB) ensures single-request upload without chunking
  • Fixed file limits: Removed user-configurable "Max File Size" setting
    • Images: Up to 25MB (auto-compressed)
    • Documents (PDF, Word, etc.): Up to 4MB
    • Videos: Not supported (users prompted to email separately)
  • Simplified UX: "Enable File Upload" checkbox now shows help text with limits
    • "Images: up to 25MB (auto-compressed) | Documents: up to 4MB"
  • New static resource: imageCompression.js - browser-image-compression library (v2.0.2)
  • Removed: "Max Document Size (MB)" input field from Form Manager

v0.4.6 (2026-02-02) - Chunked File Upload Fix

  • Fixed: Files larger than ~1.5MB could not be uploaded due to Salesforce Visualforce Remoting payload limits
  • Solution: Implemented chunked file uploads for large files
    • Files ≤750KB: Uploaded in single request (as before)
    • Files >750KB: Automatically split into 750KB chunks and uploaded sequentially
    • Chunks are stored temporarily as ContentVersions, then assembled into final file
    • Chunk files are automatically cleaned up after assembly
  • New Apex methods:
    • uploadFileChunk(caseId, fileName, chunkData, chunkIndex, totalChunks, uploadKey) - Handles chunk uploads
    • getChunkSize() - Returns chunk size for JavaScript reference
  • Updated JavaScript: Added chunking logic, progress indicator during multi-chunk uploads
  • Test coverage: 6 new unit tests for chunked upload scenarios
  • Note: The Max_File_Size_MB__c setting now actually works for files up to the configured limit (previously limited to ~2MB)

v0.4.5 (2026-01-29) - URL Display Feature

  • Site dropdown added to Form Detail editor (new/edit form views)
    • Select per-form Site override or use org-wide default
    • Sites loaded from active Salesforce Sites in the org
  • Public URL display with copy button in Form Detail view
    • Shows computed public URL based on selected Site
    • Warning message when no default Site is configured
  • "Copy URL" row action added to Form Manager list view
    • Copies public form URL to clipboard with one click
    • Toast feedback on success/failure
  • Default Site configuration saved during Setup Wizard (Step 2 → Step 3)
    • Stores both Site ID and resolved base URL in reCAPTCHA_Settings__c
  • "View Live" action now uses correct public Site URL (not internal Salesforce URL)
  • New custom fields:
    • reCAPTCHA_Settings__c.Default_Site_Id__c - Default Site ID for org
    • reCAPTCHA_Settings__c.Default_Site_Base_Url__c - Cached base URL
    • Form__c.Site_Id__c - Per-form Site override
  • URL encoding for form names with special characters
  • 143 Apex tests passing

v0.4.4 (2026-01-29) - UX Improvements

  • Setup Wizard Complete step: Consolidated from 4 boxes to 2 boxes for cleaner UX
    • Box 1: "Test Your Setup" - combines Sample Form, Test Form, and Public URL sections
    • Box 2: "What's Next" - links to Form Manager
    • Test Form section now only appears after sample form is created (prevents confusing "Form Not Available" errors)
    • Sample Form marked as "(Optional)" for clarity
  • Form Manager: Added "Created" date column (shows when each form was created)
  • Form Manager: Added column sorting - click any column header to sort ascending/descending
  • Form Editor: Fixed dropdown overflow issue where "Maps to Case Field" dropdown was cut off at bottom of screen
  • Bug fix: Fixed "SObject row was retrieved via SOQL without querying the requested field: Form__c.CreatedDate" error

v0.4.3 (2026-01-29) - Setup Wizard Path Component Fix

  • Fixed: Replaced custom CSS chevron path with standard lightning-progress-indicator component
  • Eliminates persistent white gap issues between chevron steps
  • Native Salesforce component handles complete/current/incomplete styling automatically
  • Simplified codebase: removed ~245 lines of custom CSS and ~50 lines of JS
  • Click navigation on steps still works via data-step attribute

v0.4.2 (2026-01-29) - reCAPTCHA v3 Support & UX Improvements

  • reCAPTCHA v3 Score-based support added alongside v2 Checkbox and v2 Invisible
  • reCAPTCHA Type selector in Setup Wizard with clear descriptions for each type
  • Simplified Score Threshold UX - removed confusing technical input, uses sensible default (0.3)
  • Admins can still adjust threshold via Setup → Custom Metadata Types if needed
  • Updated reCAPTCHA_Settings__c with Captcha_Type__c and Score_Threshold__c fields
  • Server-side v3 score verification with configurable threshold
  • Client-side v3 integration with invisible badge

v0.4.1 (2026-01-29) - Setup Wizard reCAPTCHA Configuration

  • Added Step 5: reCAPTCHA to Setup Wizard (wizard now has 6 steps)
  • Admin-friendly UI for configuring reCAPTCHA API keys without Anonymous Apex
  • Partial updates supported (update Site Key or Secret Key independently)
  • Input validation (max 255 chars, whitespace trimming)
  • "Skip for Now" option for users who don't need CAPTCHA
  • Warning on Complete step if reCAPTCHA was skipped
  • 11 new unit tests for reCAPTCHA settings (41 total in SetupWizardControllerTest)
  • 114 total tests passing across all controllers

v0.4.0 (2026-01-28) - Phase 3: reCAPTCHA Integration

  • Google reCAPTCHA v2 "I'm not a robot" checkbox integration
  • Per-form CAPTCHA toggle (Enable_Captcha__c field)
  • reCAPTCHA_Settings__c protected Custom Setting for API keys
  • Server-side token verification via Google API
  • Client-side CAPTCHA widget with error handling
  • Admin UI "Enable CAPTCHA" toggle in Form Manager
  • Remote Site Setting for Google API callouts
  • 9 new unit tests for CAPTCHA scenarios (22 total in CaseFormControllerTest)
  • 88% code coverage on CaseFormController

v0.3.0 (2026-01-28) - Phase 2: Setup Wizard

  • 5-step post-install setup wizard (expanded to 6 steps in v0.4.1, reduced back to 5 in v0.7.0)
  • Automatic Guest User permission configuration
  • Site detection and selection
  • Manual configuration instructions (Enhanced + Classic Profile UI)
  • Configuration validation
  • Sample form creation
  • Dynamic public URL generation
  • "Web-to-Case Forms" Lightning App in App Launcher
  • SetupWizardController with unit tests
  • Setup_Wizard Lightning tab

v0.2.0 (2026-01-28) - Phase 1: Admin UI

  • LWC Form Manager for creating/editing forms without Setup
  • FormAdminController with CRUD operations (33 tests, 94%+ coverage)
  • formAdminApp component with list view and delete modal
  • formDetail component with inline field editing
  • Clickable form names for quick editing
  • Field reordering with up/down arrows
  • URL hash routing for bookmarkable links
  • Preview mode support (?preview=true)
  • Form_Manager Lightning tab

v0.1.0 (2026-01-28) - Phase 0: MVP

  • Initial release
  • Form__c, Form_Field__c, Error_Log__c custom objects
  • CaseFormController with file attachment support
  • CaseFormPage Visualforce page
  • Basic styling and client-side validation
  • Error logging utility

Manual Testing Still Needed

See the 🧪 MANUAL TESTING REQUIRED section at the top of this README for the current testing checklist.


2GP Package Update Workflow

The devhub runs the managed package. Direct sf project deploy does NOT update managed package components. The only way to update what the user sees is to create a new package version, promote it, and install it.

Steps to Ship a Change

# 1. Commit your changes first (so git log = source of truth)
git add <files> && git commit -m "description"

# 2. Create a new package version
sf package version create --package "Web-to-Case Forms" --target-dev-hub devhub \
  --code-coverage --wait 20 --definition-file config/project-scratch-def.json \
  --installation-key-bypass

# 3. Promote (release) the version
sf package version promote --package <04t...> --target-dev-hub devhub --no-prompt

# 4. Install/upgrade in devhub
sf package install --package <04t...> --target-org devhub \
  --upgrade-type Mixed --wait 10 --no-prompt

# 5. Commit the updated sfdx-project.json (new alias was added in step 2)
git add sfdx-project.json && git commit -m "Package version x.y.z"

# 6. Hard refresh browser (Ctrl+Shift+R) to see changes

Version Numbering Convention

  • Use minor increments for each change: 1.3.0, 1.4.0, 1.5.0, ...
  • 2GP managed packages do NOT support patch versioning (1.2.1) unless enabled via Partner Community case
  • sfdx-project.json uses MAJOR.MINOR.PATCH.NEXT format — always use X.Y.0.NEXT

Common Errors

Error Fix
ErrorAncestorNotHighestRelease Update ancestorVersion in sfdx-project.json to latest released minor (e.g., 1.2.0.LATEST)
A released package version with version number X already exists Bump versionNumber patch or minor
Retrieved LWC shows correct content but org shows old You retrieved the unpackaged copy, not the managed package. Create a new package version and install it.

Pitfalls Learned the Hard Way

  1. Uncommitted changes are NOT reliably in the package. Always git commit before sf package version create.
  2. Retrieving LightningComponentBundle:setupWizard returns the unpackaged copy, not the managed caseform__setupWizard. This is misleading — the managed component shows (hidden) in subscriber orgs.
  3. sf project deploy to devhub creates an unpackaged copy alongside the managed package. The FlexiPages use caseform:setupWizard, so the unpackaged c:setupWizard is never displayed.
  4. Patch versioning (1.2.1) is NOT supported for 2GP managed packages by default. Requires a Partner Community case. Use minor bumps (1.3.0, 1.4.0) instead.
  5. ObjectPermissions and FieldPermissions store namespace-prefixed API names (e.g., caseform__Form__c). Code that queries these setup entities must qualify custom names at runtime.
  6. Daily limit: 6 package version creates per day per dev hub.

Package Version History

v1.8.0.1 (Released) — 2026-02-12

Fix Configuration Status dashboard and Form Manager banner showing prematurely.

  • Subscriber Package Version ID: 04td2000000KAWHAA4
  • Ancestor: v1.7.0.1
  • Install URL: https://login.salesforce.com/packaging/installPackage.apexp?p0=04td2000000KAWHAA4
  • setupStatus.js: isConfigured getter now requires allPermissionsPassed === true
  • SetupWizardController.isSetupComplete(): now calls getSetupStatus() and checks validation.allPassed instead of just checking Default_Site_Id__c
  • Both surfaces correctly hide until the wizard is fully completed (all steps including permission verify)

v1.7.0.1 (Superseded) — 2026-02-12

Auto-configure Apex/VF access, setup banner, tab reorder.

  • Subscriber Package Version ID: 04td2000000KAPpAAO
  • Ancestor: v1.6.0.1
  • Install URL: https://login.salesforce.com/packaging/installPackage.apexp?p0=04td2000000KAPpAAO
  • Setup Wizard Step 3 now auto-grants SetupEntityAccess for Apex classes and VF pages
  • Form Manager tab is now the default/first tab in the app
  • Setup banner in Form Manager warns when Setup Wizard hasn't been completed
  • Namespace-aware fallback instructions in Step 4

v1.6.0.1 (Superseded) — 2026-02-12

Hide Configuration Status card on wizard steps 2-5 and fix scroll jump.

  • Subscriber Package Version ID: 04td2000000KA4rAAG
  • Ancestor: v1.5.0.1
  • Dashboard card only shows on Step 1; hides during wizard steps to reduce noise

v1.5.0.1 (Superseded) — 2026-02-12

Reorder step 4: validation results first, instructions when failures.

  • Subscriber Package Version ID: 04td2000000K9yPAAS
  • Ancestor: v1.4.0.1
  • Step 4 now shows validation results at the top, with manual instructions only when there are failures

v1.4.0.1 (Superseded) — 2026-02-12

Add "Open Site Settings" button to Setup Wizard step 4.

  • Subscriber Package Version ID: 04td2000000K9wnAAC
  • Ancestor: v1.3.0.1
  • Convenience link to Salesforce Site settings page from within the wizard

v1.3.0.1 (Superseded) — 2026-02-12

Fix: Namespace prefix in Guest User permission configuration.

  • Subscriber Package Version ID: 04td2000000K9qLAAS
  • Ancestor: v1.2.0.1
  • Code coverage: 78%
  • Install URL: https://login.salesforce.com/packaging/installPackage.apexp?p0=04td2000000K9qLAAS
  • Installed in dev hub org (dietrich-dev-ed) — verified working
  • Fix: ObjectPermissions and FieldPermissions now use namespace-qualified API names (caseform__Form__c instead of Form__c)
  • Added qualifyApiName() runtime namespace detection in SetupWizardController

v1.2.0.1 (Superseded) — 2026-02-12

Fix: Setup Wizard instructions (text + link).

  • Subscriber Package Version ID: 04td2000000K9jtAAC
  • "Active Site Home Page" text fix, Sites Setup link fix

v1.1.0.2 (Superseded) — 2026-02-12

Did NOT contain the text fix (built from uncommitted working tree).

  • Subscriber Package Version ID: 04td2000000K9TlAAK

v1.0.0.2 (Superseded) — 2026-02-12

Original release.

  • Subscriber Package Version ID: 04td2000000K8xVAAS

Fixes applied during version creation:

  • SetupWizardControllerTest.testPreconditionsAsStandardUser: Changed profile query to filter by PermissionsCustomizeApplication = false AND PermissionsModifyAllData = false (packaging scratch org profiles can have admin perms even if not named "System Administrator")
  • Added @TestVisible to 7 private helper methods in SetupWizardController and 25 new direct unit tests that don't depend on active Sites (coverage: 48% → 68% in packaging scratch org)

Orgs

Alias Username Purpose
devhub tilman.dietrich@gmail.com.freelance Dev Hub org (2GP packaging)
devorg tilman.dietrich@gmail.com.dev Namespace org (caseform registered here)

Package Info

Package Name Web-to-Case Forms
Package ID 0Hod20000000XlZCAU
Package Type 2GP Managed
Namespace caseform
Version Config 1.9.0.NEXT in sfdx-project.json (minor increments — patch versioning not enabled)

Re-enabling reCAPTCHA for v2

All reCAPTCHA code is commented out with /* v2: reCAPTCHA ... */ markers. To re-enable for v2:

1. Restore deleted file:

File Action
Google_reCAPTCHA.remoteSite-meta.xml Re-create Remote Site Setting for https://www.google.com with <isActive>true</isActive>

2. Uncomment Apex code (search for /* v2: reCAPTCHA):

File What to uncomment
CaseFormController.cls 6 methods: getCaptchaSiteKey, getCaptchaType, getCaptchaEnabled, captcha block in submitForm, verifyCaptchaWithDetails, verifyCaptcha
WebToCaseRestAPI.cls enableCaptcha response value, captcha config block
SetupWizardController.cls getReCaptchaSettings, saveReCaptchaSettings, clearReCaptchaSettings, reCAPTCHA block in getFullStatus

3. Uncomment frontend code (search for /* v2: reCAPTCHA):

File What to uncomment
CaseFormPage.page reCAPTCHA script loading, widget rendering, formConfig vars
caseFormScript.js onCaptchaSuccess, captchaResolve, token extraction, grecaptcha refs
caseFormWidget.js Captcha rendering in FormWidget, token handling in SubmissionMixin, ConnectedForm
setupWizard.js Apex imports, tracked properties, 8 handler methods
setupStatus.js CAPTCHA_TYPE_LABELS constant

4. Re-enable UI toggles (search for v1 MVP):

File Change
setupWizard.js Uncomment reCAPTCHA step in STEPS, renumber Complete back to '6'
formDetail.js Change showCaptchaToggle to return true
setupStatus.js Change showRecaptchaPanel to return true

5. Restore permission set and tests:

File What to uncomment
Web_to_Case_Admin.permissionset-meta.xml Enable_Captcha__c FLS entry
CaseFormControllerTest.cls ~16 test methods, 5 HTTP mock classes
SetupWizardControllerTest.cls ~25 reCAPTCHA test methods

Search for v2: reCAPTCHA and v1 MVP across the codebase to find all change points.

Phase 5 Implementation Ideas

Multi-file Upload:

  • Allow multiple file attachments per submission
  • Drag-and-drop file upload UI
  • File type and size validation per file

Custom Field Types:

  • Picklist fields with configurable options
  • Date picker fields
  • Checkbox fields
  • Phone number formatting

Form Analytics:

  • Track form views, submissions, abandonment
  • Success/error rate metrics
  • Time-to-submit analytics

AppExchange Package Metadata

When creating the managed/unlocked package for AppExchange, include the following metadata components:

Custom Objects (4)

Component API Name Description
Custom Object Form__c Form configuration
Custom Object Form_Field__c Form field definitions
Custom Object Error_Log__c Error logging
Custom Object Rate_Limit_Counter__c Rate limit tracking (Phase 4)

Custom Settings (1)

Component API Name Description
Custom Setting (Hierarchy) reCAPTCHA_Settings__c reCAPTCHA API keys and settings (Protected)

Custom Fields - Form__c (11)

Field API Name
Form Name Form_Name__c
Title Title__c
Description Description__c
Success Message Success_Message__c
Active Active__c
Enable File Upload Enable_File_Upload__c
Max File Size MB Max_File_Size_MB__c
Enable Captcha Enable_Captcha__c
Site Id Site_Id__c
Allowed Domains Allowed_Domains__c (Phase 4)
Default Case Values Default_Case_Values__c - JSON defaults for hidden Case fields

Custom Fields - Form_Field__c (6)

Field API Name
Form (Master-Detail) Form__c
Field Label Field_Label__c
Field Type Field_Type__c
Case Field Case_Field__c
Required Required__c
Sort Order Sort_Order__c

Custom Fields - Error_Log__c (4)

Field API Name
Error Message Error_Message__c
Stack Trace Stack_Trace__c
Form Id Form_Id__c
Timestamp Timestamp__c

Custom Fields - reCAPTCHA_Settings__c (6)

Field API Name
Site Key Site_Key__c
Secret Key Secret_Key__c
Captcha Type Captcha_Type__c
Score Threshold Score_Threshold__c
Default Site Id Default_Site_Id__c
Default Site Base Url Default_Site_Base_Url__c

Custom Fields - Rate_Limit_Counter__c (4) - Phase 4

Field API Name
Origin Key Origin_Key__c
Origin Domain Origin_Domain__c
Count Count__c
Hour Bucket Hour_Bucket__c

Apex Classes (15)

Class Description
CaseDefaultFieldConfig Shared allowlist of Case fields for default values
CaseFormController Public form controller
CaseFormControllerTest Test class
ErrorLogger Error logging utility
ErrorLoggerTest Test class
FileAssemblyQueueable Async file chunk assembly for files >2MB (up to 4MB)
FileAssemblyQueueableTest Test class
FormAdminController Form Manager admin controller
FormAdminControllerTest Test class
SetupWizardController Setup Wizard controller
SetupWizardControllerTest Test class
WebToCaseRestAPI REST API for embed widget (Phase 4)
WebToCaseNonceService Nonce management for security (Phase 4)
WebToCaseRateLimiter Rate limiting logic (Phase 4)
WebToCaseRestAPITest Test class (Phase 4)

Lightning Message Channels (1)

Channel API Name Description
Setup Status Refresh SetupStatusRefresh Notifies setupStatus to refresh after wizard completes

Lightning Web Components (4)

Component Description
formAdminApp Form Manager main container
formDetail Form editor with field management
setupStatus Configuration Status Dashboard
setupWizard Post-install setup wizard

Visualforce Pages (1)

Page Description
CaseFormPage Public form page

Static Resources (4)

Resource Description
caseFormStyles Form CSS styling
caseFormScript Form JavaScript (validation, compression, submission)
imageCompression browser-image-compression library for client-side image optimization
caseFormWidget Embeddable widget script for external websites (Phase 4)

Lightning App (1)

App API Name
Web-to-Case Forms Web_to_Case_Forms

Lightning Pages (FlexiPages) (2)

Page API Name
Form Manager Form_Manager
Setup Wizard Setup_Wizard

Custom Tabs (2)

Tab API Name
Form Manager Form_Manager
Setup Wizard Setup_Wizard

Permission Sets (1)

Permission Set API Name
Web-to-Case Admin Web_to_Case_Admin

Remote Site Settings (0)

Google_reCAPTCHA was deleted in v0.8.2 to eliminate the "Approve Third-Party Access" install prompt. Re-create for v2 reCAPTCHA re-enablement.

Platform Cache Partitions (1)

Partition API Name Description
WebToCase WebToCase Stores one-time nonces for replay attack prevention (15-min TTL)

Org-Specific Metadata (Excluded from Package)

The following metadata types are org-specific and should NOT be included in the managed package. Customers configure their own via Salesforce Setup:

  • CORS Whitelist Origins — customers add their own domains
  • CSP Trusted Sites — customers add their own domains
  • Custom Sites — customers create their own Site

These are excluded via .forceignore.

Package.xml Example

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Form__c</members>
        <members>Form_Field__c</members>
        <members>Error_Log__c</members>
        <members>Rate_Limit_Counter__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>reCAPTCHA_Settings__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>CaseDefaultFieldConfig</members>
        <members>CaseFormController</members>
        <members>CaseFormControllerTest</members>
        <members>ErrorLogger</members>
        <members>ErrorLoggerTest</members>
        <members>FileAssemblyQueueable</members>
        <members>FileAssemblyQueueableTest</members>
        <members>FormAdminController</members>
        <members>FormAdminControllerTest</members>
        <members>SetupWizardController</members>
        <members>SetupWizardControllerTest</members>
        <members>WebToCaseRestAPI</members>
        <members>WebToCaseNonceService</members>
        <members>WebToCaseRateLimiter</members>
        <members>WebToCaseRestAPITest</members>
        <name>ApexClass</name>
    </types>
    <types>
        <members>formAdminApp</members>
        <members>formDetail</members>
        <members>setupStatus</members>
        <members>setupWizard</members>
        <name>LightningComponentBundle</name>
    </types>
    <types>
        <members>CaseFormPage</members>
        <name>ApexPage</name>
    </types>
    <types>
        <members>caseFormStyles</members>
        <members>caseFormScript</members>
        <members>imageCompression</members>
        <members>caseFormWidget</members>
        <name>StaticResource</name>
    </types>
    <types>
        <members>Web_to_Case_Forms</members>
        <name>CustomApplication</name>
    </types>
    <types>
        <members>Form_Manager</members>
        <members>Setup_Wizard</members>
        <name>FlexiPage</name>
    </types>
    <types>
        <members>Form_Manager</members>
        <members>Setup_Wizard</members>
        <name>CustomTab</name>
    </types>
    <types>
        <members>Web_to_Case_Admin</members>
        <name>PermissionSet</name>
    </types>
    <!-- Remote Site Setting removed in v0.8.2: Google_reCAPTCHA (re-add for v2) -->
    <types>
        <members>SetupStatusRefresh</members>
        <name>LightningMessageChannel</name>
    </types>
    <types>
        <members>WebToCase</members>
        <name>PlatformCachePartition</name>
    </types>
    <!-- CORS, CSP, and Sites are org-specific — excluded from package -->
    <version>59.0</version>
</Package>

Notes for Packaging

  1. Custom Setting: reCAPTCHA_Settings__c is a Protected Hierarchy Custom Setting. The records themselves (API keys) are NOT included - users configure these post-install via Setup Wizard.

  2. Remote Site Setting: Google_reCAPTCHA was deleted in v0.8.2 to eliminate the "Approve Third-Party Access" install prompt. Re-create when re-enabling reCAPTCHA for v2.

  3. Permission Set: Web_to_Case_Admin grants access to all admin functionality. Assign to users who need to manage forms.

  4. Post-Install Configuration Required:

    • Create/select a Salesforce Site
    • Configure Guest User permissions (via Setup Wizard)
    • Grant Apex class and VF page access to Guest User profile
    • (v2 only) Add reCAPTCHA API keys via Setup Wizard
  5. Test Coverage: All Apex classes have >75% code coverage. 257 tests passing, 64% org-wide coverage.

  6. Platform Cache: The WebToCase cache partition is required for nonce-based replay attack prevention. The org must have Platform Cache allocated (at least session cache).

  7. CORS, CSP & Sites: Org-specific metadata (CORS origins, CSP trusted sites, Site config) has been removed from the project and excluded via .forceignore. Customers configure their own domains post-install.

  8. Site Metadata: Customers using iframe embed mode need AllowAllFraming on their Site (documented in post-install Setup Wizard).

About

Salesforce AppExchange app - Web-to-Case with file attachments

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors