Audit of all 28 "backward compatibility" instances across the codebase, grouped into 7 cleanup tasks prioritized by impact. App is not live yet so all compat shims should be removed to build clean target state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.8 KiB
Backward Compatibility Cleanup Plan
Date: 2026-02-14 Status: Proposed Motivation: The app is not live yet. All backward compatibility shims should be removed to build the clean target state.
Inventory: 28 instances found, grouped into 7 cleanup tasks
Task 1: Remove legacy location field from Inventory model (HIGH)
Files:
app/modules/inventory/models/inventory.py:33— legacylocation = Column(String)fieldapp/modules/inventory/services/inventory_service.py:90,158— writeslocation=locationalongside newbin_location
What exists: The old single location field (e.g., "SA-10-02") is kept in parallel with the new warehouse + bin_location split. Every inventory write populates both.
Cleanup:
- Remove
locationcolumn fromInventorymodel - Remove
location=locationfrom both create paths ininventory_service.py - Search all reads of
.locationand migrate to.bin_locationor.warehouse - Update
__repr__method - Create Alembic migration to drop the column (data already in
bin_location)
Task 2: Remove dashboard backward-compat helpers + legacy stat fields (HIGH)
Files:
app/modules/core/routes/api/admin_dashboard.py:73-107,146,149— helper functions_extract_metric_value(),_widget_list_item_to_dict(),_extract_widget_items()that transform new aggregator data to old response formatapp/modules/analytics/services/stats_service.py:294-299,494-498— duplicate legacy fields (total_stores,active_stores,total_imports,completed_imports, etc.) alongside new schema-compatible fields
What exists: The dashboard endpoint transforms the new provider-based aggregator output into an old flat response. Stats service returns both old and new field names.
Cleanup:
- Remove the three
_extract_*helper functions fromadmin_dashboard.py - Return aggregator data directly from endpoints
- Remove legacy field names from
get_store_statistics()andget_import_statistics()instats_service.py - Keep only the schema-compatible field names (
total,verified,pending, etc.) - Update frontend to consume the new field names
Task 3: Remove re-export shims and aliases (MEDIUM)
Files:
app/core/frontend_detector.py:200-207—get_frontend_type()wrapper aroundFrontendDetector.detect()app/modules/task_base.py:169-170—DatabaseTask = ModuleTaskaliasapp/modules/cms/routes/api/admin.py:26-27—router = admin_routeraliasapp/modules/cms/routes/store.py— entire file re-exportsstore_routerfromroutes/api/store.pyapp/modules/payments/routes/__init__.py— re-exportsadmin_router,store_routerfromroutes/api/app/modules/analytics/schemas/stats.py:18-34,154-169— re-exports core dashboard schemasapp/modules/billing/services/subscription_service.py:33— re-exportsSubscriptionNotFoundExceptionapp/modules/tenancy/models/admin.py:60-61— comment aboutAdminNotificationre-export viamodels/database/__init__.pyapp/modules/dev_tools/models/test_run.py:7— re-export commentapp/modules/dev_tools/models/architecture_scan.py:7— re-export commentapp/modules/dev_tools/tasks/test_runner.py:7— re-export commentapp/modules/dev_tools/tasks/code_quality.py:7— re-export commentapp/modules/dev_tools/schemas/__init__.py:6— re-export comment
What exists: A collection of aliases, wrapper functions, and re-export modules that allow old import paths to keep working after code was moved or renamed.
Cleanup (per item):
| Item | Action |
|---|---|
get_frontend_type() |
Delete function. Update callers to FrontendDetector.detect() |
DatabaseTask = ModuleTask |
Delete alias. Rename all DatabaseTask imports to ModuleTask |
router = admin_router (CMS) |
Delete alias. Update imports to use admin_router |
cms/routes/store.py |
Delete file. Update cms/definition.py to import from routes/api/store |
payments/routes/__init__.py |
Clear re-exports. Update payments/definition.py to import from routes/api/ |
analytics/schemas/stats.py re-exports |
Remove re-export block. Update all imports to core.schemas.dashboard |
SubscriptionNotFoundException re-export |
Remove import. Update callers to import from billing.exceptions |
AdminNotification re-export |
Find and remove from models/database/__init__.py. Update imports to messaging.models.admin_notification |
| dev_tools comments | Remove backward compat comments. Verify no legacy import paths exist |
Task 4: Remove module-enabling JSON fallback (MEDIUM)
Files:
app/modules/service.py:140-174— falls back fromPlatformModulejunction table toPlatform.settings["enabled_modules"]JSON, then to "enable all modules"
What exists: Three-tier fallback for determining which modules are enabled:
PlatformModulejunction table (new, auditable)Platform.settings["enabled_modules"]JSON field (old)- Enable all modules if nothing configured (oldest)
Cleanup:
- Remove the JSON fallback path (lines ~166-174)
- Remove the "enable all" default
- Require explicit
PlatformModulerecords - Seed scripts should create
PlatformModuleentries for all platforms - Remove
_migrate_json_to_junction_table()helper if no longer needed - Update
app/modules/service.pydocstring
Task 5: Remove marketplace title/description compat + menu legacy format (MEDIUM)
Files:
app/modules/marketplace/services/marketplace_product_service.py:116-118— stripstitle/descriptionfrom product data dict before DB insert (old fields moved to translations table)app/modules/core/services/menu_service.py:263— converts new menu structure to legacy format viamenu_to_legacy_format()
Cleanup:
- Marketplace: Remove
product_dict.pop("title", None)andproduct_dict.pop("description", None). Remove these fields fromMarketplaceProductCreate/MarketplaceProductUpdateschemas if present. - Menu: Remove
menu_to_legacy_format()call. Return new menu structure directly. Update templates to consume the new format.
Task 6: Clean up billing convenience methods (LOW)
Files:
app/modules/billing/services/subscription_service.py:164—get_subscription_for_store()resolves store → merchant → platform → subscriptionapp/modules/billing/services/feature_service.py:223—has_feature_for_store()resolves store → merchant/platform → feature check
What exists: Convenience methods that hide the merchant/platform hierarchy from store-level callers.
Cleanup:
- Find all callers of
get_subscription_for_store()andhas_feature_for_store() - Refactor callers to resolve the merchant/platform explicitly
- Remove the convenience methods
- Or: rename them to
resolve_subscription_for_store()and drop the "backward compat" comment — these may be genuinely useful abstractions even in the target state
Note: These might actually be worth keeping as they provide a clean API. The decision is whether the store→merchant→platform resolution is truly "backward compat" or just a useful service abstraction. If kept, just remove the "backward compatibility" comments.
Task 7: Clean up test fixtures and test comments (LOW)
Files:
tests/fixtures/auth_fixtures.py:52,133—is_super_admin=Trueon test_admin fixtures "for backward compatibility"tests/integration/middleware/test_merchant_domain_flow.py:10,98— test verifying subdomain routing "backward compatibility"app/modules/tenancy/schemas/store.py:209— language field defaults "for backward compatibility"app/modules/tenancy/routes/api/admin_stores.py:213— deprecated store-level ownership transfer endpointapp/modules/registry.py:67-79—__getattr__lazy module variablesalembic/versions_backup/— migration references (leave as-is, it's history)
Cleanup:
| Item | Action |
|---|---|
| Auth fixtures | Remove "backward compat" comment. Decide if test_admin should be super_admin or not based on what tests actually need |
| Merchant domain test | Remove "backward compat" from docstring. This is just testing subdomain routing — a current feature, not a compat shim |
| Store schema language defaults | Remove "backward compat" comment. These are just sensible defaults |
| Admin stores endpoint | Remove deprecated ownership transfer endpoint entirely if merchant-level endpoint exists |
Registry __getattr__ |
Either migrate all callers to function calls, or keep the pattern and remove the "backward compat" comment (lazy loading is a valid pattern) |
| Alembic backup | Leave as-is — migration history should not be modified |
Execution Order
Task 1 (inventory location) ████████████ HIGH — DB column removal, needs migration
Task 2 (dashboard/stats) ████████████ HIGH — API response shape change
Task 3 (re-export shims) ████████ MEDIUM — mechanical find-and-replace
Task 4 (module-enabling JSON) ████████ MEDIUM — seed script update needed
Task 5 (marketplace/menu) ████████ MEDIUM — schema + template changes
Task 6 (billing convenience) ████ LOW — may decide to keep
Task 7 (tests/comments) ████ LOW — mostly comment removal
Tasks 1-2 are the most impactful (actual dead code/fields). Tasks 3-5 are mechanical cleanup. Tasks 6-7 are mostly comment/naming hygiene.
Verification
After each task:
python -c "from main import app; print('OK')"
python -m pytest tests/ app/modules/*/tests/ -v --timeout=60
python scripts/validate/validate_architecture.py -v
After all tasks:
grep -rn "backward.compat\|backwards.compat" --include="*.py" | grep -v alembic
# Should return 0 results (alembic history excluded)