Skip to content

refactor(handlers): extract the admin dispatcher into admin_dispatcher - #844

Closed
dmeiser wants to merge 6 commits into
fm/KW-ISSUE-773-SHIP-5from
fm/KW-ISSUE-773-SHIP-6
Closed

dmeiser wants to merge 6 commits into
fm/KW-ISSUE-773-SHIP-5from
fm/KW-ISSUE-773-SHIP-6

Conversation

@dmeiser

@dmeiser dmeiser commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Closes #773

Final slice of the admin_operations.py split: the dispatcher moves into its final home and admin_operations.py (1,838 lines at the start of #773) ends at 166 lines. Zero behavior change.

What changed

  • New src/handlers/admin_dispatcher.py (105 lines): the _OPERATION_HANDLERS map and lambda_handler, moved byte-identical, plus the 8 handler imports that feed the map.
  • src/handlers/admin_operations.py (271 → 166 lines): keeps the shared helpers the admin_* modules import (audit/auth helpers, throttling/batch-lookup classifiers) and re-exports lambda_handler, so the Terraform-wired entry point handlers.admin_operations.lambda_handler is unchanged — no IaC, no AppSync change.
  • AGENTS.md: two stale module pointers corrected.

The six slices

  1. refactor(handlers): extract admin user listing & search into admin_user_operations #833 — admin_user_operations
  2. refactor(handlers): extract adminPurgeUserAccount handler into admin_account_purge #836 — admin_account_purge
  3. refactor(handlers): extract createManagedCatalog handler into admin_catalog_operations #839 — admin_catalog_operations
  4. refactor(handlers): extract adminDeleteUser* per-entity handlers into admin_user_deletion #840 — admin_user_deletion
  5. refactor(handlers): extract adminGetUser*, share/campaign, and credential reset handlers #843 — admin_user_reads, admin_share_campaign_ops, admin_credential_reset
  6. refactor(handlers): extract the admin dispatcher into admin_dispatcher #844 — admin_dispatcher; admin_operations.py → 166 lines

Tests

No test changes: 1841 passed, 2 skipped, 100% coverage (same counts as slice 5); ruff check/format (changed files), mypy strict, xenon Grade A/B, tofu validate (dev), cspell — clean.

…er_operations

Slice 1 of the admin_operations split (#773): move the user
listing/search concern (adminListUsers, adminSearchUser and their
private helpers) from the 1,838-line admin_operations module into
src/handlers/admin_user_operations.py, with zero behavior change.

- Handler/helper bodies are moved verbatim. The only adjustments:
  the two Cognito throttling branches now reference
  TRANSIENT_ERROR_CODES directly (the file-local alias is unchanged
  in admin_operations, and the same frozenset comes from
  utils.dynamodb), and _raise_batch_lookup_error / _actor_sub are
  imported at function level from admin_operations (a top-level
  import would be circular: the dispatcher map imports these
  handlers), following the established campaign_operations precedent.
- The Lambda entry point (handlers.admin_operations.lambda_handler)
  and the AppSync handler mapping are unchanged: admin_operations
  imports the two handlers for its operation dispatcher map. No IaC
  change: the Lambda payload already ships the whole src/ tree.
- Tests: patch targets for the moved symbols are repointed to
  src.handlers.admin_user_operations; the
  test_cognito_filter_call_sites and test_admin_group_name_contract
  table rows follow the moved call sites.
- Verified: uv run pytest tests/unit -q (1841 passed, 100%
  coverage), ruff check, ruff format --check, mypy src/ (strict),
  xenon complexity gate, cspell, and tofu validate on the dev
  environment.
…account_purge

Moves the whole account-purge concern (the adminPurgeUserAccount handler
plus its private helpers) out of admin_operations into its own module,
continuing the #773 extraction. Zero behavior change: the dispatcher map
in admin_operations keeps registering the handler (the dispatcher stays the
single registry), the module is imported back for that map only at module
load, and every shared helper is imported inside functions to keep the
load-time acyclic edge.

Test patch targets and inline imports follow the code to the new module
namespace; the code itself is byte-identical (verified), including the
function-level import of the shared helpers from admin_operations.
…atalog_operations

Slice 3 of the #773 admin_operations split: move the managed-catalog
creation concern (the createManagedCatalog handler plus its private
validation/build/persist helpers) from admin_operations into its own module
src/handlers/admin_catalog_operations.py, with zero behavior change.

- The seven functions (_parse_product_price, _validate_and_process_product,
  _validate_catalog_input, _build_catalog_item, _persist_catalog,
  _require_admin_and_get_actor_sub, create_managed_catalog) move verbatim; the
  only textual difference is the file-boundary newline, because
  create_managed_catalog is now the module's last function.
- This is the cleanest of the three extractions: every private helper it uses,
  including _require_admin_and_get_actor_sub, is used only by the
  createManagedCatalog handler, so the whole concern travels to the new module
  with no function-level import from admin_operations at all.
- The dispatcher map in admin_operations stays the single registry: it imports
  create_managed_catalog back at module load (safe — the new module imports
  nothing from this module), and the AppSync handler mapping plus the Lambda
  entry point are unchanged. No IaC change: the Lambda payload ships the whole
  src/ tree.
- admin_operations drops its now-unused `import uuid` and the
  `Decimal`/`InvalidOperation` imports.
- Tests: the create_managed_catalog import in test_admin_operations.py is
  repointed to the new module, and the two `tables` patch targets in
  TestCreateManagedCatalog follow the code to
  src.handlers.admin_catalog_operations; no test logic changed.

Verified: uv run pytest tests/unit -q (1841 passed, 2 skipped, 100% coverage),
ruff check src/ tests/, ruff format --check src/, mypy src/ (strict), xenon
A/B complexity gate, cspell on the changed files, and tofu validate (dev).
… admin_user_deletion

Slice 4 of the #773 admin_operations split: move the per-entity user deletion
concern (the four adminDeleteUser* handlers plus their shared profile-sweep
helper) from admin_operations into its own module
src/handlers/admin_user_deletion.py, with zero behavior change.

- The five functions (_user_profiles_for, admin_delete_user_orders,
  admin_delete_user_campaigns, admin_delete_user_shares,
  admin_delete_user_profiles) move byte-identical; the only textual difference
  is the function-level import of _require_admin_and_get_target_account_id
  from .admin_operations in each handler (same convention as
  admin_account_purge, since a top-level import would be circular).
- admin_operations keeps the dispatcher as the single registry (it imports the
  four handlers back at module load) and drops the four delete_user_* names
  from its .deletion_cascade import. The AppSync mapping and the Lambda entry
  point are unchanged; no IaC change (the payload ships the whole src/ tree).
- Line counts: src/handlers/admin_operations.py 839 -> 775;
  src/handlers/admin_user_deletion.py 123 (new).

Tests:
- tests/unit/test_admin_operations.py: repoint the 21 function-local imports
  of the four handlers from src.handlers.admin_operations to
  src.handlers.admin_user_deletion; no test logic and no patch target changed
  (the suites mock src.handlers.deletion_cascade.tables /
  src.handlers.campaign_operations.tables, which stay put).
- Full unit suite green (1841 passed, 2 skipped, 100% coverage),
  ruff check src/ tests/ + ruff format --check src/, mypy src/ (strict),
  xenon A/B complexity gate, cspell on the changed files, and
  tofu validate (dev).
…tial reset handlers

Slice 5 of the #773 admin_operations split: move the remaining read and
update handlers (the account-scoped adminGetUser* reads, the profile-share
and campaign shared-code mutations, and adminResetUserPassword) from
admin_operations into their own modules, with zero behavior change.

- The 24 functions move byte-identical; the only textual difference is the
  in-function import of the shared helpers (_require_admin_and_get_target_account_id
  / _actor_sub) from .admin_operations in the 8 handlers that need them, the
  same convention admin_account_purge / admin_user_deletion already use (a
  top-level import would be circular).
- Three new modules:
  - admin_user_reads.py: adminGetUser{Profiles,Catalogs,Campaigns,
    SharedCampaigns} plus the campaign-catalog batch helpers.
  - admin_share_campaign_ops.py: adminGetProfileShares, adminDeleteShare,
    adminUpdateCampaignSharedCode plus their helpers.
  - admin_credential_reset.py: adminResetUserPassword plus its helpers.
- admin_operations keeps the dispatcher as the single registry (it imports the
  eight handlers back at module load) and drops the 24 moved functions and the
  now-unused imports. The AppSync mapping and the Lambda entry point are
  unchanged; no IaC change (the Lambda package ships the whole src/ tree).
- Line counts: admin_operations.py 775 -> 271; admin_user_reads.py 287 (new),
  admin_share_campaign_ops.py 247 (new), admin_credential_reset.py 126 (new).

Tests:
- tests/unit/test_admin_operations.py: 34 function-local patch/import targets
  repointed off src.handlers.admin_operations (16 to admin_credential_reset,
  11 to admin_user_reads, 6 to admin_share_campaign_ops, and 1 to
  deletion_cascade.tables where that handler reads its tables, the base's
  admin_operations.tables patch there being a no-op), plus the module-level
  handler/helper imports; no test logic changed.
- tests/unit/test_cognito_filter_call_sites.py: the _find_user_by_email row now
  points at admin_credential_reset.
- Full unit suite green (1841 passed, 2 skipped, 100% coverage),
  ruff check src/ tests/ + ruff format --check, mypy src/ (strict),
  xenon A/B complexity gate. No IaC or frontend change.
Slice 6 (final) of #773. The operation map and the lambda_handler entry
point move byte-identical from admin_operations.py into a new
admin_dispatcher.py module. admin_operations.py keeps the shared helpers
the admin_* modules import (audit/auth helpers, throttling and
batch-lookup-error classifiers) and re-exports lambda_handler, so the
Terraform-wired Lambda entry point handlers.admin_operations.lambda_handler
is unchanged: no IaC change, no AppSync change.

Also corrects two stale module pointers in AGENTS.md (the dispatcher
pattern example and the admin list handler locations).
@dmeiser dmeiser added the no-release No release/version bump expected from this change label Oct 26, 2026
@dmeiser
dmeiser force-pushed the fm/KW-ISSUE-773-SHIP-5 branch 2 times, most recently from b387a4f to 93e4895 Compare October 27, 2026 00:07
@dmeiser

dmeiser commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

Content already merged in main (commits bba89e0, 6471657, f668ec7, cabbcd4, 893448f, e0681f6)

@dmeiser dmeiser closed this Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-release No release/version bump expected from this change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant