feat(api): expose reset status polling (#1598)

* feat(api): expose reset status polling

* fix(api): hide reset enqueue exception details

* fix(api): use stable reset authorization message

* fix(api): narrow reset enqueue error handling

* fix(api): document reset enqueue failures

* docs(api): regenerate reset status OpenAPI

* fix(api): address reset polling review feedback
This commit is contained in:
ghost
2026-05-02 14:56:42 -06:00
committed by GitHub
parent 95c2208bdb
commit a8425a2488
6 changed files with 330 additions and 10 deletions

View File

@@ -42,23 +42,28 @@ RSpec.describe 'API V1 Users', type: :request do
description 'Resets all financial data (accounts, categories, merchants, tags, etc.) ' \
'for the current user\'s family while keeping the user account intact. ' \
'The reset runs asynchronously in the background. ' \
'The returned job_id is informational only; reset status is family-scoped, not job-scoped. ' \
'Requires admin role.'
security [ { apiKeyAuth: [] } ]
produces 'application/json'
response '200', 'account reset initiated' do
schema '$ref' => '#/components/schemas/SuccessMessage'
schema '$ref' => '#/components/schemas/ResetInitiatedResponse'
run_test!
end
response '401', 'unauthorized' do
schema '$ref' => '#/components/schemas/ErrorResponse'
let(:'X-Api-Key') { 'invalid-key' }
run_test!
end
response '403', 'forbidden - requires read_write scope and admin role' do
schema '$ref' => '#/components/schemas/ErrorResponse'
let(:api_key) do
key = ApiKey.generate_secure_key
ApiKey.create!(
@@ -72,6 +77,49 @@ RSpec.describe 'API V1 Users', type: :request do
run_test!
end
response '500', 'reset enqueue failed' do
schema '$ref' => '#/components/schemas/ErrorResponse'
before do
allow(FamilyResetJob).to receive(:perform_later).and_raise(StandardError, 'queue down')
end
run_test!
end
end
end
path '/api/v1/users/reset/status' do
get 'Retrieve reset status' do
tags 'Users'
description 'Returns counts of family-owned data targeted by account reset. ' \
'Use this after DELETE /api/v1/users/reset to decide whether reset materialization has completed. ' \
'Completion is a counts-based family snapshot and may change if new data is created after reset.'
security [ { apiKeyAuth: [] } ]
produces 'application/json'
response '200', 'reset status returned' do
schema '$ref' => '#/components/schemas/ResetStatusResponse'
run_test!
end
response '401', 'unauthorized' do
schema '$ref' => '#/components/schemas/ErrorResponse'
let(:'X-Api-Key') { 'invalid-key' }
run_test!
end
response '403', 'forbidden - requires admin role' do
schema '$ref' => '#/components/schemas/ErrorResponse'
let(:role) { :member }
run_test!
end
end
end
@@ -114,6 +162,7 @@ RSpec.describe 'API V1 Users', type: :request do
schema '$ref' => '#/components/schemas/ErrorResponse'
before do
api_key
allow_any_instance_of(User).to receive(:deactivate).and_return(false)
allow_any_instance_of(User).to receive(:errors).and_return(
double(full_messages: [ 'Cannot deactivate admin with other users' ])