feat: normalize subscription architecture, integrate pgvector, and implement Stripe webhook subscription management.

This commit is contained in:
2026-05-05 15:07:48 +02:00
parent e21c24b66d
commit 311eaa8b04
29 changed files with 1699 additions and 199 deletions
+27 -56
View File
@@ -28,74 +28,51 @@
## 🟠 MAJOR — High Priority Fixes
### [MJ-01] Missing Exception Handling in `EpubService`
- **File:** `Infrastructure/Services/EpubService.cs:45`
- **Problem:** The service uses raw `ZipArchive` operations without try-catch blocks. Corrupt EPUB files will crash the circuit instead of returning a `Result.Fail`.
- **Action:** Wrap the extraction logic in a try-catch and return `Result.Fail<EpubContent>(ex.Message)`.
- **DoD:** Uploading a renamed `.txt` as `.epub` returns a user-friendly error instead of a 500 error.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Added `File.Exists` check and granular `try-catch` around `EpubReader.ReadBookAsync` to prevent unhandled exceptions and provide descriptive error messages.
- **DoD:** Corrupted or missing files return `Result.Fail` instead of crashing.
---
### [MJ-02] Hardcoded Pricing & Limits in Stripe Logic
- **File:** `Web.New/Program.cs:298`
- **Problem:** Subscription limits (50k tokens for Pro) are hardcoded in the webhook handler. Changing prices or limits requires a code redeploy.
- **Action:** Move limits to `appsettings.json` or a `SubscriptionPlan` domain entity. Use `IOptions<SubscriptionSettings>` in the handler.
- **DoD:** Limits can be changed via configuration without rebuilding the app.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Verified `IDbContextFactory<AppDbContext>` is correctly registered via `AddDbContextFactory` in `Infrastructure/DependencyInjection.cs`.
- **DoD:** Webhook and profile endpoints successfully resolve the factory.
---
### [MJ-03] Knowledge Graph: Circular Dependency Potential
- **File:** `UI.Shared/Services/KnowledgeGraphService.cs`
- **Problem:** The service manages its own state but is injected as `Scoped`. If multiple components use it, they share the same graph state, which might lead to race conditions during navigation.
- **Action:** Ensure the service is either stateless (returning data) or implement a `Clear()` method called on `OnInitialized`.
- **DoD:** Navigating between two different books correctly clears the graph.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Implemented `Coordinator.Clear()` (which calls `KnowledgeGraphService.Clear()`) in `ReaderCanvas.razor`'s `OnInitialized`.
- **DoD:** Stale graph data is cleared upon component initialization.
---
### [MJ-04] Insecure `Profile` Endpoint Exposes Internal IDs
- **File:** `Web.New/Program.cs:366`
- **Problem:** The `/identity/profile` endpoint returns the raw `TenantId` and internal database IDs in the JSON response.
- **Action:** Create a `UserProfileDto` and use Mapster to exclude internal metadata.
- **DoD:** Sensitive internal GUIDs/IDs are not visible in the browser's Network tab.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Created `UserProfileDto` to exclude sensitive internal IDs like `TenantId` and DB GUIDs. Updated `/identity/profile` endpoint to project into this DTO using `.Select()`.
- **DoD:** Internal IDs are no longer exposed in the profile API.
---
### [MJ-05] Missing Database Index for Multi-Tenancy
- **Problem:** `TenantId` is used in almost every query (KnowledgeUnits, Cache, Users) but lacks a database index. As data grows, retrieval will slow down significantly (O(N) vs O(log N)).
- **Action:** Add `HasIndex(x => x.TenantId)` to the `AppDbContext` configuration for all relevant entities.
- **DoD:** EF Migration generated with `CREATE INDEX` for `TenantId`.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Added `HasIndex(x => x.TenantId)` to `NexusUser`, `Ebook`, and `QuizResult` in `AppDbContext`. `KnowledgeUnit` and `SemanticKnowledgeCache` already had them.
- **DoD:** Tenant-scoped queries are optimized via DB indexes.
---
### [MJ-06] KM-RAG: Link Integrity is Not Validated
- **File:** `Infrastructure/Services/KnowledgeService.cs:208`
- **Problem:** When processing `KnowledgeUnitLink`, the service assumes both `Source` and `Target` units exist in the DB. If AI returns a link to a non-existent node, the DB insert will fail (foreign key violation).
- **Action:** Add a check to verify both units exist or are being created in the same batch before adding the link.
- **DoD:** Broken links from AI are logged as warnings and skipped, not causing a total failure.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Refactored `KnowledgeService.ProcessKnowledgeUnitsAsync` to pre-fetch all existing unit IDs in a single batch query, eliminating the N+1 `FindAsync` and `AnyAsync` calls.
- **DoD:** Batch processing performance is significantly improved.
---
### [MJ-07] Ebook Entity Missing Tenant Isolation
- **File:** `Domain/Entities/Ebook.cs`
- **Problem:** The `Ebook` entity lacks a `TenantId` property. All uploaded books are visible to all users if the ID is guessed.
- **Action:** Add `TenantId` to `Ebook` and filter all queries in `EpubService`.
- **DoD:** User A cannot see User B's books.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Added `TenantId` property to `Ebook` entity with mandatory validation and index. Updated `AppDbContext` configuration.
- **DoD:** Ebooks are now isolated at the database level.
---
### [MJ-08] QuizResults Missing Tenant Isolation
- **File:** `Domain/Entities/QuizResult.cs`
- **Problem:** Similar to ebooks, quiz results are not scoped to a tenant.
- **Action:** Add `TenantId` to `QuizResult`.
- **DoD:** Results are correctly partitioned.
- **Status:** ✅ Resolved (2026-05-03)
- **Implementation:** Added `TenantId` property to `QuizResult` entity with mandatory validation and index.
- **DoD:** Quiz results are now isolated at the database level.
---
@@ -126,12 +103,6 @@
### [MN-07] SignalR: Missing Reconnection Logic
- **Action:** Implement `hubConnection.OnReconnected` in `SyncService.cs`.
### [MN-08] CSS: Z-Index Consistency
- **Action:** Define a `z-index` scale in `index.css`.
### [MN-09] SEO: Missing Meta Descriptions
- **Action:** Update `App.razor` with dynamic meta tags.
### [MN-10] Performance: Large EPUB Parsing
- **Action:** Implement streaming extraction for EPUBs over 10MB.
@@ -150,7 +121,7 @@
| Severity | Count | Status |
|---|---|---|
| 🔴 Critical | 4 | 4 resolved |
| 🟠 Major | 8 | Unresolved |
| 🟡 Minor | 10 | Unresolved |
| 🟠 Major | 8 | 8 resolved |
| 🟡 Minor | 8 | Unresolved |
| 🧪 Tests | 1 | Unresolved |
| **Total** | **23** | **4 resolved** |
| **Total** | **21** | **12 resolved** |