HandleInertiaRequests::share() is an Inertia shared-data provider and should be
read-only, but it ran a DELETE + UPDATE against the user on every non-API web
GET to purge the leftover encryption salt and EncryptedMessage once a user no
longer had any encrypted accounts or transactions. Writing to the database
while resolving render props is a side effect in the wrong place.
The existing encryption commands do not cover this case: both
NotifyEncryptedDataRemovalCommand and DeleteEncryptedDataAccountsCommand target
users who *still* have encrypted data, whereas this cleanup finalizes users who
have *finished* decrypting. To preserve that eventual-cleanup semantics without
writing during the render, the work now goes to a new
PurgeResidualEncryptionArtifactsJob dispatched from share(). The job re-checks
the condition on execution and is idempotent, so repeat dispatches are no-ops.
The two ->exists() checks stay because they still feed the hasEncryptedAccounts
and hasEncryptedTransactions props.
Tests: InertiaSharedDataTest asserts a web GET no longer mutates the user inline
and instead queues the job (and does not queue it when there is no salt); a new
PurgeResidualEncryptionArtifactsJobTest covers the clear, the two 'still has
encrypted data' guards, and the null-salt no-op.