refactor(P11+P12): codebase hygiene — CLAUDE.md rewrite, type safety, dead code removal
- Rewrite CLAUDE.md to match current 8-service architecture (was 11, 5 deleted) - Remove all as-any casts in OrderDetail.tsx (9 casts → 0) - Add cad_parsed_objects/cad_part_materials to OrderItem interface - Rename require_admin → require_global_admin across 6 router files (22 calls) - Remove EXPORT_GLB_PRODUCTION enum + generate_gltf_production_task (dead code) - Remove worker-thumbnail from ALLOWED_SERVICES, replace Flamenco link - Delete obsolete PLAN.md (1455 lines) and PLAN_REFACTOR.md (1174 lines) - Fix digit-only USD prim names with p_ prefix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -303,34 +303,6 @@ async def generate_gltf_geometry(
|
||||
return {"status": "queued", "task_id": task.id, "cad_file_id": str(id)}
|
||||
|
||||
|
||||
@router.post("/{id}/generate-gltf-production", status_code=status.HTTP_202_ACCEPTED)
|
||||
async def generate_gltf_production(
|
||||
id: uuid.UUID,
|
||||
user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Queue production GLB export (Blender + PBR materials) from a geometry GLB.
|
||||
|
||||
Requires a gltf_geometry MediaAsset to already exist (run generate-gltf-geometry first).
|
||||
Stores result as a MediaAsset with asset_type='gltf_production'.
|
||||
"""
|
||||
if not is_privileged(user):
|
||||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||||
|
||||
cad = await _get_cad_file(id, db)
|
||||
if not cad.stored_path:
|
||||
raise HTTPException(status_code=404, detail="STEP file not uploaded for this CAD file")
|
||||
|
||||
logger.warning(
|
||||
"generate_gltf_production called for cad %s — "
|
||||
"deprecated: renders now consume usd_master directly",
|
||||
id,
|
||||
)
|
||||
from app.tasks.step_tasks import generate_gltf_production_task
|
||||
task = generate_gltf_production_task.delay(str(id))
|
||||
return {"status": "queued", "task_id": task.id, "cad_file_id": str(id)}
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{id}/regenerate-thumbnail",
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
|
||||
@@ -10,7 +10,7 @@ from app.domains.rendering.schemas import (
|
||||
GlobalRenderPositionPatch,
|
||||
GlobalRenderPositionOut,
|
||||
)
|
||||
from app.utils.auth import require_admin, get_current_user
|
||||
from app.utils.auth import require_global_admin, get_current_user
|
||||
|
||||
router = APIRouter(prefix="/render-positions/global", tags=["global-render-positions"])
|
||||
|
||||
@@ -31,7 +31,7 @@ async def list_global_render_positions(
|
||||
async def create_global_render_position(
|
||||
body: GlobalRenderPositionCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
_user=Depends(require_global_admin),
|
||||
):
|
||||
"""Create a new global render position (admin only)."""
|
||||
pos = GlobalRenderPosition(**body.model_dump())
|
||||
@@ -46,7 +46,7 @@ async def update_global_render_position(
|
||||
pos_id: uuid.UUID,
|
||||
body: GlobalRenderPositionPatch,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
_user=Depends(require_global_admin),
|
||||
):
|
||||
"""Update a global render position (admin only)."""
|
||||
result = await db.execute(select(GlobalRenderPosition).where(GlobalRenderPosition.id == pos_id))
|
||||
@@ -64,7 +64,7 @@ async def update_global_render_position(
|
||||
async def delete_global_render_position(
|
||||
pos_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
_user=Depends(require_global_admin),
|
||||
):
|
||||
"""Delete a global render position (admin only)."""
|
||||
result = await db.execute(select(GlobalRenderPosition).where(GlobalRenderPosition.id == pos_id))
|
||||
|
||||
@@ -6,7 +6,7 @@ from sqlalchemy import select
|
||||
from pydantic import BaseModel
|
||||
from app.database import get_db
|
||||
from app.models.template import Template
|
||||
from app.utils.auth import get_current_user, require_admin
|
||||
from app.utils.auth import get_current_user, require_global_admin
|
||||
from app.models.user import User
|
||||
|
||||
router = APIRouter(prefix="/templates", tags=["templates"])
|
||||
@@ -63,7 +63,7 @@ async def get_template(
|
||||
async def update_template(
|
||||
template_id: uuid.UUID,
|
||||
body: TemplateUpdate,
|
||||
user: User = Depends(require_admin),
|
||||
user: User = Depends(require_global_admin),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
result = await db.execute(select(Template).where(Template.id == template_id))
|
||||
|
||||
@@ -17,7 +17,7 @@ from app.models.product import Product
|
||||
from app.models.user import User
|
||||
from app.models.worker_config import WorkerConfig
|
||||
from app.models.system_setting import SystemSetting
|
||||
from app.utils.auth import get_current_user, require_admin_or_pm, require_admin
|
||||
from app.utils.auth import get_current_user, require_admin_or_pm, require_global_admin
|
||||
|
||||
router = APIRouter(prefix="/worker", tags=["worker"])
|
||||
|
||||
@@ -364,7 +364,7 @@ async def cancel_task(task_id: str, user: User = Depends(require_admin_or_pm)):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class ScaleRequest(BaseModel):
|
||||
service: str # "render-worker" | "worker" | "worker-thumbnail"
|
||||
service: str # "render-worker" | "worker"
|
||||
count: int # 0–20
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ async def scale_workers(
|
||||
body: ScaleRequest,
|
||||
user: User = Depends(require_admin_or_pm),
|
||||
):
|
||||
"""Scale a Compose service (render-worker, worker, worker-thumbnail) up or down.
|
||||
"""Scale a Compose service (render-worker, worker) up or down.
|
||||
|
||||
Requires the docker socket and compose file to be accessible inside the container
|
||||
(see docker-compose.yml COMPOSE_PROJECT_DIR env var).
|
||||
@@ -421,7 +421,7 @@ async def scale_workers(
|
||||
import subprocess
|
||||
from fastapi import HTTPException
|
||||
|
||||
ALLOWED_SERVICES = {"render-worker", "worker", "worker-thumbnail"}
|
||||
ALLOWED_SERVICES = {"render-worker", "worker"}
|
||||
if body.service not in ALLOWED_SERVICES:
|
||||
raise HTTPException(400, detail=f"service must be one of {ALLOWED_SERVICES}")
|
||||
if not (0 <= body.count <= 20):
|
||||
@@ -462,7 +462,7 @@ async def scale_workers(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@router.post("/probe/gpu", status_code=http_status.HTTP_202_ACCEPTED)
|
||||
async def trigger_gpu_probe(current_user: User = Depends(require_admin)):
|
||||
async def trigger_gpu_probe(current_user: User = Depends(require_global_admin)):
|
||||
"""Queue a GPU probe task on the render-worker."""
|
||||
from app.tasks.gpu_tasks import probe_gpu
|
||||
result = probe_gpu.delay()
|
||||
@@ -471,7 +471,7 @@ async def trigger_gpu_probe(current_user: User = Depends(require_admin)):
|
||||
|
||||
@router.get("/probe/gpu/result")
|
||||
async def get_gpu_probe_result(
|
||||
current_user: User = Depends(require_admin),
|
||||
current_user: User = Depends(require_global_admin),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Return the last GPU probe result from system_settings."""
|
||||
@@ -622,7 +622,7 @@ class WorkerConfigUpdate(BaseModel):
|
||||
|
||||
@router.get("/configs", response_model=list[WorkerConfigOut])
|
||||
async def list_worker_configs(
|
||||
user: User = Depends(require_admin),
|
||||
user: User = Depends(require_global_admin),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""List all worker concurrency configurations (admin only)."""
|
||||
@@ -644,7 +644,7 @@ async def list_worker_configs(
|
||||
async def update_worker_config(
|
||||
queue_name: str,
|
||||
body: WorkerConfigUpdate,
|
||||
user: User = Depends(require_admin),
|
||||
user: User = Depends(require_global_admin),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Update concurrency settings for a specific queue (admin only)."""
|
||||
|
||||
Reference in New Issue
Block a user