Improve the frontend 4

This commit is contained in:
Urtzi Alfaro
2025-11-01 21:35:03 +01:00
parent f44d235c6d
commit 0220da1725
59 changed files with 5785 additions and 1870 deletions

View File

@@ -0,0 +1,378 @@
# Tenant Deletion Implementation Guide
## Overview
This guide documents the standardized approach for implementing tenant data deletion across all microservices in the Bakery-IA platform.
## Architecture
### Phase 1: Tenant Service Core (✅ COMPLETED)
The tenant service now provides three critical endpoints:
1. **DELETE `/api/v1/tenants/{tenant_id}`** - Delete a tenant and all associated data
- Verifies caller permissions (owner/admin or internal service)
- Checks for other admins before allowing deletion
- Cascades deletion to local tenant data (members, subscriptions)
- Publishes `tenant.deleted` event for other services
2. **DELETE `/api/v1/tenants/user/{user_id}/memberships`** - Delete all memberships for a user
- Only accessible by internal services
- Removes user from all tenant memberships
- Used during user account deletion
3. **POST `/api/v1/tenants/{tenant_id}/transfer-ownership`** - Transfer tenant ownership
- Atomic operation to change owner and update member roles
- Requires current owner permission or internal service call
4. **GET `/api/v1/tenants/{tenant_id}/admins`** - Get all tenant admins
- Returns list of users with owner/admin roles
- Used by auth service to check before tenant deletion
### Phase 2: Service-Level Deletion (IN PROGRESS)
Each microservice must implement tenant data deletion using the standardized pattern.
## Implementation Pattern
### Step 1: Create Deletion Service
Each service should create a `tenant_deletion_service.py` that implements `BaseTenantDataDeletionService`:
```python
# services/{service}/app/services/tenant_deletion_service.py
from typing import Dict
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete, func
import structlog
from shared.services.tenant_deletion import (
BaseTenantDataDeletionService,
TenantDataDeletionResult
)
class {Service}TenantDeletionService(BaseTenantDataDeletionService):
"""Service for deleting all {service}-related data for a tenant"""
def __init__(self, db_session: AsyncSession):
super().__init__("{service}-service")
self.db = db_session
async def get_tenant_data_preview(self, tenant_id: str) -> Dict[str, int]:
"""Get counts of what would be deleted"""
preview = {}
# Count each entity type
# Example:
# count = await self.db.scalar(
# select(func.count(Model.id)).where(Model.tenant_id == tenant_id)
# )
# preview["model_name"] = count or 0
return preview
async def delete_tenant_data(self, tenant_id: str) -> TenantDataDeletionResult:
"""Delete all data for a tenant"""
result = TenantDataDeletionResult(tenant_id, self.service_name)
try:
# Delete each entity type
# 1. Delete child records first (respect foreign keys)
# 2. Then delete parent records
# 3. Use try-except for each delete operation
# Example:
# try:
# delete_stmt = delete(Model).where(Model.tenant_id == tenant_id)
# result_proxy = await self.db.execute(delete_stmt)
# result.add_deleted_items("model_name", result_proxy.rowcount)
# except Exception as e:
# result.add_error(f"Model deletion: {str(e)}")
await self.db.commit()
except Exception as e:
await self.db.rollback()
result.add_error(f"Fatal error: {str(e)}")
return result
```
### Step 2: Add API Endpoints
Add two endpoints to the service's API router:
```python
# services/{service}/app/api/{main_router}.py
@router.delete("/tenant/{tenant_id}")
async def delete_tenant_data(
tenant_id: str,
current_user: dict = Depends(get_current_user_dep),
db = Depends(get_db)
):
"""Delete all {service} data for a tenant (internal only)"""
# Only allow internal service calls
if current_user.get("type") != "service":
raise HTTPException(status_code=403, detail="Internal services only")
from app.services.tenant_deletion_service import {Service}TenantDeletionService
deletion_service = {Service}TenantDeletionService(db)
result = await deletion_service.safe_delete_tenant_data(tenant_id)
return {
"message": "Tenant data deletion completed",
"summary": result.to_dict()
}
@router.get("/tenant/{tenant_id}/deletion-preview")
async def preview_tenant_deletion(
tenant_id: str,
current_user: dict = Depends(get_current_user_dep),
db = Depends(get_db)
):
"""Preview what would be deleted (dry-run)"""
# Allow internal services and admins
if not (current_user.get("type") == "service" or
current_user.get("role") in ["owner", "admin"]):
raise HTTPException(status_code=403, detail="Insufficient permissions")
from app.services.tenant_deletion_service import {Service}TenantDeletionService
deletion_service = {Service}TenantDeletionService(db)
preview = await deletion_service.get_tenant_data_preview(tenant_id)
return {
"tenant_id": tenant_id,
"service": "{service}-service",
"data_counts": preview,
"total_items": sum(preview.values())
}
```
## Services Requiring Implementation
### ✅ Completed:
1. **Tenant Service** - Core deletion logic, memberships, ownership transfer
2. **Orders Service** - Example implementation complete
### 🔄 In Progress:
3. **Inventory Service** - Template created, needs testing
### ⏳ Pending:
4. **Recipes Service**
- Models to delete: Recipe, RecipeIngredient, RecipeStep, RecipeNutrition
5. **Production Service**
- Models to delete: ProductionBatch, ProductionSchedule, ProductionPlan
6. **Sales Service**
- Models to delete: Sale, SaleItem, DailySales, SalesReport
7. **Suppliers Service**
- Models to delete: Supplier, SupplierProduct, PurchaseOrder, PurchaseOrderItem
8. **POS Service**
- Models to delete: POSConfiguration, POSTransaction, POSSession
9. **External Service**
- Models to delete: ExternalDataCache, APIKeyUsage
10. **Forecasting Service** (Already has some deletion logic)
- Models to delete: Forecast, PredictionBatch, ModelArtifact
11. **Training Service** (Already has some deletion logic)
- Models to delete: TrainingJob, TrainedModel, ModelMetrics
12. **Notification Service** (Already has some deletion logic)
- Models to delete: Notification, NotificationPreference, NotificationLog
13. **Alert Processor Service**
- Models to delete: Alert, AlertRule, AlertHistory
14. **Demo Session Service**
- May not need tenant deletion (demo data is transient)
## Phase 3: Orchestration & Saga Pattern (PENDING)
### Goal
Create a centralized deletion orchestrator in the auth service that:
1. Coordinates deletion across all services
2. Implements saga pattern for distributed transactions
3. Provides rollback/compensation logic for failures
4. Tracks deletion job status
### Components Needed
#### 1. Deletion Orchestrator Service
```python
# services/auth/app/services/deletion_orchestrator.py
class DeletionOrchestrator:
"""Coordinates tenant deletion across all services"""
def __init__(self):
self.service_registry = {
"orders": OrdersServiceClient(),
"inventory": InventoryServiceClient(),
"recipes": RecipesServiceClient(),
# ... etc
}
async def orchestrate_tenant_deletion(
self,
tenant_id: str,
deletion_job_id: str
) -> DeletionResult:
"""
Execute deletion saga across all services
Returns comprehensive result with per-service status
"""
pass
```
#### 2. Deletion Job Status Tracking
```sql
CREATE TABLE deletion_jobs (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
initiated_by UUID NOT NULL,
status VARCHAR(50), -- pending, in_progress, completed, failed, rolled_back
services_completed JSONB,
services_failed JSONB,
total_items_deleted INTEGER,
error_log TEXT,
created_at TIMESTAMP,
completed_at TIMESTAMP
);
```
#### 3. Service Registry
Track all services that need to be called for deletion:
```python
SERVICE_DELETION_ENDPOINTS = {
"orders": "http://orders-service:8000/api/v1/orders/tenant/{tenant_id}",
"inventory": "http://inventory-service:8000/api/v1/inventory/tenant/{tenant_id}",
"recipes": "http://recipes-service:8000/api/v1/recipes/tenant/{tenant_id}",
"production": "http://production-service:8000/api/v1/production/tenant/{tenant_id}",
"sales": "http://sales-service:8000/api/v1/sales/tenant/{tenant_id}",
"suppliers": "http://suppliers-service:8000/api/v1/suppliers/tenant/{tenant_id}",
"pos": "http://pos-service:8000/api/v1/pos/tenant/{tenant_id}",
"external": "http://external-service:8000/api/v1/external/tenant/{tenant_id}",
"forecasting": "http://forecasting-service:8000/api/v1/forecasts/tenant/{tenant_id}",
"training": "http://training-service:8000/api/v1/models/tenant/{tenant_id}",
"notification": "http://notification-service:8000/api/v1/notifications/tenant/{tenant_id}",
}
```
## Phase 4: Enhanced Features (PENDING)
### 1. Soft Delete with Retention Period
- Add `deleted_at` timestamp to tenants table
- Implement 30-day retention before permanent deletion
- Allow restoration during retention period
### 2. Audit Logging
- Log all deletion operations with details
- Track who initiated deletion and when
- Store deletion summaries for compliance
### 3. Deletion Preview for All Services
- Aggregate preview from all services
- Show comprehensive impact analysis
- Allow download of deletion report
### 4. Async Job Status Check
- Add endpoint to check deletion job progress
- WebSocket support for real-time updates
- Email notification on completion
## Testing Strategy
### Unit Tests
- Test each service's deletion service independently
- Mock database operations
- Verify correct SQL generation
### Integration Tests
- Test deletion across multiple services
- Verify CASCADE deletes work correctly
- Test rollback scenarios
### End-to-End Tests
- Full tenant deletion from API call to completion
- Verify all data is actually deleted
- Test with production-like data volumes
## Rollout Plan
1. **Week 1**: Complete Phase 2 for critical services (Orders, Inventory, Recipes, Production)
2. **Week 2**: Complete Phase 2 for remaining services
3. **Week 3**: Implement Phase 3 (Orchestration & Saga)
4. **Week 4**: Implement Phase 4 (Enhanced Features)
5. **Week 5**: Testing & Documentation
6. **Week 6**: Production deployment with monitoring
## Monitoring & Alerts
### Metrics to Track
- `tenant_deletion_duration_seconds` - How long deletions take
- `tenant_deletion_items_deleted` - Number of items deleted per service
- `tenant_deletion_errors_total` - Count of deletion failures
- `tenant_deletion_jobs_status` - Current status of deletion jobs
### Alerts
- Alert if deletion takes longer than 5 minutes
- Alert if any service fails to delete data
- Alert if CASCADE deletes don't work as expected
## Security Considerations
1. **Authorization**: Only owners, admins, or internal services can delete
2. **Audit Trail**: All deletions must be logged
3. **No Direct DB Access**: All deletions through API endpoints
4. **Rate Limiting**: Prevent abuse of deletion endpoints
5. **Confirmation Required**: User must confirm before deletion
6. **GDPR Compliance**: Support right to be forgotten
## Current Status Summary
| Phase | Status | Completion |
|-------|--------|------------|
| Phase 1: Tenant Service Core | ✅ Complete | 100% |
| Phase 2: Service Deletions | 🔄 In Progress | 20% (2/10 services) |
| Phase 3: Orchestration | ⏳ Pending | 0% |
| Phase 4: Enhanced Features | ⏳ Pending | 0% |
## Next Steps
1. **Immediate**: Complete Phase 2 for remaining 8 services using the template above
2. **Short-term**: Implement orchestration layer in auth service
3. **Mid-term**: Add saga pattern and rollback logic
4. **Long-term**: Implement soft delete and enhanced features
## Files Created/Modified
### New Files:
- `/services/shared/services/tenant_deletion.py` - Base classes and utilities
- `/services/orders/app/services/tenant_deletion_service.py` - Orders implementation
- `/services/inventory/app/services/tenant_deletion_service.py` - Inventory template
- `/TENANT_DELETION_IMPLEMENTATION_GUIDE.md` - This document
### Modified Files:
- `/services/tenant/app/services/tenant_service.py` - Added deletion methods
- `/services/tenant/app/services/messaging.py` - Added deletion event
- `/services/tenant/app/api/tenants.py` - Added DELETE endpoint
- `/services/tenant/app/api/tenant_members.py` - Added membership deletion & transfer endpoints
- `/services/orders/app/api/orders.py` - Added tenant deletion endpoints
## References
- [Saga Pattern](https://microservices.io/patterns/data/saga.html)
- [GDPR Right to Erasure](https://gdpr-info.eu/art-17-gdpr/)
- [Distributed Transactions in Microservices](https://www.nginx.com/blog/microservices-pattern-distributed-transactions-saga/)