feat(subscriptions): migrate subscription management to merchant level and seed tiers

Move subscription create/edit from store detail (broken endpoint) to merchant
detail page with proper modal UI. Seed 4 subscription tiers (Essential,
Professional, Business, Enterprise) in init_production.py. Also includes
cross-module dependency declarations, store domain platform_id migration,
platform context middleware, CMS route fixes, and migration backups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 21:04:04 +01:00
parent 7feacd5af8
commit 68493dc6cb
97 changed files with 13286 additions and 77 deletions

View File

@@ -0,0 +1,239 @@
# Session Note: IMPORT-002 Cross-Module Dependency Cleanup
**Date:** 2026-02-09
**Status:** Part A complete, Part B deferred
**Priority:** Medium — architecture cleanup (no runtime crashes, but undeclared dependencies)
**Follows:** SESSION_NOTE_2026-02-03_module-dependency-redesign.md
---
## Context
After fixing all IMPORT-001 violations (core → optional) in previous sessions, the architecture validator now passes with **0 errors and 40 IMPORT-002 warnings**. These are all optional → optional cross-module imports without declared dependencies.
Billing module is fully clean — zero violations.
---
## Current `requires=[]` Declarations
| Module | Currently declares |
|--------|--------------------|
| catalog | `requires=["inventory"]` |
| marketplace | `requires=["inventory"]` |
| orders | `requires=["payments"]` |
| inventory | *(nothing)* |
| cart | `requires=["inventory"]` |
| analytics | *(nothing)* |
---
## Part A: Declare Dependencies (30 warnings — trivial fixes)
These are **hard dependencies** where the source module fundamentally cannot function without the target. Fix is adding to `requires=[]` in each module's `definition.py`.
### A1. marketplace → add `catalog`, `orders`
**Change:** `requires=["inventory"]``requires=["inventory", "catalog", "orders"]`
**File:** `app/modules/marketplace/definition.py`
**Warnings resolved:** 9
| File | Imports from | What |
|------|-------------|------|
| `services/marketplace_product_service.py:862-863` | catalog | `Product` model |
| `services/letzshop_export_service.py:16` | catalog | `Product` model |
| `services/letzshop/order_service.py:26-27` | catalog, orders | `Order`, `OrderItem`, `Product` models |
| `services/letzshop/order_service.py:17` | orders | `order_service` |
| `services/marketplace_product_service.py:1006` | orders | order-related import |
| `routes/api/admin_letzshop.py:23-24` | orders | `OrderHasUnresolvedExceptionsException`, `order_item_exception_service` |
| `routes/api/store_letzshop.py:24-25` | orders | `OrderHasUnresolvedExceptionsException`, `order_item_exception_service` |
**Rationale:** Marketplace syncs products and imports orders from Letzshop. No products or orders = no marketplace.
---
### A2. orders → add `catalog`, `inventory`
**Change:** `requires=["payments"]``requires=["payments", "catalog", "inventory"]`
**File:** `app/modules/orders/definition.py`
**Warnings resolved:** 9
| File | Imports from | What |
|------|-------------|------|
| `services/order_item_exception_service.py:22,26` | catalog | `ProductNotFoundException`, `Product` |
| `services/order_service.py:51` | catalog | `Product` model |
| `services/order_inventory_service.py:17-28` | inventory | `Inventory`, `InventoryTransaction`, `TransactionType`, exceptions, schemas, service (6 imports) |
| `services/order_service.py:29` | inventory | `InsufficientInventoryException` |
**Rationale:** Order line items reference products. Order fulfillment manages stock via `order_inventory_service.py`. Both are fundamental.
---
### A3. inventory → add `catalog`
**Change:** `requires=[]``requires=["catalog"]`
**File:** `app/modules/inventory/definition.py`
**Warnings resolved:** 7
| File | Imports from | What |
|------|-------------|------|
| `services/inventory_service.py:15,33` | catalog | `ProductNotFoundException`, `Product` |
| `services/inventory_transaction_service.py:14,19` | catalog | `ProductNotFoundException`, `Product` |
| `services/inventory_import_service.py:27` | catalog | `Product` |
**Rationale:** Every inventory record tracks stock for a product. No products = no inventory.
---
### A4. cart → add `catalog`
**Change:** `requires=["inventory"]``requires=["inventory", "catalog"]`
**File:** `app/modules/cart/definition.py`
**Warnings resolved:** 2
| File | Imports from | What |
|------|-------------|------|
| `services/cart_service.py:24,27` | catalog | `ProductNotFoundException`, `Product` |
**Rationale:** Cart items are products. Can't add to cart without the Product model.
---
### Part A Subtotal: 4 one-line edits → 27 warnings resolved
*(Note: 3 remaining "declare dependency" warnings are covered by marketplace→analytics which is categorized under Part B as provider pattern instead.)*
---
## Part B: Provider Pattern (10 warnings — moderate refactoring)
These are **optional enrichment** where the source module works without the target. Need actual refactoring to conditionally load/call.
### B1. catalog → marketplace (3 warnings)
| File | What |
|------|------|
| `schemas/product.py:14` | `MarketplaceProductResponse` |
| `schemas/catalog.py:14` | `MarketplaceProductResponse` |
| `services/product_service.py:21` | `MarketplaceProduct` model |
**Why optional:** Products exist independently. Marketplace sync status is display enrichment.
**Fix approach:** Make marketplace fields `Optional` in schemas, populate via provider if marketplace is enabled.
---
### B2. marketplace → analytics (2 warnings)
| File | What |
|------|------|
| `routes/api/admin_marketplace.py:17` | `stats_service` |
| `routes/api/admin_marketplace.py:29` | `ImportStatsResponse` |
**Why optional:** Marketplace import/sync works without analytics. Stats on admin page are dashboard decoration.
**Fix approach:** Conditionally call stats aggregator, return empty stats if analytics disabled.
---
### B3. orders → marketplace (1 warning)
| File | What |
|------|------|
| `services/order_service.py:50` | `MarketplaceProduct`, `MarketplaceProductTranslation` |
**Why optional:** Orders work without marketplace. Enriches order display with Letzshop product info.
**Fix approach:** Conditionally join marketplace data when rendering, skip if module disabled.
---
### B4. inventory → orders (2 warnings)
| File | What |
|------|------|
| `services/inventory_transaction_service.py:15,18` | `OrderNotFoundException`, `Order` |
**Why optional:** Inventory tracks stock independently. Order reference on transactions is an audit back-reference, not functional.
**Fix approach:** Store `order_id` as nullable FK, resolve order details via provider for display.
---
### B5. inventory → marketplace (1 warning)
| File | What |
|------|------|
| `services/inventory_service.py:606` | marketplace import |
**Why optional:** Optional sync enrichment.
**Fix approach:** Conditional import or provider call.
---
### B6. analytics → catalog, orders, inventory, marketplace (4 warnings)
| File | What |
|------|------|
| `services/stats_service.py:23` | `Inventory` model |
| `services/stats_service.py:24` | `MarketplaceImportJob`, `MarketplaceProduct` models |
| `services/stats_service.py:25` | `Order` model |
| `services/stats_service.py:26` | `Product` model |
**Why optional:** Analytics aggregates everything — should report on whatever modules are enabled, not crash if one is disabled. Every module already exposes a `metrics_provider`.
**Fix approach:** Refactor `stats_service` to use module `metrics_provider` pattern instead of direct model imports. Cleanest candidate for provider pattern.
---
### Part B Subtotal: 6 refactors → 13 warnings resolved
---
## Resulting Dependency Tree
After all fixes, the clean module dependency graph:
```
catalog (foundational — products)
├── inventory (requires: catalog)
├── cart (requires: catalog, inventory)
├── orders (requires: catalog, inventory, payments)
├── marketplace (requires: catalog, orders, inventory)
└── analytics (no hard deps — all via providers)
```
---
## Execution Log
### Part A — Completed 2026-02-09
- [x] **A1** — marketplace: declare `catalog`, `orders`
- [x] **A2** — orders: declare `catalog`, `inventory`
- [x] **A3** — inventory: declare `catalog`
- [x] **A4** — cart: declare `catalog`
**Result:** 40 warnings → 13 warnings (27 resolved)
### Part B — Deferred (provider pattern refactors)
Remaining 13 warnings require provider pattern refactoring. To be tackled in a future session.
- [ ] **B6** — analytics: provider pattern (cleanest, biggest impact — 4 warnings)
- [ ] **B1** — catalog: provider pattern for marketplace enrichment (3 warnings)
- [ ] **B2** — marketplace: provider pattern for analytics stats (2 warnings)
- [ ] **B4** — inventory: provider pattern for order back-references (2 warnings)
- [ ] **B3** — orders: provider pattern for marketplace enrichment (1 warning)
- [ ] **B5** — inventory: provider pattern for marketplace sync (1 warning)
---
## Validation Target
Current state:
```
$ python scripts/validate_architecture.py
→ 0 errors, 13 warnings (all IMPORT-002 — provider pattern candidates)
```
After Part B complete:
```
$ python scripts/validate_architecture.py
→ 0 errors, 0 warnings
```