fix demo session 2

This commit is contained in:
Urtzi Alfaro
2026-01-02 12:18:46 +01:00
parent cf0176673c
commit 0a1951051f
14 changed files with 497 additions and 810 deletions

View File

@@ -0,0 +1,55 @@
"""
Internal API for Inventory Service
Handles internal service-to-service operations
"""
from fastapi import APIRouter, Depends, HTTPException, Header
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from uuid import UUID
import structlog
from app.core.database import get_db
from app.core.config import settings
from app.models import Ingredient
logger = structlog.get_logger()
router = APIRouter(prefix="/internal", tags=["internal"])
async def verify_internal_api_key(x_internal_api_key: str = Header(None)):
"""Verify internal API key for service-to-service communication"""
required_key = settings.INTERNAL_API_KEY
if x_internal_api_key != required_key:
logger.warning("Unauthorized internal API access attempted")
raise HTTPException(status_code=403, detail="Invalid internal API key")
return True
@router.get("/count")
async def get_ingredient_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of active ingredients for onboarding status check.
Internal endpoint for tenant service.
"""
try:
count = await db.scalar(
select(func.count()).select_from(Ingredient)
.where(
Ingredient.tenant_id == UUID(tenant_id),
Ingredient.is_active == True
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get ingredient count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get ingredient count: {str(e)}")

View File

@@ -610,35 +610,4 @@ async def delete_demo_tenant_data(
raise HTTPException(
status_code=500,
detail=f"Failed to delete demo data: {str(e)}"
)
@router.get("/count")
async def get_ingredient_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of active ingredients for onboarding status check.
Internal endpoint for tenant service.
"""
try:
from sqlalchemy import select, func
count = await db.scalar(
select(func.count()).select_from(Ingredient)
.where(
Ingredient.tenant_id == UUID(tenant_id),
Ingredient.is_active == True
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get ingredient count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get ingredient count: {str(e)}")
)

View File

@@ -33,7 +33,8 @@ from app.api import (
sustainability,
audit,
ml_insights,
enterprise_inventory
enterprise_inventory,
internal
)
from app.api.internal_alert_trigger import router as internal_alert_trigger_router
from app.api.internal_demo import router as internal_demo_router
@@ -215,6 +216,7 @@ service.add_router(dashboard.router)
service.add_router(analytics.router)
service.add_router(sustainability.router)
service.add_router(internal_demo.router, tags=["internal-demo"])
service.add_router(internal.router)
service.add_router(ml_insights.router) # ML insights endpoint
service.add_router(ml_insights.internal_router) # Internal ML insights endpoint for demo cloning
service.add_router(internal_alert_trigger_router) # Internal alert trigger for demo cloning

View File

@@ -231,7 +231,7 @@ async def clone_demo_data(
raise HTTPException(status_code=500, detail=f"Failed to clone orchestration runs: {str(e)}")
@router.delete("/internal/demo/tenant/{virtual_tenant_id}")
@router.delete("/tenant/{virtual_tenant_id}")
async def delete_demo_data(
virtual_tenant_id: str,
db: AsyncSession = Depends(get_db),
@@ -280,7 +280,7 @@ async def delete_demo_data(
raise HTTPException(status_code=500, detail=str(e))
@router.get("/internal/demo/clone/health")
@router.get("/clone/health")
async def health_check(_: bool = Depends(verify_internal_api_key)):
"""Health check for demo cloning endpoint"""
return {"status": "healthy", "service": "orchestrator"}

View File

@@ -0,0 +1,56 @@
"""
Internal API for Recipes Service
Handles internal service-to-service operations
"""
from fastapi import APIRouter, Depends, HTTPException, Header
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from uuid import UUID
import structlog
from app.core.database import get_db
from app.core.config import settings
from app.models.recipes import Recipe, RecipeStatus
logger = structlog.get_logger()
router = APIRouter(prefix="/internal", tags=["internal"])
async def verify_internal_api_key(x_internal_api_key: str = Header(None)):
"""Verify internal API key for service-to-service communication"""
required_key = settings.INTERNAL_API_KEY
if x_internal_api_key != required_key:
logger.warning("Unauthorized internal API access attempted")
raise HTTPException(status_code=403, detail="Invalid internal API key")
return True
@router.get("/count")
async def get_recipe_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of recipes for onboarding status check.
Counts DRAFT and ACTIVE recipes (excludes ARCHIVED/DISCONTINUED).
Internal endpoint for tenant service.
"""
try:
count = await db.scalar(
select(func.count()).select_from(Recipe)
.where(
Recipe.tenant_id == UUID(tenant_id),
Recipe.status.in_([RecipeStatus.DRAFT, RecipeStatus.ACTIVE, RecipeStatus.TESTING])
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get recipe count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get recipe count: {str(e)}")

View File

@@ -434,34 +434,3 @@ async def delete_demo_tenant_data(
)
@router.get("/count")
async def get_recipe_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of recipes for onboarding status check.
Counts DRAFT and ACTIVE recipes (excludes ARCHIVED/DISCONTINUED).
Internal endpoint for tenant service.
"""
try:
from sqlalchemy import select, func
from app.models.recipes import RecipeStatus
count = await db.scalar(
select(func.count()).select_from(Recipe)
.where(
Recipe.tenant_id == UUID(tenant_id),
Recipe.status.in_([RecipeStatus.DRAFT, RecipeStatus.ACTIVE, RecipeStatus.TESTING])
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get recipe count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get recipe count: {str(e)}")

View File

@@ -14,7 +14,7 @@ from .core.database import db_manager
from shared.service_base import StandardFastAPIService
# Import API routers
from .api import recipes, recipe_quality_configs, recipe_operations, audit, internal_demo
from .api import recipes, recipe_quality_configs, recipe_operations, audit, internal_demo, internal
# Import models to register them with SQLAlchemy metadata
from .models import recipes as recipe_models
@@ -122,6 +122,7 @@ service.add_router(recipes.router)
service.add_router(recipe_quality_configs.router)
service.add_router(recipe_operations.router)
service.add_router(internal_demo.router, tags=["internal-demo"])
service.add_router(internal.router)
if __name__ == "__main__":

View File

@@ -0,0 +1,55 @@
"""
Internal API for Suppliers Service
Handles internal service-to-service operations
"""
from fastapi import APIRouter, Depends, HTTPException, Header
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from uuid import UUID
import structlog
from app.core.database import get_db
from app.core.config import settings
from app.models.suppliers import Supplier, SupplierStatus
logger = structlog.get_logger()
router = APIRouter(prefix="/internal", tags=["internal"])
async def verify_internal_api_key(x_internal_api_key: str = Header(None)):
"""Verify internal API key for service-to-service communication"""
required_key = settings.INTERNAL_API_KEY
if x_internal_api_key != required_key:
logger.warning("Unauthorized internal API access attempted")
raise HTTPException(status_code=403, detail="Invalid internal API key")
return True
@router.get("/count")
async def get_supplier_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of active suppliers for onboarding status check.
Internal endpoint for tenant service.
"""
try:
count = await db.scalar(
select(func.count()).select_from(Supplier)
.where(
Supplier.tenant_id == UUID(tenant_id),
Supplier.status == SupplierStatus.active
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get supplier count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get supplier count: {str(e)}")

View File

@@ -409,33 +409,3 @@ async def delete_demo_tenant_data(
)
@router.get("/count")
async def get_supplier_count(
tenant_id: str,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
"""
Get count of active suppliers for onboarding status check.
Internal endpoint for tenant service.
"""
try:
from sqlalchemy import select, func
from app.models.suppliers import SupplierStatus
count = await db.scalar(
select(func.count()).select_from(Supplier)
.where(
Supplier.tenant_id == UUID(tenant_id),
Supplier.status == SupplierStatus.active
)
)
return {
"count": count or 0,
"tenant_id": tenant_id
}
except Exception as e:
logger.error("Failed to get supplier count", tenant_id=tenant_id, error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to get supplier count: {str(e)}")

View File

@@ -11,7 +11,7 @@ from app.core.database import database_manager
from shared.service_base import StandardFastAPIService
# Import API routers
from app.api import suppliers, supplier_operations, analytics, audit, internal_demo
from app.api import suppliers, supplier_operations, analytics, audit, internal_demo, internal
# REMOVED: purchase_orders, deliveries - PO and delivery management moved to Procurement Service
# from app.api import purchase_orders, deliveries
@@ -110,6 +110,7 @@ service.add_router(supplier_operations.router) # /suppliers/operations/...
service.add_router(analytics.router) # /suppliers/analytics/...
service.add_router(suppliers.router) # /suppliers/{supplier_id} - catch-all, must be last
service.add_router(internal_demo.router, tags=["internal-demo"])
service.add_router(internal.router)
if __name__ == "__main__":