This ensures that CareerPlug webhooks are only created after the account
transaction has been successfully committed to the database. This prevents
orphaned webhook records if account creation fails or is rolled back.
The change improves data consistency and follows Rails best practices for
callbacks that create associated records or have external side effects.
Includes tests to verify that:
- Webhooks are created after successful account creation
- Webhooks are not created if account creation fails/rolls back
- Webhooks are not created when CAREERPLUG_WEBHOOK_SECRET is blank
This pull request enhances the audit logging capabilities within DocuSeal to granularly track user actions and data changes.
Key Changes:
* User Attribution: Added user_id to SubmissionEvent to identify exactly who performed an action.
* Granular Change Tracking: Implemented a new form_update event type that records specific field changes, capturing both previous and new values (from -> to).
* Enhanced Exports & Webhooks: Updated ExportSubmissionService and SendFormCompletedWebhookRequestJob to include detailed form values and the full submission event history in their outputs.
* Refactoring: Updated controllers and services to propagate the current_user context for accurate tracking.
* Testing: Added specs to verify the correct recording of form field updates and data integrity in exports.
* Fix PDF regeneration after change requests
Allow PDFs to be regenerated when a submitter re-completes after a change
request by using timestamp-based detection. This ensures new PDFs are
generated while preserving old ones for audit trail.
Changes:
- Allow multiple 'complete' events per submitter (remove unique constraint)
- Compare event timestamps with completion time to detect stale events
- Add current_documents method to get latest PDF generation
- Prevent waiting forever on stale retry/start events from previous attempts
* Update audit trail generation for change requests
Regenerate audit trail PDF when submitter re-completes after a change request.
Remove DocuSeal branding from audit trail header and add missing translations
for request_changes events.
Changes:
- Regenerate audit trail when created before latest completion timestamp
- Remove DocuSeal logo and branding from audit trail header
- Add request_changes_by_html translations (English and Spanish)
- Generate new audit trail before cleaning up old ones (safer approach)
- Clean up old audit trail PDFs, keeping only the newest
* Change 'Request Changes' button text to 'Submit'
* Remove Download button from submissions view
* Fix download endpoint to return current documents after re-completion
* Add comprehensive tests and apply rubocop fixes
- Add tests for Submitter#current_documents method
- Add tests for PDF regeneration on re-completion
- Add tests for audit trail regeneration logic
- Apply rubocop fixes: use Rails range syntax, fix indentation
- Extract generate_and_record_documents to reduce method length
* fix potential NoMethodError and rubocop fixes
* Use ActiveStorage::Attachment directly instead of `#audit_trail`
* Fix line length in `process`
* Scope email and external_user_id uniqueness to account
Allow the same email and external_user_id to exist across different accounts
while maintaining uniqueness within each account.
Changes:
- Scope external_user_id uniqueness to account_id
- Scope email uniqueness to account_id
- Remove Devise :validatable to avoid global email uniqueness
- Update ExternalAuthService to use account-scoped queries
- Update TokenRefreshService to use account-scoped queries
- Add custom email validation with account scope
* Add and update tests for account-scoped user uniqueness
* Run migrations and update schema
* Document account-scoped user lookup behavior
* skip password test
* we use access token validation via iframe, not passwords so this test is not necessary.
* update test for rubocop
* Add download URL generator endpoint for API
* rubocop/spec fixes
* move logic out of view into controller
* move build_signed_urls method logic into new SignedDocumentUrlBuilder service
* slim down controller and its request specs
* Fix download filenames to exclude CloudFront query parameters
- Strip query parameters from URLs before extracting filenames in download buttons
- Add Content-Disposition headers to CloudFront signed URLs for proper browser filename handling
* remove Download combined PDF
* we don't do multiple submissions in the iframe, so this button is not needed
* line length fix
* add fallback filename and tests
* rubocop changes
* refactor build_cloudfront_url
reduce complexity of method by extracting into other methods, also reduces need for more in line comments.
* remove unused buttons
* remove "Resubmit" button and Docuseal logo/header in iframe
* remove template name in preview
* fix line length
* allow there to be no header
* fixed failing tests expecting header
* we don't typically want the header rendered in the iframe
* fix erb_lint violation
* Add partnership template authorization and ability system
* Update template authorization to support partnership context
* Add request context-based authorization for API access
* Implement hybrid partnership/account authorization logic
* Add submission authorization conditions for partnerships
* Support global partnership template access
* Add template cloning services for partnership workflows
* Update template cloning to require explicit target parameters, to allow for cloning for either account or from partnership
* Add Templates::CloneToAccount service for partnership to account cloning
* Add Templates::CloneToPartnership service for global to partnership cloning
* Add logic to detect account vs partnership template cloning with validation
* Add folder assignment logic for cloned templates
* Add external authentication and partnership support
* Update ExternalAuthService to support partnership OR account authentication
* Implement user assignment to accounts when partnership context is provided
* Support pure partnership authentication without account assignment
* Update API controllers for partnership template support
* Add partnership request context to API base controller
* Update submissions controller to support partnership templates
* Add partnership template cloning to templates clone controller
* Refactor template controller webhook logic to reduce complexity
* Support external_account_id parameter for partnership workflows
* Update web controllers and views for partnership template support
* Add tests
* erb_lint fixes
* add local claude file
* shared concern for handling partnership context
* remove overly permissive case
* global templates should be available for partnerships and accounts
* pass through access context in vue
* add tests
* add partnership context and tests to submissions
* add token refresh as last resort for a corrupted token
Remove hardcoded CloudFront domains and key pair IDs from repository.
All CloudFront configuration now loaded from ENV variables for security:
- CF_URL: CloudFront distribution URL
- CF_KEY_PAIR_ID: CloudFront key pair identifier
- CF_KEY_SECRET: AWS Secrets Manager path for private key
- SECURED_STORAGE_BUCKET: S3 bucket name
- SECURED_STORAGE_REGION: AWS region
This prevents exposure of infrastructure identifiers in public repository.
Configuration should be set via cpdocuseal deployment module.
- Migration updates to change data type from integer to string for external_account_group_id
- Updated database schema and annotation comments
- Fixed service parameter type handling
- Updated test expectations to match new string type
- Added storage location field and index for completed documents
- Removed obsolete search_entries table from schema
Implement compliance storage configuration using AWS CloudFront signed URLs for completed documents. This reuses the existing ATS infrastructure to provide secure, time-limited access to document storage while maintaining backward compatibility with legacy storage.
- Add aws-sdk-cloudfront dependency for URL signing
- Create DocumentSecurityService for CloudFront signed URL generation
- Add secured storage service configuration in storage.yml
- Update completed_documents model with storage_location tracking
- Modify download controllers to use signed URLs for secured storage
- Add compliance_storage.yml configuration for different environments
- Update submitter completion job to track storage location
BREAKING CHANGE: Requires SECURED_STORAGE_BUCKET and SECURED_STORAGE_REGION environment variables for staging/production environments
* account group to partnership rename
* this is mostly converting the name account_group => partnership
* partnership user relationships are API request based
* so we don't need to maintain relational information in two databases, this many to many relationship is now handled via API context
* rubocop and test fixes
- Add account_groups table and model
- Add account_group references to accounts, users, templates, template_folders
- Make account_id nullable on users, templates, template_folders
- Add controllers and specs
* Consolidate account groups migrations
- Replace 8 separate migrations with 2 consolidated ones
- Create account groups and relationships in one migration
- Make account_id columns nullable in second migration
* this logic is being handled in external_auth_controller
* remove unnecessary controllers
* remove unnecessary routes
* refactor account_group.default_template_folder
* align method with Account version of this method
* refactor controllers to move complex logic to service
* move account/account group validation to concern
* this method is not yet needed
* we may implement this differently in next ticket to handle account and account group syncing for templates.
* rubocop violation fixes
* a few more refactors and add tests
* Change external_account_group_id to integer type
* Refactored external_account_group_id from string to integer in models, migrations, factories, and specs for consistency.
* Merged account_id nullability changes into a single migration and removed the obsolete migrations.
* Updated authentication logic to require either account or account_group presence for user activation.