Files
HartOMat/plan.md
T
Hartmut 409fb92899 feat(P2): USD Foundation — canonical part identity + material overrides
M1 — USD exporter:
- render-worker/scripts/export_step_to_usd.py (631 lines)
  Full XCAF traversal, one UsdGeom.Mesh per leaf part,
  schaeffler:partKey on every prim, index-space sharpEdgeVertexPairs
- render-worker/Dockerfile: usd-core>=24.11 installed (USD 0.26.3)

M2 — usd_master MediaAsset + pipeline auto-chain:
- migrations 060 (usd_master enum), 061 (3 JSONB columns),
  062 (rename tessellation settings keys)
- generate_usd_master_task: runs export_step_to_usd.py, upserts
  usd_master MediaAsset, writes resolved_material_assignments to CadFile
- Auto-chained from generate_gltf_geometry_task after every GLB export
- step_tasks.py shim re-exports generate_usd_master_task

M3 — scene-manifest API:
- part_key_service.py: build_scene_manifest(), generate_part_key(),
  four-layer material priority resolution with provenance
- SceneManifest / PartEntry Pydantic models in products/schemas.py
- GET /api/cad/{id}/scene-manifest endpoint (graceful fallback to
  parsed_objects when USD not yet generated)
- POST /api/cad/{id}/generate-usd-master endpoint
- frontend/src/api/sceneManifest.ts: fetchSceneManifest(),
  triggerUsdMasterGeneration()

M4 — manual-material-overrides API:
- GET/PUT /api/cad/{id}/manual-material-overrides endpoints
- CadFile.manual_material_overrides JSONB column (migration 061)
- getManualOverrides() / saveManualOverrides() in cad.ts

M5 — ThreeDViewer partKey integration:
- export_step_to_gltf.py injects partKeyMap into GLB extras
- ThreeDViewer: partKeyMap extraction, resolvePartKey(), effectiveMaterials
  merges legacy partMaterials + new manualOverrides (server-side persistence)
- MaterialPanel: dual-path save (partKey vs legacy), provenance badge,
  reconciliation panel for unmatched/unassigned parts

Also:
- Admin.tsx: generate-missing-usd-masters + canonical scenes bulk actions
- ProductDetail.tsx: usd_master row in asset table
- vite-env.d.ts: fix ImportMeta.env TypeScript error
- GPUProbeResult: add timestamp/devices/render_time_s fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:11:09 +01:00

6.4 KiB
Raw Blame History

Plan: P2 USD Foundation — Commit & Verify

Context

All five P2 milestones are already implemented in the working tree as uncommitted changes. The task now is to apply the DB migrations, commit the work, and verify the stack runs.

Milestone status (assessed 2026-03-12)

Milestone Status Key files
M1: export_step_to_usd.py with schaeffler:partKey DONE render-worker/scripts/export_step_to_usd.py (631 lines)
M2: usd_master MediaAsset + migrations 060062 + Celery task DONE migrations 060/061/062, generate_usd_master_task in export_glb.py
M3: GET /api/cad/{id}/scene-manifest DONE part_key_service.py, SceneManifest schema, endpoint in cad.py
M4: PUT /api/cad/{id}/manual-material-overrides DONE New endpoint pair in cad.py, saveManualOverrides in cad.ts
M5: ThreeDViewer uses partKey, survives reload DONE partKeyMap in GLB extras, effectiveMaterials merge, server-side persistence

Affected Files (all uncommitted — working tree only)

Backend

  • backend/alembic/versions/060_usd_master_asset_type.py — new migration
  • backend/alembic/versions/061_material_assignment_layers.py — new migration
  • backend/alembic/versions/062_rename_tessellation_settings.py — new migration
  • backend/app/domains/media/models.pyMediaAssetType.usd_master added
  • backend/app/domains/products/models.py — 3 new JSONB columns on CadFile
  • backend/app/domains/products/schemas.pySceneManifest, PartEntry Pydantic models
  • backend/app/domains/pipeline/tasks/export_glb.pygenerate_usd_master_task + auto-chain
  • backend/app/domains/pipeline/tasks/extract_metadata.py — minor update
  • backend/app/domains/pipeline/tasks/render_thumbnail.py — minor update
  • backend/app/domains/pipeline/tasks/render_order_line.py — minor update
  • backend/app/api/routers/cad.py — scene-manifest + manual-material-overrides endpoints
  • backend/app/api/routers/admin.py — generate-missing-usd-masters + generate-missing-canonical-scenes buttons
  • backend/app/services/part_key_service.py — new file: build_scene_manifest(), generate_part_key()
  • backend/app/core/config_service.py — minor update
  • backend/app/core/tenant_context.py — new file
  • backend/app/tasks/step_tasks.py — re-exports generate_usd_master_task

Render worker

  • render-worker/scripts/export_step_to_usd.py — new file: full USD exporter
  • render-worker/scripts/export_step_to_gltf.py — injects partKeyMap into GLB extras
  • render-worker/scripts/still_render.py — USD path support
  • render-worker/scripts/turntable_render.py — USD path support
  • render-worker/Dockerfileusd-core>=24.11 added

Frontend

  • frontend/src/api/cad.tsgetManualOverrides(), saveManualOverrides()
  • frontend/src/api/media.tsusd_master type added
  • frontend/src/api/sceneManifest.ts — new file: SceneManifest, fetchSceneManifest()
  • frontend/src/components/cad/ThreeDViewer.tsxpartKeyMap, effectiveMaterials, reconciliation panel
  • frontend/src/components/cad/MaterialPanel.tsx — dual-path save, provenance badge
  • frontend/src/pages/Admin.tsx — USD master bulk action buttons
  • frontend/src/pages/ProductDetail.tsxusd_master row in asset table
  • frontend/src/pages/Orders.tsx — minor update

Tasks (in order)

[ ] Task 1: Apply migrations 060062

  • What: Run docker compose exec backend alembic upgrade head to apply the three pending migrations
  • Acceptance gate: docker compose exec backend alembic current shows 062 (or higher) as current
  • Dependencies: none
  • Risk: Low — each migration is additive (ADD VALUE, ADD COLUMN, UPDATE). Check for phantom drops before running.

[ ] Task 2: TypeScript check

  • What: Run docker compose exec frontend npx tsc --noEmit to verify no type errors in the frontend changes
  • Acceptance gate: Zero TypeScript errors
  • Dependencies: none (frontend hot-reload, no rebuild needed)
  • Risk: Low

[ ] Task 3: Rebuild and restart backend + render-worker

  • What: docker compose up -d --build backend worker render-worker beat — picks up new Dockerfile (usd-core), new tasks, and new migrations
  • Acceptance gate: docker compose logs backend | grep "Application startup complete" and docker compose exec render-worker python3 -c "from pxr import Usd; print(Usd.GetVersion())" both succeed
  • Dependencies: Task 1
  • Risk: Medium — usd-core pip install adds build time; if it fails the render-worker won't start

[ ] Task 4: Commit all P2 work

  • What: Stage and commit all uncommitted P2 files in a single feat(P2) commit
  • Acceptance gate: git status shows clean working tree (except LEARNINGS.md and review-report.md which can be included)
  • Dependencies: Tasks 13 (verify before committing)
  • Risk: Low

[ ] Task 5: Smoke-test end-to-end via Admin panel

  • What: Via Admin → "Generate Missing Canonical Scenes" to regenerate GLBs with partKeyMap + auto-chain USD masters for existing CAD files
  • Acceptance gate:
    • GET /api/cad/{id}/scene-manifest returns {"parts": [...], ...} for a processed CadFile
    • ThreeDViewer loads, click a part → MaterialPanel shows assignment provenance
    • Assign a material → reload page → assignment still present
  • Dependencies: Task 3
  • Risk: Medium — existing CAD files need backfill; may take minutes for bulk jobs to complete

Migration Check

Three migrations are pending in the working tree:

  • 060_usd_master_asset_type.py — additive enum value
  • 061_material_assignment_layers.py — additive JSONB columns
  • 062_rename_tessellation_settings.py — UPDATE on system_settings rows (already checked: migration 062 was applied per review-report)

Before running: read each migration file to confirm no unexpected DROP statements.

Order Recommendation

Migrations → TypeScript check → Rebuild → Commit → Smoke test

Risks / Open Questions

  • usd-core build in Docker may be slow (first build) — expected, not a problem
  • Migration 062 may already be applied (review noted "verified by 0-row SELECT") — alembic upgrade head is idempotent if so
  • Existing CAD files need backfill for partKeyMap in GLB extras — handled by "Generate Missing Canonical Scenes" bulk action
  • resolvePartKey() falls back to identity (raw mesh name) for GLBs generated before this change — graceful degradation, not a blocking issue