Improve AI logic

This commit is contained in:
Urtzi Alfaro
2025-11-05 13:34:56 +01:00
parent 5c87fbcf48
commit 394ad3aea4
218 changed files with 30627 additions and 7658 deletions

View File

@@ -0,0 +1,273 @@
# Tenant Deletion System - Quick Reference
## Quick Start
### Test a Service Deletion
```bash
# Step 1: Preview what will be deleted (dry-run)
curl -X GET "http://localhost:8000/api/v1/pos/tenant/YOUR_TENANT_ID/deletion-preview" \
-H "Authorization: Bearer YOUR_SERVICE_TOKEN"
# Step 2: Execute deletion
curl -X DELETE "http://localhost:8000/api/v1/pos/tenant/YOUR_TENANT_ID" \
-H "Authorization: Bearer YOUR_SERVICE_TOKEN"
```
### Delete a Tenant
```bash
# Requires admin token and verifies no other admins exist
curl -X DELETE "http://localhost:8000/api/v1/tenants/YOUR_TENANT_ID" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
```
### Use the Orchestrator (Python)
```python
from services.auth.app.services.deletion_orchestrator import DeletionOrchestrator
# Initialize
orchestrator = DeletionOrchestrator(auth_token="service_jwt")
# Execute parallel deletion across all services
job = await orchestrator.orchestrate_tenant_deletion(
tenant_id="abc-123",
tenant_name="Bakery XYZ",
initiated_by="admin-user-456"
)
# Check results
print(f"Status: {job.status}")
print(f"Deleted: {job.total_items_deleted} items")
print(f"Services completed: {job.services_completed}/12")
```
## Service Endpoints
All services follow the same pattern:
| Endpoint | Method | Auth | Purpose |
|----------|--------|------|---------|
| `/tenant/{tenant_id}/deletion-preview` | GET | Service | Preview counts (dry-run) |
| `/tenant/{tenant_id}` | DELETE | Service | Permanent deletion |
### Full URLs by Service
```bash
# Core Business Services
http://orders-service:8000/api/v1/orders/tenant/{tenant_id}
http://inventory-service:8000/api/v1/inventory/tenant/{tenant_id}
http://recipes-service:8000/api/v1/recipes/tenant/{tenant_id}
http://sales-service:8000/api/v1/sales/tenant/{tenant_id}
http://production-service:8000/api/v1/production/tenant/{tenant_id}
http://suppliers-service:8000/api/v1/suppliers/tenant/{tenant_id}
# Integration Services
http://pos-service:8000/api/v1/pos/tenant/{tenant_id}
http://external-service:8000/api/v1/external/tenant/{tenant_id}
# AI/ML Services
http://forecasting-service:8000/api/v1/forecasting/tenant/{tenant_id}
http://training-service:8000/api/v1/training/tenant/{tenant_id}
# Alert/Notification Services
http://alert-processor-service:8000/api/v1/alerts/tenant/{tenant_id}
http://notification-service:8000/api/v1/notifications/tenant/{tenant_id}
```
## Implementation Pattern
### Creating a New Deletion Service
```python
# 1. Create tenant_deletion_service.py
from shared.services.tenant_deletion import (
BaseTenantDataDeletionService,
TenantDataDeletionResult
)
class MyServiceTenantDeletionService(BaseTenantDataDeletionService):
def __init__(self, db: AsyncSession):
super().__init__("my-service")
self.db = db
async def get_tenant_data_preview(self, tenant_id: str) -> Dict[str, int]:
# Return counts without deleting
count = await self.db.scalar(
select(func.count(MyModel.id)).where(MyModel.tenant_id == tenant_id)
)
return {"my_table": count or 0}
async def delete_tenant_data(self, tenant_id: str) -> TenantDataDeletionResult:
result = TenantDataDeletionResult(tenant_id, self.service_name)
try:
# Delete children before parents
delete_stmt = delete(MyModel).where(MyModel.tenant_id == tenant_id)
result_proxy = await self.db.execute(delete_stmt)
result.add_deleted_items("my_table", result_proxy.rowcount)
await self.db.commit()
except Exception as e:
await self.db.rollback()
result.add_error(f"Deletion failed: {str(e)}")
return result
```
### Adding API Endpoints
```python
# 2. Add to your API router
@router.delete("/tenant/{tenant_id}")
@service_only_access
async def delete_tenant_data(
tenant_id: str = Path(...),
current_user: dict = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
deletion_service = MyServiceTenantDeletionService(db)
result = await deletion_service.safe_delete_tenant_data(tenant_id)
if not result.success:
raise HTTPException(500, detail=f"Deletion failed: {result.errors}")
return {"message": "Success", "summary": result.to_dict()}
@router.get("/tenant/{tenant_id}/deletion-preview")
async def preview_tenant_deletion(
tenant_id: str = Path(...),
current_user: dict = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
deletion_service = MyServiceTenantDeletionService(db)
preview = await deletion_service.get_tenant_data_preview(tenant_id)
return {
"tenant_id": tenant_id,
"service": "my-service",
"data_counts": preview,
"total_items": sum(preview.values())
}
```
### Deletion Order (Foreign Keys)
```python
# Always delete in this order:
# 1. Child records (with foreign keys)
# 2. Parent records (referenced by children)
# 3. Independent records (no foreign keys)
# 4. Audit logs (last)
# Example:
await self.db.execute(delete(OrderItem).where(...)) # Child
await self.db.execute(delete(Order).where(...)) # Parent
await self.db.execute(delete(Customer).where(...)) # Parent
await self.db.execute(delete(AuditLog).where(...)) # Independent
```
## Troubleshooting
### Foreign Key Constraint Error
**Problem**: Error when deleting parent before child records
**Solution**: Check deletion order - delete children before parents
**Fix**: Review the delete() statements in delete_tenant_data()
### Service Returns 401 Unauthorized
**Problem**: Endpoint rejects valid token
**Solution**: Endpoint requires service token, not user token
**Fix**: Use @service_only_access decorator and service JWT
### Deletion Count is Zero
**Problem**: No records deleted even though they exist
**Solution**: tenant_id column might be UUID vs string mismatch
**Fix**: Use UUID(tenant_id) in WHERE clause
```python
.where(Model.tenant_id == UUID(tenant_id))
```
### Orchestrator Can't Reach Service
**Problem**: Service not responding to deletion request
**Solution**: Check service URL in SERVICE_DELETION_ENDPOINTS
**Fix**: Ensure service name matches Kubernetes service name
Example: "orders-service" not "orders"
## Key Files
### Base Infrastructure
```
services/shared/services/tenant_deletion.py # Base classes
services/auth/app/services/deletion_orchestrator.py # Orchestrator
```
### Service Implementations (12 Services)
```
services/orders/app/services/tenant_deletion_service.py
services/inventory/app/services/tenant_deletion_service.py
services/recipes/app/services/tenant_deletion_service.py
services/sales/app/services/tenant_deletion_service.py
services/production/app/services/tenant_deletion_service.py
services/suppliers/app/services/tenant_deletion_service.py
services/pos/app/services/tenant_deletion_service.py
services/external/app/services/tenant_deletion_service.py
services/forecasting/app/services/tenant_deletion_service.py
services/training/app/services/tenant_deletion_service.py
services/alert_processor/app/services/tenant_deletion_service.py
services/notification/app/services/tenant_deletion_service.py
```
## Data Deletion Summary
| Service | Main Tables | Typical Count |
|---------|-------------|---------------|
| Orders | Customers, Orders, Items | 1,000-10,000 |
| Inventory | Products, Stock Movements | 500-2,000 |
| Recipes | Recipes, Ingredients, Steps | 100-500 |
| Sales | Sales Records, Predictions | 5,000-50,000 |
| Production | Production Runs, Steps | 500-5,000 |
| Suppliers | Suppliers, Orders, Contracts | 100-1,000 |
| POS | Transactions, Items, Logs | 10,000-100,000 |
| External | Tenant Weather Data | 100-1,000 |
| Forecasting | Forecasts, Batches, Cache | 5,000-50,000 |
| Training | Models, Artifacts, Logs | 1,000-10,000 |
| Alert Processor | Alerts, Interactions | 1,000-10,000 |
| Notification | Notifications, Preferences | 5,000-50,000 |
**Total Typical Deletion**: 25,000-250,000 records per tenant
## Important Reminders
### Security
- ✅ All deletion endpoints require `@service_only_access`
- ✅ Tenant endpoint checks for admin permissions
- ✅ User deletion verifies ownership before tenant deletion
### Data Integrity
- ✅ Always use database transactions
- ✅ Delete children before parents (foreign keys)
- ✅ Track deletion counts for audit
- ✅ Log every step with structlog
### Testing
- ✅ Always test preview endpoint first (dry-run)
- ✅ Test with small tenant before large ones
- ✅ Verify counts match expected values
- ✅ Check logs for errors
## Success Criteria
### Service is Complete When:
- [x] `tenant_deletion_service.py` created
- [x] Extends `BaseTenantDataDeletionService`
- [x] DELETE endpoint added to API
- [x] GET preview endpoint added
- [x] Service registered in orchestrator
- [x] Tested with real tenant data
- [x] Logs show successful deletion
---
For detailed information, see [deletion-system.md](deletion-system.md)
**Last Updated**: 2025-11-04