{"openapi":"3.1.0","info":{"title":"Prototyping.io API","version":"47a4b8f010481ab7e9501711aa0ae5f28c854cec"},"paths":{"/api/v1/health":{"get":{"tags":["health"],"summary":"Health Check","description":"Return application health status, version, and timestamp.","operationId":"health_check_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/debug-sentry":{"get":{"tags":["health"],"summary":"Debug Sentry","description":"Trigger a test error for Sentry. Only available in development.","operationId":"debug_sentry_api_v1_debug_sentry_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Debug Sentry Api V1 Debug Sentry Get"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["auth"],"summary":"Auth Me","description":"Return the current authenticated identity.\n\nAttempts admin resolution first (via ``get_current_admin``).  If that\nfails with 403 (no admin profile), falls back to ``get_current_user``.","operationId":"auth_me_api_v1_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthMeResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/auth/sync":{"post":{"tags":["auth"],"summary":"Sync User","description":"Sync the authenticated Supabase user to the local database.\n\nExtracts ``sub`` and ``email`` from the JWT, then calls\n``AuthService.get_or_create_user``.  Optional profile fields\n(first_name, last_name, company) can be supplied in the request body.","operationId":"sync_user_api_v1_auth_sync_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SyncUserRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/auth/register-with-invite":{"post":{"tags":["auth"],"summary":"Register With Invite","description":"Register a new user account using a waitlist invite token.\n\nNo authentication is required — the invite token itself authorises the\nregistration.  The email is derived from the validated token, not from\nthe request body.","operationId":"register_with_invite_api_v1_auth_register_with_invite_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterWithInviteRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterWithInviteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/dev-info":{"get":{"tags":["auth"],"summary":"Dev Info","description":"Return dev-mode synthetic credentials and configuration.\n\nOnly available when ``ENVIRONMENT=development``.  Returns 404\nin production.","operationId":"dev_info_api_v1_auth_dev_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dev Info Api V1 Auth Dev Info Get"}}}}}}},"/api/v1/users/me":{"get":{"tags":["users"],"summary":"Get Profile","description":"Return the authenticated user's full profile.","operationId":"get_profile_api_v1_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"patch":{"tags":["users"],"summary":"Update Profile","description":"Partially update the authenticated user's profile.\n\nOnly fields included in the request body are modified.","operationId":"update_profile_api_v1_users_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/users/me/welcome-deck":{"get":{"tags":["users"],"summary":"Get Welcome Deck State","description":"Return the current user's welcome deck dismissed-at timestamp.\n\nThe frontend calls this on dashboard mount to decide whether to render\nthe welcome card deck modal. Returns ``None`` when the user has never\nseen / dismissed the deck.","operationId":"get_welcome_deck_state_api_v1_users_me_welcome_deck_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WelcomeDeckResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/users/me/welcome-deck/dismiss":{"post":{"tags":["users"],"summary":"Dismiss Welcome Deck","description":"Mark the welcome card deck as dismissed for the current user.\n\nSets ``UserPreferences.welcome_deck_dismissed_at = now()``. Idempotent —\ncalling twice has no effect after the first call.","operationId":"dismiss_welcome_deck_api_v1_users_me_welcome_deck_dismiss_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WelcomeDeckResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/users/me/company-prompt":{"get":{"tags":["users"],"summary":"Get Company Prompt State","description":"Return whether the current user should see the company prompt.\n\nUsers with a company never see it. Users without one can dismiss it, and\nthe prompt becomes eligible again after ``COMPANY_PROMPT_REPROMPT_DAYS``.","operationId":"get_company_prompt_state_api_v1_users_me_company_prompt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyPromptResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/users/me/company-prompt/dismiss":{"post":{"tags":["users"],"summary":"Dismiss Company Prompt","description":"Defer the optional company prompt for the current user.","operationId":"dismiss_company_prompt_api_v1_users_me_company_prompt_dismiss_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyPromptResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/projects/":{"post":{"tags":["projects"],"summary":"Create Project","description":"Create a new project in DRAFT status.","operationId":"create_project_api_v1_projects__post","security":[{"OAuth2PasswordBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["projects"],"summary":"List Projects","description":"List the current user's projects with pagination, status filter, search, and sorting.","operationId":"list_projects_api_v1_projects__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by project status","title":"Status"},"description":"Filter by project status"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by project name or description","title":"Search"},"description":"Search by project name or description"},{"name":"sort_by","in":"query","required":false,"schema":{"enum":["created_at","updated_at","name","status","priority","target_delivery_date"],"type":"string","description":"Sort field","default":"created_at","title":"Sort By"},"description":"Sort field"},{"name":"sort_order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"Sort order","default":"desc","title":"Sort Order"},"description":"Sort order"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ProjectResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/stats":{"get":{"tags":["projects"],"summary":"Get Project Stats","description":"Get project count statistics for the current user's dashboard.\n\nReturns the total number of projects and a breakdown by status in a\nsingle query, replacing the need for multiple list calls with limit=1.","operationId":"get_project_stats_api_v1_projects_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatsResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/projects/{project_id}/ingest-run":{"get":{"tags":["projects"],"summary":"Get Ingest Run","description":"AI-native ingest run summary: per-part feature counts, DFM score,\npending agent questions, and confirmed assumptions. Column-tuple\nqueries only — powers the analyze-page summary strip and the\nRequest Quote assumptions preflight.","operationId":"get_ingest_run_api_v1_projects__project_id__ingest_run_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/ingest-intent":{"post":{"tags":["projects"],"summary":"Answer Project Ingest Intent","description":"Answer the single pushed project-level intent question (\"What are\nthese parts for?\"). Fans out to every part's DesignIntent.purpose via\nthe manufacturing-intent ledger (idempotent); parts finalizing later\nare picked up by the question generator.","operationId":"answer_project_ingest_intent_api_v1_projects__project_id__ingest_intent_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectIntentAnswerRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}":{"get":{"tags":["projects"],"summary":"Get Project","description":"Get a single project with its parts eagerly loaded.","operationId":"get_project_api_v1_projects__project_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["projects"],"summary":"Update Project","description":"Partially update a project.\n\nMost fields can only be changed while in DRAFT status.\n``shipping_address_id`` can be updated regardless of project status;\nchanging it will invalidate any active quotes (QUOTED/APPROVED).","operationId":"update_project_api_v1_projects__project_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["projects"],"summary":"Delete Project","description":"Soft-delete a project by setting its status to CANCELLED.\n\nOnly projects in DRAFT status can be deleted.","operationId":"delete_project_api_v1_projects__project_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/activity-events":{"get":{"tags":["projects"],"summary":"List Project Activity Events","description":"List recent deterministic project activity for Ollie-aware UI.","operationId":"list_project_activity_events_api_v1_projects__project_id__activity_events_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectActivityEventResponse"},"title":"Response List Project Activity Events Api V1 Projects  Project Id  Activity Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/submit":{"post":{"tags":["projects"],"summary":"Submit Project","description":"Submit a project for review. Transitions status from DRAFT to SUBMITTED.\n\n``background_tasks`` is threaded through to ``ProjectService.submit`` so\nthe vendors-agent outbound hook can schedule its session start as a\nBackgroundTask (PRO-70). The hook is feature-flagged and isolated;\nSUBMIT itself never depends on the agent infrastructure being healthy.","operationId":"submit_project_api_v1_projects__project_id__submit_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSubmitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/shipment":{"get":{"tags":["projects"],"summary":"Get Project Shipment","description":"Get the shipment for a project with tracking events.","operationId":"get_project_shipment_api_v1_projects__project_id__shipment_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/":{"post":{"tags":["parts"],"summary":"Create Part","description":"Create a new part within a DRAFT project.","operationId":"create_part_api_v1_projects__project_id__parts__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["parts"],"summary":"List Parts","description":"List all parts for a project, ordered by creation time.","operationId":"list_parts_api_v1_projects__project_id__parts__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PartSummaryResponse"},"title":"Response List Parts Api V1 Projects  Project Id  Parts  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}":{"get":{"tags":["parts"],"summary":"Get Part","description":"Get a single part with its CAD file versions eagerly loaded.","operationId":"get_part_api_v1_projects__project_id__parts__part_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["parts"],"summary":"Update Part","description":"Partially update a part. Only allowed while the project is in DRAFT status.","operationId":"update_part_api_v1_projects__project_id__parts__part_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["parts"],"summary":"Delete Part","description":"Hard-delete a part. Allowed in pre-order statuses (DRAFT through QUOTE_REJECTED).","operationId":"delete_part_api_v1_projects__project_id__parts__part_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/bulk":{"patch":{"tags":["parts"],"summary":"Bulk Update Parts","description":"Bulk-update specs on multiple parts. Only allowed while project is DRAFT.","operationId":"bulk_update_parts_api_v1_projects__project_id__parts_bulk_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartBulkUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PartSummaryResponse"},"title":"Response Bulk Update Parts Api V1 Projects  Project Id  Parts Bulk Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}/finish":{"patch":{"tags":["parts"],"summary":"Update Part Finish","description":"Apply a unified Finish update to a part.\n\nReplaces the two-call (finishing_id + coating_id) pattern with a\nsingle atomic write. Selecting a finish-dropdown row decomposes\nonto the correct backend column (``finishing_id`` for mechanical\nstate, ``coating_id`` for bath/coating); the inverse field is set\nto NULL so the part never carries both at once.\n\nSee ``app/services/parts.py::PartService.update_finish`` for the\nfull validation matrix (process / material compat, color palette,\ncustom-color path).","operationId":"update_part_finish_api_v1_projects__project_id__parts__part_id__finish_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinishUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}/cad/{version_id}/diff":{"get":{"tags":["parts"],"summary":"Get Feature Diff","description":"Compute feature diff between two CadFileVersions.\n\nIf compare_to is not provided, compares against the previous version.\nUses stable feature_id for matching.","operationId":"get_feature_diff_api_v1_projects__project_id__parts__part_id__cad__version_id__diff_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}},{"name":"compare_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Compare To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"anyOf":[{"type":"array","items":{"type":"object","additionalProperties":{"type":"string"}}},{"type":"integer"}]},"title":"Response Get Feature Diff Api V1 Projects  Project Id  Parts  Part Id  Cad  Version Id  Diff Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}/retrigger-analysis":{"post":{"tags":["parts"],"summary":"Retrigger Analysis","description":"Force-restart deterministic DFM/pricing for a part.\n\nUsed by the analysis sidebar Retry button when a part lands in\n``analysis_status=FAILED``. Returns 202 for the existing client\ncontract; the chokepoint owns the COMPLETE / FAILED transition.\n\nPermission: user must own the parent project. Admins use the\nparallel admin endpoint, which skips the ownership check.","operationId":"retrigger_analysis_api_v1_projects__project_id__parts__part_id__retrigger_analysis_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetriggerAnalysisRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetriggerAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}/drawing-conflicts":{"get":{"tags":["parts"],"summary":"List Drawing Conflicts","description":"Open spec-level drawing-vs-selection conflicts for a part.","operationId":"list_drawing_conflicts_api_v1_projects__project_id__parts__part_id__drawing_conflicts_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DrawingModelConflictResponse"},"title":"Response List Drawing Conflicts Api V1 Projects  Project Id  Parts  Part Id  Drawing Conflicts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/parts/{part_id}/drawing-conflicts/{conflict_id}/resolve":{"post":{"tags":["parts"],"summary":"Resolve Drawing Conflict","description":"Resolve a spec conflict: apply the drawing's value or keep the user's.\n\n``choice=\"drawing\"`` applies the drawing's proposal through the SAME\n``PartService.update`` path as the spec form (validation, provenance\nmarker clearing, pricing chokepoint refresh all inherited). Resolutions\npersist with ``resolved_by=\"customer\"`` — future seeds for the R3\nconfirmed-intent ledger.","operationId":"resolve_drawing_conflict_api_v1_projects__project_id__parts__part_id__drawing_conflicts__conflict_id__resolve_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"conflict_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conflict Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConflictResolveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingModelConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/quote-pdf":{"get":{"tags":["quotes"],"summary":"Get Quote Pdf","description":"Get presigned download URL for the quote PDF.","operationId":"get_quote_pdf_api_v1_projects__project_id__quotes_quote_pdf_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"delivery_option_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Delivery Option Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/request":{"post":{"tags":["quotes"],"summary":"Request Quote","description":"Request a quote for a project.\n\nCreates a new quote in SUBMITTED status with a line item for each\npart in the project.  Transitions the project to SUBMITTED if it\nwas previously in DRAFT status.","operationId":"request_quote_api_v1_projects__project_id__quotes_request_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequestCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/place-order-request":{"post":{"tags":["quotes"],"summary":"Place Order Request","description":"User-facing 'Place Order Request' for high-confidence parts.\n\nComputes per-part cost + lead time using the deterministic DFM\nservices, freezes the calculation as ``cost_snapshot`` on the new\nQuote, and creates it with ``intent=AUTO_ESTIMATE`` in\n``status=SUBMITTED``. Notifies admins for confirmation.\n\nReturns 400 if any part is missing specs, still processing, or\nuses a manual-quote-only process.","operationId":"place_order_request_api_v1_projects__project_id__quotes_place_order_request_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceOrderRequestBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/edit-pending":{"patch":{"tags":["quotes"],"summary":"Edit Pending Order Request","description":"Edit a still-pending auto-estimate order request.\n\nAllowed only when ``intent=AUTO_ESTIMATE`` and ``status=SUBMITTED``.\nEditable fields: per-part quantity / material / finish, target\ndelivery date, PO number, notes. Process and adding/removing parts\nare locked.\n\nUses optimistic concurrency via ``snapshot_version`` — pass the\nversion you read so the server can detect concurrent admin\nconfirmation and reject with 409.","operationId":"edit_pending_order_request_api_v1_projects__project_id__quotes__quote_id__edit_pending_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditPendingOrderBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/pricing-preview":{"get":{"tags":["quotes"],"summary":"Preview Project Pricing","description":"Preview the instant estimate shown on the draft Order Summary.\n\nReuses the same deterministic pricing path that freezes auto-estimate\nquotes, but does not create a quote or emit pricing telemetry.","operationId":"preview_project_pricing_api_v1_projects__project_id__quotes_pricing_preview_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectPricingPreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/":{"get":{"tags":["quotes"],"summary":"List Quotes","description":"List all quotes for a project, ordered by newest first.","operationId":"list_quotes_api_v1_projects__project_id__quotes__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QuoteResponse"},"title":"Response List Quotes Api V1 Projects  Project Id  Quotes  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}":{"get":{"tags":["quotes"],"summary":"Get Quote","description":"Get a single quote with its line items.\n\nRetention D3.7: this CUSTOMER read (ownership enforced by get_by_id)\nbumps the in-app quote-view counters — \"viewed 5x, never ordered\" vs\n\"never viewed\" are the two loss stories the CRM timeline tells. Admin\nreads go through the admin routers and never touch these counters.\nBest-effort: a counter failure must never break the quote read.","operationId":"get_quote_api_v1_projects__project_id__quotes__quote_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/request-reactivation":{"post":{"tags":["quotes"],"summary":"Request Quote Reactivation","description":"Customer asks us to take another look at an EXPIRED quote (E1/DR7).\n\nThe unified reactivation action: same admin notification + timeline\nevent as the loss-confirm page's post-submit button — two entry\npoints, one path.","operationId":"request_quote_reactivation_api_v1_projects__project_id__quotes__quote_id__request_reactivation_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/approve":{"post":{"tags":["quotes"],"summary":"Approve Quote","description":"Approve a quote.\n\nThe quote must be in QUOTED status and must have been human-reviewed\nby an admin before the customer can approve it.","operationId":"approve_quote_api_v1_projects__project_id__quotes__quote_id__approve_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QuoteApprovalRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteApprovalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/delivery-option-selection":{"patch":{"tags":["quotes"],"summary":"Change Selected Delivery Option","description":"Change the accepted delivery option before payment/PO submission.","operationId":"change_selected_delivery_option_api_v1_projects__project_id__quotes__quote_id__delivery_option_selection_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionSelectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/reject":{"post":{"tags":["quotes"],"summary":"Reject Quote","description":"Reject a quote, optionally providing a reason.","operationId":"reject_quote_api_v1_projects__project_id__quotes__quote_id__reject_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRejectRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteApprovalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/quotes/{quote_id}/request-changes":{"post":{"tags":["quotes"],"summary":"Request Changes","description":"Request changes to a quote with a message explaining what needs to change.","operationId":"request_changes_api_v1_projects__project_id__quotes__quote_id__request_changes_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteChangesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteApprovalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/initiate":{"post":{"tags":["cad-uploads"],"summary":"Initiate Upload","description":"Initiate a CAD file upload by creating a CadFileVersion row.\n\nReturns the ``r2_key`` and ``version_id``. The client then streams the\nraw file bytes to ``POST /parts/{part_id}/cad/upload/{version_id}`` and\nfinally calls ``POST /confirm`` with the ``version_id`` and ``r2_key``.","operationId":"initiate_upload_api_v1_parts__part_id__cad_initiate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/upload/{version_id}":{"post":{"tags":["cad-uploads"],"summary":"Upload Cad File","description":"Stream a CAD file to R2 server-side (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``,\nwhich corporate firewalls can block. The client POSTs the file as\n``multipart/form-data`` to this endpoint; the API streams it straight\nto R2. The client must still call ``POST /confirm`` afterwards.\n\nAuthorization: the version must belong to ``part_id``, the part must\nbe owned by the current user, and the version must still be in\nUPLOADING status. The file is written to the version's stored\n``r2_key`` — the client cannot choose an arbitrary key.","operationId":"upload_cad_file_api_v1_parts__part_id__cad_upload__version_id__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_cad_file_api_v1_parts__part_id__cad_upload__version_id__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Upload Cad File Api V1 Parts  Part Id  Cad Upload  Version Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/confirm":{"post":{"tags":["cad-uploads"],"summary":"Confirm Upload","description":"Confirm that the client-side upload to R2 completed successfully.\n\nTransitions the ``CadFileVersion`` from UPLOADING to UPLOADED status\nand marks it as the latest version for the part.","operationId":"confirm_upload_api_v1_parts__part_id__cad_confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CadFileVersionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/":{"get":{"tags":["cad-uploads"],"summary":"List Versions","description":"List all non-deleted CAD file versions for a part, newest first.","operationId":"list_versions_api_v1_parts__part_id__cad__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CadFileVersionResponse"},"title":"Response List Versions Api V1 Parts  Part Id  Cad  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/{version_id}/status":{"get":{"tags":["cad-uploads"],"summary":"Get Processing Status","description":"Get lightweight processing status for a CAD file version.\n\nReturns only status, processing_step, and error_message — suitable\nfor frequent polling during pipeline execution. Selects exactly those\ncolumns (the previous full-row load dragged every JSON blob on the\nversion through the pooled connection on each poll).","operationId":"get_processing_status_api_v1_parts__part_id__cad__version_id__status_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessingStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/{version_id}/download-url":{"get":{"tags":["cad-uploads"],"summary":"Get Download Url","description":"Generate a presigned download URL for a file belonging to this version.\n\nThe ``key`` query parameter must exactly match one of the version's stored\nR2 keys (``r2_key``, ``glb_r2_key``, ``thumbnail_r2_key``, or\n``topology_r2_key``). Different TTLs are applied depending on the file type:\n\n- Raw CAD file (``r2_key``): 5 minutes\n- GLB file (``glb_r2_key``): 15 minutes\n- Thumbnail (``thumbnail_r2_key``): 1 hour\n- Topology sidecar (``topology_r2_key``): 15 minutes (paired with GLB)","operationId":"get_download_url_api_v1_parts__part_id__cad__version_id__download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}},{"name":"key","in":"query","required":true,"schema":{"type":"string","description":"R2 object key to generate a download URL for. Must match one of the version's R2 keys (r2_key, glb_r2_key, thumbnail_r2_key, or topology_r2_key).","title":"Key"},"description":"R2 object key to generate a download URL for. Must match one of the version's R2 keys (r2_key, glb_r2_key, thumbnail_r2_key, or topology_r2_key)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/cad/{version_id}":{"get":{"tags":["cad-uploads"],"summary":"Get Version","description":"Get a single CAD file version by ID.\n\nThe ``detected_features`` blob is filtered against the part's selected\nmanufacturing process so the user sidebar doesn't show CNC-only features\non a sheet metal part (and vice versa). The ``?unfiltered=true`` escape\nhatch returns the full raw blob for debugging.","operationId":"get_version_api_v1_parts__part_id__cad__version_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}},{"name":"unfiltered","in":"query","required":false,"schema":{"type":"boolean","description":"Skip process-aware feature filtering. Admin/debug only — ownership is already verified above.","default":false,"title":"Unfiltered"},"description":"Skip process-aware feature filtering. Admin/debug only — ownership is already verified above."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CadFileVersionDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["cad-uploads"],"summary":"Delete Version","description":"Soft-delete a CAD file version (sets status to DELETED).","operationId":"delete_version_api_v1_parts__part_id__cad__version_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/assembly-file/initiate-upload":{"post":{"tags":["assembly-files"],"summary":"Initiate Assembly Upload","description":"Initiate an assembly file upload — returns the R2 key.\n\nHard-replaces any existing assembly file for the project (deletes the\nold R2 object + DB row before creating the new row). The client then\nstreams the file to ``POST /upload`` and finally calls confirm-upload.\n\nReturns 409 ``ASSEMBLY_UPLOAD_BLOCKED_BY_STATUS`` if the project is\npast IN_PRODUCTION.","operationId":"initiate_assembly_upload_api_v1_projects__project_id__assembly_file_initiate_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateAssemblyUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateAssemblyUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/assembly-file/upload":{"post":{"tags":["assembly-files"],"summary":"Upload Assembly File","description":"Stream an assembly file to R2 server-side (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``.\nThe client POSTs the file as ``multipart/form-data`` to this endpoint;\nthe API streams it straight to R2. The client must still call\n``POST /confirm-upload`` afterwards.\n\nAuthorization: the project must be owned by the current user, the\nproject status must still allow mutations, and the assembly file row\n(created by ``/initiate-upload``) must be in UPLOADING status. The\nfile is written to the row's stored ``r2_key`` — the client cannot\nchoose an arbitrary key.","operationId":"upload_assembly_file_api_v1_projects__project_id__assembly_file_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_assembly_file_api_v1_projects__project_id__assembly_file_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Upload Assembly File Api V1 Projects  Project Id  Assembly File Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/assembly-file/confirm-upload":{"post":{"tags":["assembly-files"],"summary":"Confirm Assembly Upload","description":"Confirm the browser PUT to R2 completed; queue magic-bytes validation.\n\nTransitions the row from ``uploading`` -> ``uploaded`` and kicks off\nthe validation Temporal workflow on the light worker.","operationId":"confirm_assembly_upload_api_v1_projects__project_id__assembly_file_confirm_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmAssemblyUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssemblyFileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/assembly-file":{"get":{"tags":["assembly-files"],"summary":"Get Assembly File","description":"Return the project's current assembly file (or null if none).\n\nIncludes a presigned GET URL (``download_url``) when the file is in\n``validated`` status. Allowed regardless of project status — only\nmutations are gated.","operationId":"get_assembly_file_api_v1_projects__project_id__assembly_file_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AssemblyFileResponse"},{"type":"null"}],"title":"Response Get Assembly File Api V1 Projects  Project Id  Assembly File Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["assembly-files"],"summary":"Delete Assembly File","description":"Hard-delete the project's assembly file (R2 object + DB row).\n\nIdempotent — returns 204 even if no assembly file exists.\nReturns 409 if the project is past IN_PRODUCTION.","operationId":"delete_assembly_file_api_v1_projects__project_id__assembly_file_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents":{"get":{"tags":["project-documents"],"summary":"List Project Documents","operationId":"list_project_documents_api_v1_projects__project_id__documents_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDocumentResponse"},"title":"Response List Project Documents Api V1 Projects  Project Id  Documents Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents/initiate-upload":{"post":{"tags":["project-documents"],"summary":"Initiate Project Document Upload","operationId":"initiate_project_document_upload_api_v1_projects__project_id__documents_initiate_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateProjectDocumentUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateProjectDocumentUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents/{document_id}/upload":{"post":{"tags":["project-documents"],"summary":"Upload Project Document","operationId":"upload_project_document_api_v1_projects__project_id__documents__document_id__upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_project_document_api_v1_projects__project_id__documents__document_id__upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Upload Project Document Api V1 Projects  Project Id  Documents  Document Id  Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents/confirm-upload":{"post":{"tags":["project-documents"],"summary":"Confirm Project Document Upload","operationId":"confirm_project_document_upload_api_v1_projects__project_id__documents_confirm_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmProjectDocumentUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDocumentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents/{document_id}/download-url":{"get":{"tags":["project-documents"],"summary":"Get Project Document Download Url","operationId":"get_project_document_download_url_api_v1_projects__project_id__documents__document_id__download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Get Project Document Download Url Api V1 Projects  Project Id  Documents  Document Id  Download Url Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/documents/{document_id}":{"delete":{"tags":["project-documents"],"summary":"Delete Project Document","operationId":"delete_project_document_api_v1_projects__project_id__documents__document_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/initiate":{"post":{"tags":["drawings"],"summary":"Initiate Drawing Upload","description":"Initiate a drawing file upload by deriving its R2 key.\n\nReturns the ``r2_key``. The client then streams the raw file bytes to\n``POST /parts/{part_id}/drawings/upload`` and finally calls\n``POST /confirm`` with the ``r2_key`` and ``file_size``.","operationId":"initiate_drawing_upload_api_v1_parts__part_id__drawings_initiate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateDrawingUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateDrawingUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/upload":{"post":{"tags":["drawings"],"summary":"Upload Drawing File","description":"Stream a drawing file to R2 server-side (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``.\nThe client POSTs the file as ``multipart/form-data`` and passes the\n``r2_key`` returned by ``/initiate`` as a query parameter. The client\nmust still call ``POST /confirm`` afterwards.\n\nAuthorization: the part must be owned by the current user, and the\nrequested ``r2_key`` must fall inside the deterministic\n``drawings/{user_id}/{part_id}/`` namespace for this part — any key\noutside it is rejected (403).","operationId":"upload_drawing_file_api_v1_parts__part_id__drawings_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"r2_key","in":"query","required":true,"schema":{"type":"string","description":"R2 object key from the initiate endpoint.","title":"R2 Key"},"description":"R2 object key from the initiate endpoint."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_drawing_file_api_v1_parts__part_id__drawings_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Upload Drawing File Api V1 Parts  Part Id  Drawings Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/confirm":{"post":{"tags":["drawings"],"summary":"Confirm Drawing Upload","description":"Confirm that the client-side drawing upload to R2 completed successfully.\n\nSaves the drawing metadata (file name, R2 key, file size) on the Part record.","operationId":"confirm_drawing_upload_api_v1_parts__part_id__drawings_confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmDrawingUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Confirm Drawing Upload Api V1 Parts  Part Id  Drawings Confirm Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/download-url":{"get":{"tags":["drawings"],"summary":"Get Drawing Download Url","description":"Generate a presigned download URL for the part's drawing file.","operationId":"get_drawing_download_url_api_v1_parts__part_id__drawings_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/redacted-download-url":{"get":{"tags":["drawings"],"summary":"Get Redacted Drawing Download Url","description":"Generate a presigned download URL for the redacted drawing (admin only).\n\nThe redacted drawing has logos, company data, and PII removed —\nsafe for sharing with suppliers.","operationId":"get_redacted_drawing_download_url_api_v1_parts__part_id__drawings_redacted_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/":{"delete":{"tags":["drawings"],"summary":"Delete Drawing","description":"Remove drawing metadata from the Part.\n\nNote: This clears the Part fields but does not delete the R2 object.\nOrphaned R2 objects can be cleaned up via a periodic job if needed.","operationId":"delete_drawing_api_v1_parts__part_id__drawings__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/link-callout":{"post":{"tags":["drawings"],"summary":"Link Callout","description":"Manually link (or unlink) a drawing callout to a 3D feature.\n\nThis persists the link in two places:\n\n1. **Immediate:** mutates ``part.drawing_analysis[category][idx].feature_id``\n   in place so the frontend sees the link reflected on the next query.\n   Uses ``flag_modified`` because SQLAlchemy's MutableDict does not\n   recursively track nested mutations (see comment on Part.drawing_analysis).\n2. **Durable:** creates an ``OutcomeEvent`` with\n   ``outcome_type=\"user_drawing_link\"`` so the stitcher respects the\n   user's choice on re-run (and we have an audit trail).\n\nValidates:\n- User owns the parent project (404 otherwise)\n- Category is one of the valid drawing_analysis field names (400 otherwise)\n- callout_index is within bounds (400 otherwise)\n- When action='link', target_feature_id is provided AND exists on a\n  detected feature in the part's latest CAD version (400 otherwise)","operationId":"link_callout_api_v1_parts__part_id__drawings_link_callout_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkCalloutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkCalloutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/drawings/retry-analysis":{"post":{"tags":["drawings"],"summary":"Retry Drawing Analysis","description":"Re-kick the drawing analysis for this part.\n\nUsed by the \"Retry analysis\" button in the failure empty state.\n\nStarts the ``DrawingAnalysisWorkflow`` (TERMINATE_EXISTING — a retry\nsupersedes any in-flight run). The activity downloads the PDF from R2\non the light worker and writes back to ``part.drawing_analysis`` when\ncomplete.\n\nClears ``part.drawing_analysis`` up front so the UI flips back to the\n\"processing\" state and hides the retry button while the new run is in\nflight.\n\nValidates:\n- User owns the parent project (404 otherwise)\n- Part has an uploaded drawing_r2_key (400 otherwise)","operationId":"retry_drawing_analysis_api_v1_parts__part_id__drawings_retry_analysis_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/files":{"get":{"tags":["files"],"summary":"Get File","description":"Stream a token-referenced R2 object (no filename in the path).\n\nUsed for viewer assets — GLB models, thumbnails — that are loaded by\n``<img>`` / ``GLTFLoader`` and never \"downloaded\" by name.","operationId":"get_file_api_v1_files_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","description":"HMAC-signed file-download token.","title":"T"},"description":"HMAC-signed file-download token."},{"name":"filename","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Legacy filename hint (path-segment form is preferred).","title":"Filename"},"description":"Legacy filename hint (path-segment form is preferred)."},{"name":"disposition","in":"query","required":false,"schema":{"type":"string","description":"'inline' (default) or 'attachment' to force a download.","default":"inline","title":"Disposition"},"description":"'inline' (default) or 'attachment' to force a download."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/files/{download_name}":{"get":{"tags":["files"],"summary":"Get Named File","description":"Stream a token-referenced R2 object, named by the path segment.\n\n``download_name`` is the trailing URL path segment. It is **only** a\ncosmetic hint so the browser names the download/inline-view correctly\n(Chrome's PDF viewer reads the filename from the path); the signed\n``t`` token is the sole authority for which object is served.","operationId":"get_named_file_api_v1_files__download_name__get","parameters":[{"name":"download_name","in":"path","required":true,"schema":{"type":"string","title":"Download Name"}},{"name":"t","in":"query","required":true,"schema":{"type":"string","description":"HMAC-signed file-download token.","title":"T"},"description":"HMAC-signed file-download token."},{"name":"disposition","in":"query","required":false,"schema":{"type":"string","description":"'inline' (default) or 'attachment' to force a download.","default":"inline","title":"Disposition"},"description":"'inline' (default) or 'attachment' to force a download."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dropdowns/":{"get":{"tags":["dropdowns"],"summary":"List All","description":"Return all active dropdowns grouped by category.\n\nThe frontend fetches this once on load and caches the result to\npopulate the machining-process, material, finishing, and coating selects.\n\nOptional ``?material_id=X`` filters the ``coatings`` group to only\ncoatings compatible with that material (per ``VALID_COATING_COMBINATIONS``).\nEmpty list for plastics + 3D-printing materials → frontend disables\nthe coating select.","operationId":"list_all_api_v1_dropdowns__get","parameters":[{"name":"material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropdownListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dropdowns/validate":{"post":{"tags":["dropdowns"],"summary":"Validate Combination","description":"Check whether a process/material/finishing combination is supported.\n\nUsed when the user selects manufacturing specs for a part.  The\nbackend checks the ``process_mappings`` table to confirm the\ncombination is valid before persisting the selection.","operationId":"validate_combination_api_v1_dropdowns_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateMaterialRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateMaterialResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dropdowns/materials-for-process/{process_id}":{"get":{"tags":["dropdowns"],"summary":"Get Materials","description":"Return materials that are valid for the given machining process.\n\nEnables cascading dropdowns: after the user selects a machining\nprocess, the material dropdown is filtered to only show compatible\noptions.","operationId":"get_materials_api_v1_dropdowns_materials_for_process__process_id__get","parameters":[{"name":"process_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Process Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DropdownResponse"},"title":"Response Get Materials Api V1 Dropdowns Materials For Process  Process Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dropdowns/finishings-for-process/{process_id}":{"get":{"tags":["dropdowns"],"summary":"Get Finishings","description":"Return finishings that are valid for the given machining process.\n\nSimilar to the materials endpoint — enables cascading dropdown\nfiltering based on the selected machining process.","operationId":"get_finishings_api_v1_dropdowns_finishings_for_process__process_id__get","parameters":[{"name":"process_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Process Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DropdownResponse"},"title":"Response Get Finishings Api V1 Dropdowns Finishings For Process  Process Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dropdowns/{category}":{"get":{"tags":["dropdowns"],"summary":"List By Category","description":"Return active dropdowns for a specific category.\n\nValid categories include ``machining_process``, ``material``,\n``finishing``, and ``coating``.  Returns a 400 for unknown categories.\n\nOptional ``?material_id=X`` filters ``coating`` results to only\ncoatings compatible with that material (per ``VALID_COATING_COMBINATIONS``).\nIgnored for non-coating categories. Empty list = \"no coatings\navailable for this material\" — the frontend uses that signal to\ndisable the coating select.","operationId":"list_by_category_api_v1_dropdowns__category__get","parameters":[{"name":"category","in":"path","required":true,"schema":{"type":"string","title":"Category"}},{"name":"material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DropdownResponse"},"title":"Response List By Category Api V1 Dropdowns  Category  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/dashboard/":{"get":{"tags":["user-dashboard"],"summary":"Get User Dashboard","description":"Return recent activity scoped to the authenticated user.\n\nMerges the user's projects and quotes into a single feed ordered\nby creation date (newest first), limited to 10 items.","operationId":"get_user_dashboard_api_v1_dashboard__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDashboardResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/notifications/":{"get":{"tags":["notifications"],"summary":"List Notifications","operationId":"list_notifications_api_v1_notifications__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"unread_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Unread Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/unread-count":{"get":{"tags":["notifications"],"summary":"Get Unread Count","operationId":"get_unread_count_api_v1_notifications_unread_count_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreadCountResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/notifications/{notification_id}/read":{"patch":{"tags":["notifications"],"summary":"Mark Read","operationId":"mark_read_api_v1_notifications__notification_id__read_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/read-all":{"patch":{"tags":["notifications"],"summary":"Mark All Read","operationId":"mark_all_read_api_v1_notifications_read_all_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Mark All Read Api V1 Notifications Read All Patch"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/notifications/preferences":{"get":{"tags":["notifications"],"summary":"Get Preferences","operationId":"get_preferences_api_v1_notifications_preferences_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/NotificationPreferenceResponse"},"type":"array","title":"Response Get Preferences Api V1 Notifications Preferences Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"put":{"tags":["notifications"],"summary":"Update Preferences","operationId":"update_preferences_api_v1_notifications_preferences_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/NotificationPreferenceResponse"},"type":"array","title":"Response Update Preferences Api V1 Notifications Preferences Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/payments/calculate-tax":{"post":{"tags":["payments"],"summary":"Calculate Tax","description":"Calculate tax for a project quote based on shipping address.\n\nUses the Stripe Tax Calculation API to compute destination-based\nsales tax. The returned ``calculation_id`` must be passed to\n``create-intent`` or ``purchase-order`` to attach tax to the payment.\n\nHandles deposit quotes: if the quote requires a deposit, tax is\ncalculated on the deposit portion of each line item.","operationId":"calculate_tax_api_v1_payments_calculate_tax_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxCalculateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxCalculateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/payments/create-intent":{"post":{"tags":["payments"],"summary":"Create Payment Intent","description":"Create a Stripe PaymentIntent for an approved project.\n\nReturns the ``client_secret`` needed to initialize Stripe Elements\non the frontend. Idempotent — calling again for the same project\nreturns the existing PaymentIntent.\n\nIf ``tax_calculation_id`` is provided (from a prior ``calculate-tax``\ncall), the PaymentIntent amount will include tax and the calculation\nwill be linked to the PaymentIntent for automatic tax transaction\ncreation on success.","operationId":"create_payment_intent_api_v1_payments_create_intent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntentCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/payments/{project_id}":{"get":{"tags":["payments"],"summary":"Get Payment","description":"Get the payment status for a project.","operationId":"get_payment_api_v1_payments__project_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/{project_id}/invoice":{"get":{"tags":["payments"],"summary":"Get Invoice","description":"Get the invoice for a completed payment.","operationId":"get_invoice_api_v1_payments__project_id__invoice_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/purchase-order":{"post":{"tags":["payments"],"summary":"Submit Purchase Order","description":"Submit a Purchase Order for an approved project.\n\nThe quote must be approved and human-reviewed before a PO can be\nsubmitted.\n\nIf ``tax_calculation_id`` is provided (from a prior ``calculate-tax``\ncall), the tax amounts are stored on the Payment record and will be\nused when the admin marks the PO as received to create a Stripe Tax\nTransaction.","operationId":"submit_purchase_order_api_v1_payments_purchase_order_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/payments/po-document":{"post":{"tags":["payments"],"summary":"Upload Po Document","description":"Stream a PO document to R2 server-side (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``.\nThe client POSTs the file as ``multipart/form-data`` with the\n``project_id`` as a query parameter; the API streams it straight to\nR2 and returns the ``r2_key``. The client passes that key back as\n``po_document_r2_key`` on the subsequent ``POST /payments/purchase-order``\ncall.\n\nAuthorization: the project must be owned by the current user and have\nthe same approved, human-reviewed quote required for PO submission.\nThe file is written to a key namespaced under the user's id — the\nclient cannot choose an arbitrary key.","operationId":"upload_po_document_api_v1_payments_po_document_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_po_document_api_v1_payments_po_document_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/POUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/po-document-extractions/{extraction_id}":{"get":{"tags":["payments"],"summary":"Get Po Document Extraction","description":"Return extraction payload for a PO document uploaded by this user.","operationId":"get_po_document_extraction_api_v1_payments_po_document_extractions__extraction_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"extraction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Extraction Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommercialDocumentExtractionReview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/config/stripe":{"get":{"tags":["payments"],"summary":"Get Stripe Config","description":"Get the Stripe publishable key for frontend Elements initialization.","operationId":"get_stripe_config_api_v1_config_stripe_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeConfigResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/payments/{project_id}/invoice-pdf":{"get":{"tags":["payments"],"summary":"Get Invoice Pdf","description":"Get presigned download URL for the invoice PDF.","operationId":"get_invoice_pdf_api_v1_payments__project_id__invoice_pdf_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/business-profile":{"get":{"tags":["business-profiles"],"summary":"Get Business Profile","description":"Return the current user's business profile. 404 if none exists.","operationId":"get_business_profile_api_v1_business_profile_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"post":{"tags":["business-profiles"],"summary":"Create Business Profile","description":"Create a business profile for PO eligibility. 400 if one already exists.","operationId":"create_business_profile_api_v1_business_profile_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessProfileCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"patch":{"tags":["business-profiles"],"summary":"Update Business Profile","description":"Update the current user's business profile. 404 if none exists.","operationId":"update_business_profile_api_v1_business_profile_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessProfileUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/business-profile/tax-exempt-cert":{"post":{"tags":["business-profiles"],"summary":"Upload Tax Exempt Cert","description":"Stream a tax-exempt certificate to R2 (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``.\nThe client POSTs the file as ``multipart/form-data``; the API streams\nit straight to R2 and returns the ``r2_key``. After uploading, the\nuser should PATCH ``/business-profile`` with ``tax_exempt_cert_r2_key``\nset to the returned ``r2_key`` to associate the certificate with their\nprofile.\n\nAuthorization: the user must already have a business profile. The\nfile is written to a key namespaced under the user's id — the client\ncannot choose an arbitrary key.","operationId":"upload_tax_exempt_cert_api_v1_business_profile_tax_exempt_cert_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_tax_exempt_cert_api_v1_business_profile_tax_exempt_cert_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxExemptCertUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/shipping-addresses/":{"get":{"tags":["shipping-addresses"],"summary":"List Shipping Addresses","description":"List all saved shipping addresses for the current user.","operationId":"list_shipping_addresses_api_v1_shipping_addresses__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ShippingAddressResponse"},"type":"array","title":"Response List Shipping Addresses Api V1 Shipping Addresses  Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"post":{"tags":["shipping-addresses"],"summary":"Create Shipping Address","description":"Create a new shipping address. Max 10 per user.","operationId":"create_shipping_address_api_v1_shipping_addresses__post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingAddressCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingAddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/shipping-addresses/{address_id}":{"patch":{"tags":["shipping-addresses"],"summary":"Update Shipping Address","description":"Update an existing shipping address.","operationId":"update_shipping_address_api_v1_shipping_addresses__address_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingAddressUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingAddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["shipping-addresses"],"summary":"Delete Shipping Address","description":"Delete a shipping address.","operationId":"delete_shipping_address_api_v1_shipping_addresses__address_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/webhooks/stripe":{"post":{"tags":["webhooks"],"summary":"Stripe Webhook","description":"Handle incoming Stripe webhook events.\n\nReads the raw request body for signature verification.\nReturns 200 on success, 400 on invalid signature.","operationId":"stripe_webhook_api_v1_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/webhooks/sendgrid":{"post":{"tags":["webhooks"],"summary":"Sendgrid Webhook","operationId":"sendgrid_webhook_api_v1_webhooks_sendgrid_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Sendgrid Webhook Api V1 Webhooks Sendgrid Post"}}}}}}},"/api/v1/followups/public/loss-reason":{"get":{"tags":["followups-public"],"summary":"Loss Reason Context","description":"Render context for the confirm page. READ ONLY — never writes.","operationId":"loss_reason_context_api_v1_followups_public_loss_reason_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LossReasonContext"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["followups-public"],"summary":"Submit Loss Reason","description":"Confirm POST from the loss page. Idempotent: a repeat submit with a\nreason already recorded refuses the overwrite (stale-token protection)\nand reports ``already_recorded``.","operationId":"submit_loss_reason_api_v1_followups_public_loss_reason_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LossReasonSubmit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LossReasonResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/followups/public/reactivate":{"post":{"tags":["followups-public"],"summary":"Request Reactivation","description":"Unified quote-reactivation request (DR7) — the confirm page's\npost-submit button. Fires the same admin notification + event shape as\nthe expired-quote page CTA.","operationId":"request_reactivation_api_v1_followups_public_reactivate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReactivateSubmit"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Request Reactivation Api V1 Followups Public Reactivate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/followups/public/preferences":{"get":{"tags":["followups-public"],"summary":"Preferences Context","description":"Context for the preferences landing page. READ ONLY.","operationId":"preferences_context_api_v1_followups_public_preferences_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferencesContext"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/followups/public/unsubscribe":{"post":{"tags":["followups-public"],"summary":"Submit Unsubscribe","description":"Opt-out action from the preferences page (POST — scanner-safe).","operationId":"submit_unsubscribe_api_v1_followups_public_unsubscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeSubmit"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Submit Unsubscribe Api V1 Followups Public Unsubscribe Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/followups/public/one-click-unsubscribe":{"post":{"tags":["followups-public"],"summary":"One Click Unsubscribe","description":"RFC 8058 ``List-Unsubscribe-Post`` target. Mail clients POST here\nwith no body we can rely on — the token rides the URL. Suppresses ALL\nlifecycle categories (one-click intent is \"stop emailing me\", not a\npreference dialog).","operationId":"one_click_unsubscribe_api_v1_followups_public_one_click_unsubscribe_post","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response One Click Unsubscribe Api V1 Followups Public One Click Unsubscribe Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/":{"get":{"tags":["admin-followups"],"summary":"List Followups","operationId":"list_followups_api_v1_admin_followups__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"tab","in":"query","required":false,"schema":{"type":"string","description":"due|scheduled|sent|suppressed|failed","default":"due","title":"Tab"},"description":"due|scheduled|sent|suppressed|failed"},{"name":"rule","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by rule slug","title":"Rule"},"description":"Filter by rule slug"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Customer name/email/company","title":"Search"},"description":"Customer name/email/company"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Scope to one project (project detail panel)","title":"Project Id"},"description":"Scope to one project (project detail panel)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_FollowupTaskListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/stats":{"get":{"tags":["admin-followups"],"summary":"Followup Stats","operationId":"followup_stats_api_v1_admin_followups_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupStats"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/followups/rules":{"get":{"tags":["admin-followups"],"summary":"List Rules","description":"Rules are code-defined (D7); only the per-rule mode is DB-backed.","operationId":"list_rules_api_v1_admin_followups_rules_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RuleInfo"},"type":"array","title":"Response List Rules Api V1 Admin Followups Rules Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"patch":{"tags":["admin-followups"],"summary":"Update Rule Modes","operationId":"update_rule_modes_api_v1_admin_followups_rules_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleModesUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RuleInfo"},"type":"array","title":"Response Update Rule Modes Api V1 Admin Followups Rules Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/followups/evaluate":{"post":{"tags":["admin-followups"],"summary":"Trigger Evaluation","description":"Manual evaluator pass (staging/debugging). Same phases as the cron.","operationId":"trigger_evaluation_api_v1_admin_followups_evaluate_post","responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Trigger Evaluation Api V1 Admin Followups Evaluate Post"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/followups/{task_id}":{"get":{"tags":["admin-followups"],"summary":"Get Followup","operationId":"get_followup_api_v1_admin_followups__task_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupTaskDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/email-preview":{"get":{"tags":["admin-followups"],"summary":"Followup Email Preview","description":"Render the task's email exactly as a send would (drawer preview).","operationId":"followup_email_preview_api_v1_admin_followups__task_id__email_preview_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupEmailPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/email":{"put":{"tags":["admin-followups"],"summary":"Save Followup Email","description":"Store an admin-edited subject/HTML pair (WYSIWYG editor save).","operationId":"save_followup_email_api_v1_admin_followups__task_id__email_put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupEmailOverrideRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupEmailPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-followups"],"summary":"Reset Followup Email","description":"Drop the stored edit and return to the template render.","operationId":"reset_followup_email_api_v1_admin_followups__task_id__email_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowupEmailPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/send":{"post":{"tags":["admin-followups"],"summary":"Send Followup","description":"Send now — through the FULL gate (CAS claim, re-validation,\nsuppression, caps). A double-click loses the claim and reports it.","operationId":"send_followup_api_v1_admin_followups__task_id__send_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"override_caps","in":"query","required":false,"schema":{"type":"boolean","description":"Explicit admin confirm to bypass frequency caps","default":false,"title":"Override Caps"},"description":"Explicit admin confirm to bypass frequency caps"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResultResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/snooze":{"post":{"tags":["admin-followups"],"summary":"Snooze Followup","operationId":"snooze_followup_api_v1_admin_followups__task_id__snooze_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnoozeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Snooze Followup Api V1 Admin Followups  Task Id  Snooze Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/skip":{"post":{"tags":["admin-followups"],"summary":"Skip Followup","operationId":"skip_followup_api_v1_admin_followups__task_id__skip_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkipRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Skip Followup Api V1 Admin Followups  Task Id  Skip Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/{task_id}/retry":{"post":{"tags":["admin-followups"],"summary":"Retry Followup","description":"One-click retry from the Failed state (re-queues as due).","operationId":"retry_followup_api_v1_admin_followups__task_id__retry_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Retry Followup Api V1 Admin Followups  Task Id  Retry Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/manual-contact":{"post":{"tags":["admin-followups"],"summary":"Log Manual Contact","operationId":"log_manual_contact_api_v1_admin_followups_manual_contact_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualContactRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Log Manual Contact Api V1 Admin Followups Manual Contact Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/followups/quotes/{quote_id}/loss-reason":{"post":{"tags":["admin-followups"],"summary":"Set Loss Reason","description":"Admin manual loss-reason entry — the one path allowed to overwrite.","operationId":"set_loss_reason_api_v1_admin_followups_quotes__quote_id__loss_reason_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLossReasonRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Set Loss Reason Api V1 Admin Followups Quotes  Quote Id  Loss Reason Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/customers/{user_id}/suppress":{"post":{"tags":["admin-customers"],"summary":"Suppress Customer","operationId":"suppress_customer_api_v1_admin_customers__user_id__suppress_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Suppress Customer Api V1 Admin Customers  User Id  Suppress Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/customers/suppressions/{suppression_id}":{"delete":{"tags":["admin-customers"],"summary":"Deactivate Suppression","operationId":"deactivate_suppression_api_v1_admin_customers_suppressions__suppression_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"suppression_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Suppression Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Deactivate Suppression Api V1 Admin Customers Suppressions  Suppression Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/customers/external":{"get":{"tags":["admin-customers"],"summary":"List External Customers","description":"Override (\"external\") customers — ordered for via a platform broker.","operationId":"list_external_customers_api_v1_admin_customers_external_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ExternalCustomerListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/customers/external/{external_id}":{"get":{"tags":["admin-customers"],"summary":"Get External Customer","operationId":"get_external_customer_api_v1_admin_customers_external__external_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"External Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalCustomerDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/customers/{user_id}":{"get":{"tags":["admin-customers"],"summary":"Get Customer","operationId":"get_customer_api_v1_admin_customers__user_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/gmail/inbound":{"post":{"tags":["webhooks"],"summary":"Gmail Inbound Webhook","description":"Receive a Gmail Pub/Sub push notification.\n\nVerifies the OIDC JWT, decodes the envelope, schedules background\nprocessing, and returns 204 immediately. See module docstring for\nthe full flow.","operationId":"gmail_inbound_webhook_webhooks_gmail_inbound_post","responses":{"204":{"description":"Successful Response"}}}},"/webhooks/anthropic/session-status":{"post":{"tags":["webhooks"],"summary":"Anthropic Session Status Webhook","description":"Handle an Anthropic Managed Agents session-status webhook event.\n\nReads the raw request body for signature verification.\nReturns 200 on success (including ignored/unknown events),\n400 on an invalid or stale signature.","operationId":"anthropic_session_status_webhook_webhooks_anthropic_session_status_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/waitlist/join":{"post":{"tags":["waitlist"],"summary":"Join Waitlist","description":"Submit a waitlist application.\n\nRate-limited to **5 requests per minute** per IP.\n\nHoneypot field: if ``honeypot`` is filled, the request is silently accepted\n(HTTP 200) but nothing is persisted — bots see success, humans never fill it.","operationId":"join_waitlist_api_v1_waitlist_join_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistJoinRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistJoinResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/waitlist/invite/{token}":{"get":{"tags":["waitlist"],"summary":"Validate Invite","description":"Validate a waitlist invite token.\n\nReturns the associated email and name when the token is valid and\nnot expired, enabling the frontend registration form to pre-populate\nfields.","operationId":"validate_invite_api_v1_waitlist_invite__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteValidationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/features":{"get":{"tags":["features"],"summary":"Get Part Features","description":"Get detected features for a part's latest CAD version.\n\nPhase 6C: features are filtered by the part's machining process\n(via ``canonical_process`` bucket) so sheet-metal parts don't show\nCNC threads, CNC parts don't show bends, etc. If the part has no\nprocess selected (NULL ``machining_process_id``) or the process\nslug is unknown, the filter is a no-op and all features are\nreturned. Admins can force the unfiltered list via ``?unfiltered=true``.","operationId":"get_part_features_api_v1_parts__part_id__features_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"unfiltered","in":"query","required":false,"schema":{"type":"boolean","description":"Escape hatch for debugging. When true, returns ALL detected features including those irrelevant to the part's machining process. Available to any authenticated owner of the part — the data returned is data the user already owns; the flag just disables the process-aware filter.","default":false,"title":"Unfiltered"},"description":"Escape hatch for debugging. When true, returns ALL detected features including those irrelevant to the part's machining process. Available to any authenticated owner of the part — the data returned is data the user already owns; the flag just disables the process-aware filter."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/features/{feature_id}/correct":{"post":{"tags":["features"],"summary":"Correct Feature","description":"Phase 0: record a user correction on a single feature card.\n\nThree actions:\n  - **confirm**: ✓ \"yes this is correctly detected\" — positive\n    training signal, no DFM impact.\n  - **dismiss**: ✗ \"this isn't a feature\" — marks feature\n    ``not_a_feature=True``, DFM rules skip it.\n  - **reclassify**: ⇄ \"wrong class\" — sets feature ``type`` to\n    ``new_class`` (must be a ``FeatureClass`` taxonomy value).\n\nThe correction is stored as an OutcomeEvent with the feature's\n``geometry_fingerprint`` in the data payload — that's what makes\ncorrections survive re-uploads. ``source`` is automatically set\nto ``admin_label`` if the calling user has an ``AdminProfile``,\nelse ``user_correction``.\n\nAfter persisting, immediately replays *all* Phase 0 corrections\nfor this part across all versions and routes the resulting DFM\nre-evaluation through ``PartSpecsChokepoint`` (so analysis_status\ntransitions correctly + SSE events fire on failure).","operationId":"correct_feature_api_v1_parts__part_id__features__feature_id__correct_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","title":"Feature Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureCorrectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureCorrectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/admin/labeled-features":{"get":{"tags":["features"],"summary":"Export Labeled Features","description":"Phase 0: emit the labeled-features dataset for ML training / regression.\n\nJoins ``feature_confirm`` + ``feature_reclassification`` events\nagainst the matching detected_features to produce one row per\nlabeled example. Admin-only — the dataset is the canonical training\nsource for Phase 1+ ML work.","operationId":"export_labeled_features_api_v1_parts_admin_labeled_features_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":10000,"minimum":1},{"type":"null"}],"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LabeledDatasetRow"},"title":"Response Export Labeled Features Api V1 Parts Admin Labeled Features Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/ai-synthesis":{"post":{"tags":["dfm"],"summary":"Trigger Ai Synthesis","description":"Trigger AI DFM synthesis for a part (user-facing).\n\nKicks off the Temporal AI synthesis workflow asynchronously and returns\nimmediately. The frontend polls via the version query to pick up results.\nThis avoids HTTP timeout issues with the ~18s Claude API call.","operationId":"trigger_ai_synthesis_api_v1_parts__part_id__ai_synthesis_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Trigger Ai Synthesis Api V1 Parts  Part Id  Ai Synthesis Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/dfm-check":{"post":{"tags":["dfm"],"summary":"Run Dfm Check","description":"Run DFM rules + cost/lead time estimation for the user's own part.\n\nDeterministic: no Claude API calls. Runs in ~50-200ms.\n\nWhen ``preview=true``, only the cost and lead-time calculators are run\nand no DB write happens. Used for live preview while editing specs.\n\nAuth: requires the JWT user to own the part's parent project. Admins\nuse the parallel endpoint ``POST /admin/parts/{part_id}/dfm-check``\nwhich skips the ownership check.","operationId":"run_dfm_check_api_v1_parts__part_id__dfm_check_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"preview","in":"query","required":false,"schema":{"type":"boolean","description":"Cost/lead-time preview only","default":false,"title":"Preview"},"description":"Cost/lead-time preview only"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DfmCheckRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DfmCheckResponse"},{"$ref":"#/components/schemas/CostPreviewResponse"}],"title":"Response Run Dfm Check Api V1 Parts  Part Id  Dfm Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/dfm-highlights":{"get":{"tags":["dfm"],"summary":"Get Dfm Highlights","description":"Return cached highlight overlay from the last DFM check.\n\nReads process_dfm_results.highlight_overlay from the latest CadFileVersion.\nReturns an empty list if no DFM check has been run yet.","operationId":"get_dfm_highlights_api_v1_parts__part_id__dfm_highlights_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DfmHighlightsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/outcome-events":{"get":{"tags":["outcome-events"],"summary":"List Outcome Events","description":"List outcome events for a part, optionally filtered by source or type.","operationId":"list_outcome_events_api_v1_parts__part_id__outcome_events_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"outcome_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome Type"}},{"name":"version_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Version Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Outcome Events Api V1 Parts  Part Id  Outcome Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["outcome-events"],"summary":"Create Correction","description":"Submit a user correction for a detected feature.\n\nCreates an OutcomeEvent with source='user_correction'. If the part has\ncomplete manufacturing specs and the correction can affect quoting\ninputs, deterministic DFM/pricing is re-run through the part-spec\nchokepoint.","operationId":"create_correction_api_v1_parts__part_id__outcome_events_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrectionCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrectionWithDfmResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/corrections/batch":{"post":{"tags":["outcome-events"],"summary":"Create Batch Corrections","description":"Apply the same correction to multiple features at once.\n\nCreates one OutcomeEvent per feature_id, all sharing the same\ncorrection_type, data payload, and label. Quote-impacting batch\ncorrections trigger one deterministic DFM/pricing recompute after the\nbatch commit.","operationId":"create_batch_corrections_api_v1_parts__part_id__corrections_batch_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCorrectionCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCorrectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/recommendation-feedback":{"post":{"tags":["outcome-events"],"summary":"Submit Recommendation Feedback","description":"Submit user feedback on an AI recommendation (helpful or flagged).\n\nCreates an OutcomeEvent with source='user_feedback'. Does NOT trigger\nDFM re-scoring — this is purely feedback collection for prompt tuning.","operationId":"submit_recommendation_feedback_api_v1_parts__part_id__recommendation_feedback_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationFeedbackCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationFeedbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/outcome-events/{event_id}/confirm":{"post":{"tags":["outcome-events"],"summary":"Confirm Outcome Event","description":"Confirm a draft outcome event.\n\nTransitions draft -> confirmed. Also creates a ViewerCallout pinned to\nthe feature (if feature_id is present).","operationId":"confirm_outcome_event_api_v1_parts_outcome_events__event_id__confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Confirm Outcome Event Api V1 Parts Outcome Events  Event Id  Confirm Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/outcome-events/{event_id}/undo":{"post":{"tags":["outcome-events"],"summary":"Undo Outcome Event","description":"Undo a confirmed outcome event within the 10-minute window.\n\nTransitions confirmed -> undone. Also dismisses the linked ViewerCallout\nif one was created during confirm.","operationId":"undo_outcome_event_api_v1_parts_outcome_events__event_id__undo_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Undo Outcome Event Api V1 Parts Outcome Events  Event Id  Undo Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/versions/{version_id}/events":{"get":{"tags":["analysis-events"],"summary":"Analysis Events","description":"Stream analysis status events for a specific CAD version.\n\n**Auth:** Accepts JWT as a ``token`` query parameter because the browser's\n``EventSource`` API cannot set custom headers. The token is validated the\nsame way as ``Authorization: Bearer <token>`` on other endpoints.\n\nEvents:\n\n- ``dfm_complete``: DFM rule evaluation finished\n- ``ai_started``: AI synthesis Claude call started\n- ``ai_progress``: Partial AI result available (grade, section)\n- ``ai_complete``: Full AI synthesis committed to DB\n- ``error``: Analysis failed\n- ``cancelled``: Workflow cancelled (spec change)\n- ``ping``: Heartbeat (every 15s)\n\nThe stream closes automatically after a terminal event (``ai_complete``,\n``error``, ``cancelled``) or after 5 minutes of inactivity.","operationId":"analysis_events_api_v1_parts__part_id__versions__version_id__events_get","parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}},{"name":"token","in":"query","required":true,"schema":{"type":"string","description":"JWT token (EventSource cannot set headers)","title":"Token"},"description":"JWT token (EventSource cannot set headers)"},{"name":"after_seq","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Replay durable milestone events with a greater sequence.","title":"After Seq"},"description":"Replay durable milestone events with a greater sequence."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ollie/projects/{project_id}/conversation":{"get":{"tags":["ollie"],"summary":"Get Conversation","description":"Load paginated conversation messages for a project.\n\nThe newest page (no cursor) returns the most recent ``limit`` messages\nin chronological order; ``has_more`` signals older messages exist beyond\nthe window. Subsequent pages pass ``before_id`` to walk backwards.\n\nOrdering keys off ``(created_at, id)`` both for the windowing SQL and\nthe cursor comparison (eng-review #4c — deterministic under equal\ntimestamps).","operationId":"get_conversation_api_v1_ollie_projects__project_id__conversation_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"before_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Fetch messages older than this message id","title":"Before Id"},"description":"Fetch messages older than this message id"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConversationPageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ollie/projects/{project_id}/insights":{"get":{"tags":["ollie"],"summary":"Get Insights","description":"Return deterministic Ollie insight candidates for the current scope.","operationId":"get_insights_api_v1_ollie_projects__project_id__insights_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional part scope.","title":"Part Id"},"description":"Optional part scope."},{"name":"feature_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional selected feature scope.","title":"Feature Id"},"description":"Optional selected feature scope."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OllieInsightsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ollie/preferences":{"get":{"tags":["ollie"],"summary":"Get Preferences","description":"Return the authenticated user's Ollie preferences (auto-created on first call).","operationId":"get_preferences_api_v1_ollie_preferences_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPreferencesResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"patch":{"tags":["ollie"],"summary":"Patch Preferences","description":"Update Ollie preferences; only provided fields mutate.","operationId":"patch_preferences_api_v1_ollie_preferences_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPreferencesUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPreferencesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/ollie/projects/{project_id}/messages":{"post":{"tags":["ollie"],"summary":"Send Message","description":"Send one turn; stream ``StreamChunk`` events back via SSE.\n\nThe response body is a ``text/event-stream`` matching the agent's\ncanonical event sequence: ``ollie_thinking_start`` → ``ollie_message_chunk``\n(repeated) → ``ollie_thinking_end`` → ``ollie_message_complete`` (or\n``ollie_error``).\n\nCancellation: when the client disconnects, ``request.is_disconnected()``\nflips to ``True`` inside the generator and we break out of the loop.\nThe agent's Phase 1D cancellation path persists a partial ``[truncated]``\nturn via a background task spawned on the running loop.","operationId":"send_message_api_v1_ollie_projects__project_id__messages_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OllieTurnRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ollie/projects/{project_id}/interview/start":{"post":{"tags":["ollie"],"summary":"Start Interview","description":"Open the design intent interview for a part.\n\nThis synthesises a system-shaped user message (\"[SYSTEM: Start the design\nintent interview ...]\") and streams the agent turn via SSE. The frontend\ncalls this when the intent panel opens with an active part whose\ninterview_status is ``not_started`` / ``in_progress`` /\n``carry_forward_pending``.\n\nIdempotency: if the current interview_status is ``in_progress``,\n``completed``, or ``skipped``, we still kick off a turn (so the user can\ncontinue or re-open the conversation) but we only inject the synthetic\nstarter when status is ``not_started`` — callers repeating the request\nmid-interview won't double-seed the conversation with a fresh\n\"[SYSTEM: Start the ...]\" nudge.","operationId":"start_interview_api_v1_ollie_projects__project_id__interview_start_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterviewStartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ollie/messages/{message_id}/feedback":{"patch":{"tags":["ollie"],"summary":"Patch Message Feedback","description":"Set thumbs up/down feedback on an Ollie message.\n\nOwnership is validated by joining ``agent_conversation_messages →\nagent_conversations → projects`` — the user must own the project the\nmessage belongs to. Cross-user PATCH → 404 (collapsed with\nnot-found to avoid probing).","operationId":"patch_message_feedback_api_v1_ollie_messages__message_id__feedback_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFeedbackPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConversationMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/design-intents/parts/{part_id}/current":{"get":{"tags":["design-intents"],"summary":"Get Current","description":"Return the DesignIntent for the part's latest CadFileVersion.\n\n404 if the part doesn't exist / isn't owned, or if the intent row hasn't\nbeen ensured yet (e.g. CAD pipeline hasn't reached finalize).","operationId":"get_current_api_v1_design_intents_parts__part_id__current_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/design-intents/parts/{part_id}/ensure":{"post":{"tags":["design-intents"],"summary":"Ensure Intent","description":"Idempotently create the intent for the part's latest version.\n\nPrimary ensure runs server-side in finalize.py. This endpoint is the\nfrontend's defensive fallback — cheap to call, safe to retry, no-op when\nthe row already exists.","operationId":"ensure_intent_api_v1_design_intents_parts__part_id__ensure_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/design-intents/{intent_id}":{"patch":{"tags":["design-intents"],"summary":"Patch Intent","description":"Apply a user PATCH (inline chip edit). Promotes edits to ``user_asserted``.\n\nOwnership verification happens inside the service via the part->project->\nuser_id join. 403 if the user doesn't own the intent, 404 if the intent\ndoesn't exist.","operationId":"patch_intent_api_v1_design_intents__intent_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Intent Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignIntentPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/design-intents/{intent_id}/skip":{"post":{"tags":["design-intents"],"summary":"Skip Intent","description":"User dismisses the nudge via the panel skip button.\n\nSets ``nudge_dismissed_at=now`` AND flips ``interview_status=skipped``\n(this endpoint is the 'skip interview and quiet the nudge' path used by\nthe UI — agents flip status directly via ``mark_skipped`` in 3B).","operationId":"skip_intent_api_v1_design_intents__intent_id__skip_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/design-intents/projects/{project_id}/summary":{"get":{"tags":["design-intents"],"summary":"Get Project Summary","description":"Aggregate intent status across a project's parts.\n\nDrives the combined Ollie badge (``pending_count``). Returns a zero-filled\nsummary if the project has zero parts.","operationId":"get_project_summary_api_v1_design_intents_projects__project_id__summary_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectIntentSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/manufacturing-intents/projects/{project_id}":{"get":{"tags":["manufacturing-intents"],"summary":"List Project Intents","operationId":"list_project_intents_api_v1_manufacturing_intents_projects__project_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"enum":["project","part","feature","drawing"],"type":"string"},{"type":"null"}],"title":"Scope"}},{"name":"part_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"}},{"name":"feature_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Feature Id"}},{"name":"intent_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Intent Type"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"enum":["active","retracted","superseded"],"type":"string"},{"type":"null"}],"title":"State"}},{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Include Inactive"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/manufacturing-intents/projects/{project_id}/confirm":{"post":{"tags":["manufacturing-intents"],"summary":"Confirm Project Intent","operationId":"confirm_project_intent_api_v1_manufacturing_intents_projects__project_id__confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentConfirmRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/manufacturing-intents/{event_id}/retract":{"post":{"tags":["manufacturing-intents"],"summary":"Retract Intent","operationId":"retract_intent_api_v1_manufacturing_intents__event_id__retract_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ManufacturingIntentRetractRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/manufacturing-intents/{event_id}/supersede":{"post":{"tags":["manufacturing-intents"],"summary":"Supersede Intent","operationId":"supersede_intent_api_v1_manufacturing_intents__event_id__supersede_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentSupersedeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingIntentRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/cad-versions/{version_id}":{"get":{"tags":["viewer-callouts"],"summary":"List Callouts For Version","description":"List active + acknowledged callouts for a CAD version.","operationId":"list_callouts_for_version_api_v1_viewer_callouts_cad_versions__version_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ViewerCalloutRead"},"title":"Response List Callouts For Version Api V1 Viewer Callouts Cad Versions  Version Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/{callout_id}":{"patch":{"tags":["viewer-callouts"],"summary":"Patch Callout State","description":"Acknowledge or dismiss a callout.","operationId":"patch_callout_state_api_v1_viewer_callouts__callout_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"callout_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Callout Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/projects/{project_id}/review-summary":{"get":{"tags":["viewer-callouts"],"summary":"Project Review Summary","description":"Return per-part reviewable-callout counts for a project.\n\nDrives the Ollie sidebar CTA that routes the user into the guided\nreview flow for the first part with pending items.","operationId":"project_review_summary_api_v1_viewer_callouts_projects__project_id__review_summary_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectReviewSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/{callout_id}/ingest-answer":{"post":{"tags":["viewer-callouts"],"summary":"Answer Ingest Question","description":"Answer an ingest_question. 'threaded' routes through the corrections\npath (feature_reclassification) and re-runs DFM + pricing — the answer\nvisibly changes the quote (AI-native ingest).","operationId":"answer_ingest_question_api_v1_viewer_callouts__callout_id__ingest_answer_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"callout_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Callout Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutAnswerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/{callout_id}/skip":{"post":{"tags":["viewer-callouts"],"summary":"Skip Ingest Question","description":"Skip an ingest_question — dismisses it and records the default\nassumption as a visible ingest_assumption OutcomeEvent (flippable\nlater). Never a silent commitment.","operationId":"skip_ingest_question_api_v1_viewer_callouts__callout_id__skip_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"callout_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Callout Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/viewer-callouts/{callout_id}/answer":{"post":{"tags":["viewer-callouts"],"summary":"Answer Intent Question","description":"Answer an intent_question callout from the 3D pin popover.","operationId":"answer_intent_question_api_v1_viewer_callouts__callout_id__answer_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"callout_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Callout Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutAnswerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewerCalloutRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/welds":{"post":{"tags":["welds"],"summary":"Create Weld","description":"Create a weld annotation on a part's latest CAD version.","operationId":"create_weld_api_v1_parts__part_id__welds_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeldCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeldRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["welds"],"summary":"List Welds","description":"List non-undone welds for a part, each carrying an\n``is_process_mismatch`` flag (TRUE when the part's process has\ndrifted to a bucket that no longer supports weld annotations).","operationId":"list_welds_api_v1_parts__part_id__welds_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeldRead"},"title":"Response List Welds Api V1 Parts  Part Id  Welds Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/welds/{weld_id}":{"patch":{"tags":["welds"],"summary":"Update Weld","description":"Patch a weld's type/size/process/side/notes. Re-applies enum +\neditable-status validation.","operationId":"update_weld_api_v1_welds__weld_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"weld_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Weld Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeldUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeldRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["welds"],"summary":"Delete Weld","description":"Soft-delete a weld by flipping its state to ``undone``.","operationId":"delete_weld_api_v1_welds__weld_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"weld_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Weld Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/surface-finishes":{"post":{"tags":["surface_finishes"],"summary":"Create Surface Finish","description":"Create (or replace) a surface-finish annotation on a part's latest CAD version.\n\nRe-authoring on a face that already has a live finish flips the\nexisting row to ``state=\"undone\"`` and inserts the replacement —\nFusion-360 muscle memory: re-clicking a finished face updates, it\ndoes not duplicate.","operationId":"create_surface_finish_api_v1_parts__part_id__surface_finishes_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurfaceFinishCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurfaceFinishRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["surface_finishes"],"summary":"List Surface Finishes","description":"List non-undone surface finishes for a part.\n\nEach entry carries an ``is_process_mismatch`` flag (False under\ncurrent applicability — finishes apply to every canonical bucket —\nbut surfaced defensively for future-proofing).","operationId":"list_surface_finishes_api_v1_parts__part_id__surface_finishes_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SurfaceFinishRead"},"title":"Response List Surface Finishes Api V1 Parts  Part Id  Surface Finishes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/surface-finishes/{finish_id}":{"patch":{"tags":["surface_finishes"],"summary":"Update Surface Finish","description":"Patch a finish's type / Ra / color / notes.\n\nRe-applies enum + editable-status validation.","operationId":"update_surface_finish_api_v1_surface_finishes__finish_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"finish_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Finish Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurfaceFinishUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurfaceFinishRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["surface_finishes"],"summary":"Delete Surface Finish","description":"Soft-delete a finish by flipping its state to ``undone``.","operationId":"delete_surface_finish_api_v1_surface_finishes__finish_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"finish_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Finish Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/edge-tolerances":{"post":{"tags":["edge_tolerances"],"summary":"Create Edge Tolerance","description":"Create (or replace) an edge-tolerance annotation on a part's latest CAD version.\n\nRe-authoring on an edge that already has a live tolerance flips the\nexisting row to ``state=\"undone\"`` and inserts the replacement —\nFusion-360 muscle memory: re-clicking an edge updates, it does not\nduplicate.","operationId":"create_edge_tolerance_api_v1_parts__part_id__edge_tolerances_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeToleranceCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeToleranceRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["edge_tolerances"],"summary":"List Edge Tolerances","description":"List non-undone edge tolerances for a part.\n\nEach entry carries an ``is_process_mismatch`` flag (True when the\npart's process bucket no longer supports edge tolerances).","operationId":"list_edge_tolerances_api_v1_parts__part_id__edge_tolerances_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EdgeToleranceRead"},"title":"Response List Edge Tolerances Api V1 Parts  Part Id  Edge Tolerances Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge-tolerances/{tolerance_id}":{"patch":{"tags":["edge_tolerances"],"summary":"Update Edge Tolerance","description":"Patch a tolerance's type / size / angle / notes.","operationId":"update_edge_tolerance_api_v1_edge_tolerances__tolerance_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"tolerance_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tolerance Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeToleranceUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeToleranceRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["edge_tolerances"],"summary":"Delete Edge Tolerance","description":"Soft-delete a tolerance by flipping its state to ``undone``.","operationId":"delete_edge_tolerance_api_v1_edge_tolerances__tolerance_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"tolerance_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tolerance Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/coating-masks":{"post":{"tags":["part_annotations"],"summary":"Create Coating Mask","description":"Create a coating mask on a face (exclude from part-level coating).\n\nRejects with 422 if the part has no ``coating_id`` set.","operationId":"create_coating_mask_api_v1_parts__part_id__coating_masks_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoatingMaskCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoatingMaskRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["part_annotations"],"summary":"List Coating Masks","description":"List active coating masks for a part.","operationId":"list_coating_masks_api_v1_parts__part_id__coating_masks_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CoatingMaskRead"},"title":"Response List Coating Masks Api V1 Parts  Part Id  Coating Masks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/coating-masks/{event_id}":{"delete":{"tags":["part_annotations"],"summary":"Delete Coating Mask","description":"Soft-delete a coating mask.","operationId":"delete_coating_mask_api_v1_parts__part_id__coating_masks__event_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/edge-notes":{"post":{"tags":["part_annotations"],"summary":"Create Edge Note","description":"Add a manufacturing note to an edge.","operationId":"create_edge_note_api_v1_parts__part_id__edge_notes_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeNoteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeNoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["part_annotations"],"summary":"List Edge Notes","description":"List active edge notes for a part.","operationId":"list_edge_notes_api_v1_parts__part_id__edge_notes_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EdgeNoteRead"},"title":"Response List Edge Notes Api V1 Parts  Part Id  Edge Notes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/edge-notes/{event_id}":{"delete":{"tags":["part_annotations"],"summary":"Delete Edge Note","description":"Soft-delete an edge note.","operationId":"delete_edge_note_api_v1_parts__part_id__edge_notes__event_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"event_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Event Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parts/{part_id}/critical-surfaces":{"post":{"tags":["part_annotations"],"summary":"Create Critical Surface","description":"Mark or un-mark a face as critical.\n\nWhen ``is_critical=false`` and an existing designation exists, the\ndesignation is soft-deleted and a 204 is returned.","operationId":"create_critical_surface_api_v1_parts__part_id__critical_surfaces_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CriticalSurfaceCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CriticalSurfaceRead"},{"type":"null"}],"title":"Response Create Critical Surface Api V1 Parts  Part Id  Critical Surfaces Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["part_annotations"],"summary":"List Critical Surfaces","description":"List faces marked as critical for a part.","operationId":"list_critical_surfaces_api_v1_parts__part_id__critical_surfaces_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CriticalSurfaceRead"},"title":"Response List Critical Surfaces Api V1 Parts  Part Id  Critical Surfaces Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/dashboard/":{"get":{"tags":["admin-dashboard"],"summary":"Get Dashboard Stats","description":"Return aggregate dashboard statistics for the admin panel.\n\nRequires any authenticated admin (no specific permission check).","operationId":"get_dashboard_stats_api_v1_admin_dashboard__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardStats"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/projects/":{"get":{"tags":["admin-projects"],"summary":"List Projects","description":"List all projects with pagination, status filtering, and search.","operationId":"list_projects_api_v1_admin_projects__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by project status","title":"Status"},"description":"Filter by project status"},{"name":"internal_status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by admin-only internal project status. Use 'unset' for no status.","title":"Internal Status"},"description":"Filter by admin-only internal project status. Use 'unset' for no status."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by project name or user email","title":"Search"},"description":"Search by project name or user email"},{"name":"sort_by","in":"query","required":false,"schema":{"enum":["created_at","updated_at","name","status","internal_status","priority","target_delivery_date"],"type":"string","description":"Sort field","default":"created_at","title":"Sort By"},"description":"Sort field"},{"name":"sort_order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"Sort order","default":"desc","title":"Sort Order"},"description":"Sort order"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminProjectListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}":{"get":{"tags":["admin-projects"],"summary":"Get Project Detail","description":"Get full project detail with user info, parts, quotes, and comments.","operationId":"get_project_detail_api_v1_admin_projects__project_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-projects"],"summary":"Hard Delete Project","description":"Permanently delete a project and all associated data including R2 files.","operationId":"hard_delete_project_api_v1_admin_projects__project_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/status":{"patch":{"tags":["admin-projects"],"summary":"Update Project Status","description":"Transition a project's status with validation and audit logging.","operationId":"update_project_status_api_v1_admin_projects__project_id__status_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectStatusUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/force-status":{"patch":{"tags":["admin-projects"],"summary":"Force Set Project Status","description":"Manual status override — set a project to ANY status.\n\nBypasses the lifecycle state machine (``VALID_TRANSITIONS``); the\nescape hatch for skip-ahead, backward, and unstick operations the\ncanonical transition buttons can't express. Requires a reason\n(≥5 chars) which is recorded under the distinct\n``project_status_force_set`` audit action. Does NOT send the\ncustomer a status-change notification — use the canonical\n``PATCH /{project_id}/status`` path when the customer should know.","operationId":"force_set_project_status_api_v1_admin_projects__project_id__force_status_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectForceStatusUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/internal":{"patch":{"tags":["admin-projects"],"summary":"Update Project Internal State","description":"Update admin-only operational project status/notes.\n\nThis is deliberately separate from the customer-facing status endpoint:\nit does not notify the customer and does not trigger quote, payment,\nDFM, or pricing side effects.","operationId":"update_project_internal_state_api_v1_admin_projects__project_id__internal_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectInternalUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectInternalStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/bulk-delete":{"post":{"tags":["admin-projects"],"summary":"Bulk Delete Projects","description":"Permanently delete several projects and all their associated data.\n\nPartial success is expected and reported in the body, not via the status\ncode: each project is deleted in its own transaction, so a failure on one\ndoes not roll back the rest. A 200 does NOT mean every project was\ndeleted — callers must inspect ``failed``.\n\nRate limited deliberately: this endpoint has no eligibility guard (it will\ndelete a paid, in-production project) and there is no soft-delete or\nrestore path, so the limit is the remaining blast-radius control.","operationId":"bulk_delete_projects_api_v1_admin_projects_bulk_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectBulkDeleteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectBulkDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/projects/{project_id}/submit-on-behalf":{"post":{"tags":["admin-projects"],"summary":"Submit On Behalf","description":"Advance a DRAFT project to SUBMITTED on behalf of the user.\n\nReplicates the user's own \"Request Quote\" side effects (quote row,\nadmin notification, DRAFT → SUBMITTED transition) plus an audit log\nentry attributing the action to the admin and a user-facing\nnotification so the customer knows their project was submitted by\nour team.\n\nShipping address resolution is described in\n``AdminSubmitOnBehalfRequest`` — at most one of the two fields may\nbe set, and if neither is set the project must already have an\naddress linked.","operationId":"submit_on_behalf_api_v1_admin_projects__project_id__submit_on_behalf_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSubmitOnBehalfRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProjectDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/user-shipping-addresses":{"get":{"tags":["admin-projects"],"summary":"List Project User Shipping Addresses","description":"Return the saved shipping addresses belonging to this project's user.\n\nScoped via ``project_id`` so the URL pattern stays consistent with\nthe rest of the admin project routes. Used by the Submit-on-Behalf\nmodal's \"pick an existing address\" radio list.","operationId":"list_project_user_shipping_addresses_api_v1_admin_projects__project_id__user_shipping_addresses_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShippingAddressResponse"},"title":"Response List Project User Shipping Addresses Api V1 Admin Projects  Project Id  User Shipping Addresses Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/po-document":{"post":{"tags":["admin-projects"],"summary":"Admin Upload Po Document","description":"Stream an admin-on-behalf PO document to R2 (firewall-safe upload proxy).\n\nReplaces the browser's direct PUT to ``*.r2.cloudflarestorage.com``.\nThe admin POSTs the file as ``multipart/form-data``; the API streams\nit straight to R2 and returns the ``r2_key``. The admin passes that\nkey back as ``po_document_r2_key`` on ``POST /upload-po-on-behalf``.\n\nThe R2 key is namespaced under the **project's user_id** (not the\nadmin's id) so the user-side download path + permissions continue to\nwork identically — locked decision #7. The admin's role is solely to\nperform the upload; the artifact still lives in the customer's\nnamespace.","operationId":"admin_upload_po_document_api_v1_admin_projects__project_id__po_document_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_upload_po_document_api_v1_admin_projects__project_id__po_document_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/POUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/po-document-extractions/{extraction_id}":{"get":{"tags":["admin-projects"],"summary":"Get Admin Po Document Extraction","description":"Return extraction payload for an admin-visible PO document.","operationId":"get_admin_po_document_extraction_api_v1_admin_projects__project_id__po_document_extractions__extraction_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"extraction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Extraction Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommercialDocumentExtractionReview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/upload-po-on-behalf":{"post":{"tags":["admin-projects"],"summary":"Upload Po On Behalf","description":"Submit a PO on the user's behalf for a QUOTED/APPROVED project.\n\nMirrors the user-side ``POST /payments/purchase-order`` side effects\nvia the shared ``PaymentService._submit_purchase_order_internal``\nhelper. Adds the admin attribution column on the Payment row, fires\na user-facing in-app notification (no email), reuses the existing\n``PO_SUBMITTED`` admin notification fan-out, and writes an audit log\nentry tagged ``po_uploaded_by_admin``.\n\nReturns the fully-populated payment detail response with a presigned\nPO download URL — same shape the admin payment detail endpoint\nreturns so the frontend can render without a follow-up GET.","operationId":"upload_po_on_behalf_api_v1_admin_projects__project_id__upload_po_on_behalf_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUploadPOOnBehalfRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/payment":{"post":{"tags":["admin-projects"],"summary":"Create Payment On Behalf","description":"Create a payment record for a project that has none.\n\nThe Payment-panel escape hatch for **force-advanced projects**: the\nforce-status override only mutates ``Project.status`` — it never\ncreates a ``payments`` row, so the panel is stuck in a dead \"pending\"\nstate and every payment action 404s. This attaches a payment so the\nnormal panel (attach PO / issue invoice / mark paid) lights up.\n\n**Reconciliation override:** no approved-quote requirement. The admin\nrecords the out-of-band settlement ``amount`` directly (the editable\nfield defaults to the latest quote total client-side); the payment is\nlinked to the project's **latest quote of any status** to satisfy the\nnon-null ``quote_id`` FK. A project with no quote at all returns a\n**structured 400** — ``detail={\"code\": \"no_quote\", \"message\": ...}`` —\nso the UI can guide the admin to create/submit a quote first.\n\nCreates a ``manual`` (out-of-band — wire/check/ACH) record supporting\nissue-invoice + mark-invoice-paid; no PO doc, no confirm-PO. The\nentered ``amount`` is stamped verbatim as the settlement total (both\n``amount`` and ``total_with_tax``, no tax breakout). Purchase-order\nrecords are created via the separate ``upload-po-on-behalf`` flow;\n``method`` only accepts ``\"manual\"`` here (the schema 422s anything\nelse).\n\nIdempotent: a project that already has a payment returns **409**.\nAudit-logged as ``payment_created_on_behalf`` with a\n``reconciliation`` marker + the entered amount. Requires\n``payments:create``.","operationId":"create_payment_on_behalf_api_v1_admin_projects__project_id__payment_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentOnBehalfRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-projects"],"summary":"Update Order Placed Override","description":"Set or CLEAR the TRUE order-placed date on a project's payment (D1).\n\nThe edit-anytime correction affordance for on-behalf orders (manual\nreconciliation + upload-PO-on-behalf), where the Payment row was created\nat the admin's *processing* time rather than the real order date. The\nadmin sends a calendar ``order_placed_at`` → stored UTC-noon as\n``Payment.order_placed_at_override``; sending ``null`` **CLEARS** the\noverride so the order-placed clock reverts to the derived created_at /\npaid_at.\n\nBecause ``derive_order_placed_at`` is the single chokepoint, the change\npropagates to every read consumer (admin list/detail, the customer's\nview, the sell-side ETA). Returns the fully-populated payment detail\nresponse (same shape as the detail endpoint). A project with no payment\nrow returns **404**. Requires ``payments:create``.","operationId":"update_order_placed_override_api_v1_admin_projects__project_id__payment_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderPlacedAtRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/parts":{"post":{"tags":["admin-projects"],"summary":"Admin Create Part","description":"Create a part on behalf of the customer in an editable project.","operationId":"admin_create_part_api_v1_admin_projects__project_id__parts_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPartCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/parts/{part_id}":{"patch":{"tags":["admin-projects"],"summary":"Admin Update Part","description":"Admin customer-request edit of qty/process/material/legacy finish.","operationId":"admin_update_part_api_v1_admin_projects__project_id__parts__part_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPartQuantityUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-projects"],"summary":"Admin Delete Part","description":"Delete a part on behalf of the customer in an editable project.","operationId":"admin_delete_part_api_v1_admin_projects__project_id__parts__part_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AdminPartDeleteRequest"},{"type":"null"}],"title":"Data"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/parts/{part_id}/finish":{"patch":{"tags":["admin-projects"],"summary":"Admin Update Part Finish","description":"Admin atomic finish setter — mirrors the user route's behavior.\n\nDecomposes ``finish_dropdown_id`` onto the correct Part column\n(``finishing_id`` for mechanical state, ``coating_id`` for bath\ncoating) and persists ``coating_color`` / ``custom_coating_name`` /\n``coating_spec`` in a single atomic write — same wire shape and\nvalidation as the user-side ``PATCH /projects/{id}/parts/{id}/finish``,\nminus the user_id ownership check.\n\nUsed by the admin \"Submit Project on Behalf\" dialog so the admin\ncan set finishings AND coatings (with colors + specs) on the\ncustomer's parts at parity with the user-side Finish dropdown. The\nlegacy admin part PATCH only writes ``finishing_id`` so it cannot\npersist coatings or colors.\n\nDFM pricing cache is cleared on the latest version so the next\nrender reprices against the new finish. Active reviewed quotes are\nmarked stale so customers cannot approve or pay against old pricing.","operationId":"admin_update_part_finish_api_v1_admin_projects__project_id__parts__part_id__finish_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFinishUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/parts/{part_id}/retrigger-analysis":{"post":{"tags":["admin-projects"],"summary":"Admin Retrigger Part Analysis","description":"Admin force-restart of deterministic DFM/pricing for a part.\n\nMirrors the user-facing ``POST /projects/{id}/parts/{id}/retrigger-analysis``\nbut skips the project-ownership check — admin is allowed to recover\nany stuck part regardless of who owns the project. Used from the\nadmin Submit-on-Behalf dialog and the admin project detail view's\n\"Retry analysis\" CTA when a part lands in\n``analysis_status=FAILED``.\n\nReturns 202 for the existing client contract; the chokepoint owns\nthe COMPLETE / FAILED transition.","operationId":"admin_retrigger_part_analysis_api_v1_admin_projects__project_id__parts__part_id__retrigger_analysis_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetriggerAnalysisRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetriggerAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/comments":{"get":{"tags":["admin-projects"],"summary":"List Project Comments","description":"List all comments for a project, including internal admin notes.","operationId":"list_project_comments_api_v1_admin_projects__project_id__comments_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectCommentResponse"},"title":"Response List Project Comments Api V1 Admin Projects  Project Id  Comments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["admin-projects"],"summary":"Create Project Comment","description":"Create a comment on a project as an admin.","operationId":"create_project_comment_api_v1_admin_projects__project_id__comments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCommentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCommentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/ollie-transcript":{"get":{"tags":["admin-projects"],"summary":"Get Ollie Transcript","description":"Return the full Ollie conversation + per-part intent + notes bundle.\n\nRead-only. Phase 5D adds the visibility-toggle endpoint for notes.\nSynthetic ``[SYSTEM:...]`` bootstrap turns are filtered out so the\nadmin sees what the customer actually saw. DesignIntent entries are\nfiltered to ``user_asserted`` / ``admin_asserted`` — the same gate\nthe shop drawing uses, keeping one source of truth for \"what content\nmakes it downstream\".","operationId":"get_ollie_transcript_api_v1_admin_projects__project_id__ollie_transcript_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OllieTranscriptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}":{"patch":{"tags":["admin-quotes"],"summary":"Update Quote","description":"Update quote fields such as status, pricing, lead time, and notes.\n\nStatus transitions are validated against the allowed transition map.","operationId":"update_quote_api_v1_admin_quotes__quote_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteAdminUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/line-items":{"post":{"tags":["admin-quotes"],"summary":"Add Line Item","description":"Add a line item to a quote.\n\nThe referenced part must belong to the same project as the quote.","operationId":"add_line_item_api_v1_admin_quotes__quote_id__line_items_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteLineItemCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteLineItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/line-items/{item_id}":{"patch":{"tags":["admin-quotes"],"summary":"Update Line Item","description":"Update a line item on a quote.\n\n``total_price`` is automatically recomputed from the final\n``quantity`` and ``unit_price`` values.","operationId":"update_line_item_api_v1_admin_quotes__quote_id__line_items__item_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteLineItemUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteLineItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-quotes"],"summary":"Delete Line Item","description":"Delete a line item from a quote.","operationId":"delete_line_item_api_v1_admin_quotes__quote_id__line_items__item_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/send":{"post":{"tags":["admin-quotes"],"summary":"Send Quote","description":"Send a quote to the customer.\n\nValidates the quote is in IN_REVIEW status with at least one fully\npriced line item.  Auto-sums line item totals and transitions both\nthe quote and project to QUOTED status.","operationId":"send_quote_api_v1_admin_quotes__quote_id__send_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteAdminSendResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/calculate-tax":{"post":{"tags":["admin-quotes"],"summary":"Calculate Tax","description":"Calculate tax for a quote via Stripe Tax API.\n\nLoads the quote's priced line items and the project's shipping\naddress, checks whether the user is tax-exempt, and calls Stripe\nTax.  Stores the result on the quote (``tax_amount``,\n``tax_auto_calculated``, ``stripe_tax_calculation_id``).","operationId":"calculate_tax_api_v1_admin_quotes__quote_id__calculate_tax_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxCalculationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/generate":{"post":{"tags":["admin-quotes"],"summary":"Generate Delivery Options","description":"Generate Expedited, Standard, and Economy delivery options.","operationId":"generate_delivery_options_api_v1_admin_quotes__quote_id__delivery_options_generate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QuoteDeliveryOptionGenerateRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/{option_id}":{"patch":{"tags":["admin-quotes"],"summary":"Update Delivery Option","description":"Update a quote delivery option.","operationId":"update_delivery_option_api_v1_admin_quotes__quote_id__delivery_options__option_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Option Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/{option_id}/line-items/{line_item_id}":{"patch":{"tags":["admin-quotes"],"summary":"Update Delivery Option Line Item","description":"Update an option-specific line item.","operationId":"update_delivery_option_line_item_api_v1_admin_quotes__quote_id__delivery_options__option_id__line_items__line_item_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Option Id"}},{"name":"line_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Line Item Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionLineItemUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-quotes"],"summary":"Delete Delivery Option Line Item","description":"Delete an option-specific additional line item.","operationId":"delete_delivery_option_line_item_api_v1_admin_quotes__quote_id__delivery_options__option_id__line_items__line_item_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Option Id"}},{"name":"line_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Line Item Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/{option_id}/line-items":{"post":{"tags":["admin-quotes"],"summary":"Create Delivery Option Line Item","description":"Create an option-specific additional line item.","operationId":"create_delivery_option_line_item_api_v1_admin_quotes__quote_id__delivery_options__option_id__line_items_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Option Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionLineItemCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/calculate-tax":{"post":{"tags":["admin-quotes"],"summary":"Calculate Delivery Option Tax","description":"Calculate Stripe Tax independently for each enabled delivery option.","operationId":"calculate_delivery_option_tax_api_v1_admin_quotes__quote_id__delivery_options_calculate_tax_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Calculate Delivery Option Tax Api V1 Admin Quotes  Quote Id  Delivery Options Calculate Tax Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-options/{option_id}/calculate-tax":{"post":{"tags":["admin-quotes"],"summary":"Calculate Single Delivery Option Tax","description":"Calculate Stripe Tax for one enabled delivery option.","operationId":"calculate_single_delivery_option_tax_api_v1_admin_quotes__quote_id__delivery_options__option_id__calculate_tax_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Option Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/auto-price":{"post":{"tags":["admin-quotes"],"summary":"Auto Price","description":"Apply AI estimates to all line items on a quote.\n\nFor each part in the quote's project that has an AI cost estimate\n(from DFM analysis), a line item is created or updated with the\nmid estimate plus the optional margin.\n\nParts without AI estimates are skipped.  The ``is_human_reviewed``\nflag is **not** set — an admin must still explicitly review and\napprove the quote before it can be sent.","operationId":"auto_price_api_v1_admin_quotes__quote_id__auto_price_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AutoPriceRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoPriceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/approve-on-behalf":{"post":{"tags":["admin-quotes"],"summary":"Approve Quote On Behalf","description":"Approve a quote on behalf of the customer.\n\nUsed when ops needs to advance a project past the customer's\n\"Approve and Pay\" gate (e.g. an unresponsive buyer who has agreed\nout-of-band). Validates the same QUOTED + ``is_human_reviewed`` gate\nas the user-side approval, transitions both the quote and the\nproject to APPROVED, writes a ``quote_approved_by_admin`` audit row,\nand fires an in-app notification to the user.\n\nPermission: ``quotes:edit`` (same gate used by ``/review``,\n``/auto-price``, etc.).","operationId":"approve_quote_on_behalf_api_v1_admin_quotes__quote_id__approve_on_behalf_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QuoteApprovalRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/delivery-option-selection":{"patch":{"tags":["admin-quotes"],"summary":"Change Selected Delivery Option","description":"Change an approved quote's accepted delivery option before payment/PO.","operationId":"change_selected_delivery_option_api_v1_admin_quotes__quote_id__delivery_option_selection_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDeliveryOptionSelectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/review":{"patch":{"tags":["admin-quotes"],"summary":"Mark Reviewed","description":"Set or clear the human-reviewed flag on a quote.\n\nPass ``{\"reviewed\": true}`` (or omit the body) to mark as reviewed.\nPass ``{\"reviewed\": false}`` to clear the review, allowing further\nedits before re-reviewing and sending.\n\nMarking reviewed is rejected with **422** until the quote is actually\nready: it must have at least one delivery option generated AND every\npart in the project must be priced. The un-review path is not gated by\nthese prerequisites.\n\nUn-reviewing is blocked once the quote has been sent to the customer.","operationId":"mark_reviewed_api_v1_admin_quotes__quote_id__review_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QuoteReviewRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteReviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/history":{"get":{"tags":["admin-quotes"],"summary":"Get History","description":"Return the audit trail for a quote, newest first.","operationId":"get_history_api_v1_admin_quotes__quote_id__history_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QuoteAuditResponse"},"title":"Response Get History Api V1 Admin Quotes  Quote Id  History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/similar-parts":{"get":{"tags":["admin-quotes"],"summary":"Get Similar Parts For Quote","description":"For each part in the quote, return up to ``k`` most similar past parts.\n\nAnchors are restricted to past quotes that are ``QUOTED`` or\n``APPROVED``, ``is_human_reviewed=True``, and have a non-null\n``unit_price`` on the corresponding line item. The cohort is\nfurther filtered to the same machining process + material so a CNC\npart doesn't anchor on sheet-metal history.\n\nThe response is always well-formed: parts with no fingerprint or\nno historical anchors return ``anchors=[]`` with ``n_anchors=0``\n(no 404). Used by the admin quote-review UI to anchor pricing\ndecisions on historical analogs.","operationId":"get_similar_parts_for_quote_api_v1_admin_quotes__quote_id__similar_parts_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"k","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":1,"description":"Top-k anchors per part","default":5,"title":"K"},"description":"Top-k anchors per part"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSimilarPartsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/pdf":{"get":{"tags":["admin-quotes"],"summary":"Get Quote Pdf","description":"Get presigned download URL for a stored or option-specific quote PDF.","operationId":"get_quote_pdf_api_v1_admin_quotes__quote_id__pdf_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"delivery_option_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional delivery option to render a transient option-specific quote PDF.","title":"Delivery Option Id"},"description":"Optional delivery option to render a transient option-specific quote PDF."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/regenerate-pdf":{"post":{"tags":["admin-quotes"],"summary":"Regenerate Quote Pdf","description":"Force regenerate the quote PDF via Temporal workflow.\n\nReturns 202 Accepted. The PDF will be available within a few seconds.","operationId":"regenerate_quote_pdf_api_v1_admin_quotes__quote_id__regenerate_pdf_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Regenerate Quote Pdf Api V1 Admin Quotes  Quote Id  Regenerate Pdf Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/quotes/{quote_id}/line-items/{item_id}/pricing-feedback":{"post":{"tags":["admin-quotes"],"summary":"Create Pricing Feedback","description":"Capture admin's structured reason when actual price diverges from Track B.\n\nTriggered (in Phase 6 UI) after admin saves a line-item with >50%\ndeviation from the Track B prediction. The reason categories form\nlabeled training data for explaining bucket-level systematic biases\n(NRE, batching, urgency, etc.).\n\nComputes ``deviation_pct`` server-side as\n``(actual - predicted) / predicted`` so the value persisted matches the\nformula used by the bucket-level calibration logic. When\n``track_b_predicted_unit`` is null (cold-start) or zero, deviation is\nstored as 0.0 — the feedback row still records the actual_unit_price\nand reason for future training.\n\nAuth: ``quotes:edit``.","operationId":"create_pricing_feedback_api_v1_admin_quotes__quote_id__line_items__item_id__pricing_feedback_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingFeedbackCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Pricing Feedback Api V1 Admin Quotes  Quote Id  Line Items  Item Id  Pricing Feedback Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/reconciliation":{"get":{"tags":["admin-reconciliation"],"summary":"Get Part Reconciliation","description":"Conflicts + reconciliation summary for one part's drawing/model pair.","operationId":"get_part_reconciliation_api_v1_admin_parts__part_id__reconciliation_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartReconciliationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/reconciliation/conflicts/{conflict_id}":{"patch":{"tags":["admin-reconciliation"],"summary":"Update Conflict","description":"Admin lifecycle: dismiss (or re-open) a conflict, with an optional note.\n\nDismissal is durable — re-analysis will not resurrect a dismissed conflict\n(see ``upsert_conflicts``), so this is the adjudication record.","operationId":"update_conflict_api_v1_admin_reconciliation_conflicts__conflict_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"conflict_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conflict Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConflictUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingModelConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/users/":{"get":{"tags":["admin-users"],"summary":"List Users","description":"List all users with optional search and status filtering.\n\nRequires ``users:view`` permission. Rows additionally carry the CRM\nrollup columns (last activity, orders, revenue, open/lost quotes, last\noutreach, suppression flag) when the caller also holds\n``customer_followups:view``.","operationId":"list_users_api_v1_admin_users__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by email, first name, or last name","title":"Search"},"description":"Search by email, first name, or last name"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by user status","title":"Status"},"description":"Filter by user status"},{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(joined|last_activity|revenue|orders|committed)$","description":"Row ordering: 'joined' (created_at DESC) or a CRM-stats ordering (last_activity/revenue/orders/committed, DESC NULLS LAST). Stats orderings require the customer_followups:view permission.","default":"joined","title":"Sort"},"description":"Row ordering: 'joined' (created_at DESC) or a CRM-stats ordering (last_activity/revenue/orders/committed, DESC NULLS LAST). Stats orderings require the customer_followups:view permission."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminUserListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/users/{user_id}":{"get":{"tags":["admin-users"],"summary":"Get User Detail","description":"Get full user detail including business profile and project count.\n\nRequires ``users:view`` permission.","operationId":"get_user_detail_api_v1_admin_users__user_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/users/{user_id}/status":{"patch":{"tags":["admin-users"],"summary":"Update User Status","description":"Update a user's status (active, inactive, suspended).\n\nCreates an audit log entry for the change.\nRequires ``users:edit`` permission.","operationId":"update_user_status_api_v1_admin_users__user_id__status_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserStatusUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserListItem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/business-profiles/":{"get":{"tags":["admin-business-profiles"],"summary":"List Business Profiles","description":"List all business profiles with optional search and PO approval filtering.\n\nRequires ``users:view`` permission.","operationId":"list_business_profiles_api_v1_admin_business_profiles__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by company name","title":"Search"},"description":"Search by company name"},{"name":"is_approved","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by PO approval status","title":"Is Approved"},"description":"Filter by PO approval status"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminBusinessProfileListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/business-profiles/{profile_id}":{"get":{"tags":["admin-business-profiles"],"summary":"Get Business Profile","description":"Get full business profile detail.\n\nRequires ``users:view`` permission.","operationId":"get_business_profile_api_v1_admin_business_profiles__profile_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/business-profiles/{profile_id}/approve":{"patch":{"tags":["admin-business-profiles"],"summary":"Approve For Po","description":"Approve a business profile for Purchase Order payments.\n\nCreates an audit log entry for the approval.\nRequires ``users:edit`` permission.","operationId":"approve_for_po_api_v1_admin_business_profiles__profile_id__approve_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessProfileApproveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/business-profiles/{profile_id}/revoke":{"patch":{"tags":["admin-business-profiles"],"summary":"Revoke Po Approval","description":"Revoke Purchase Order eligibility for a business profile.\n\nCreates an audit log entry for the revocation.\nRequires ``users:edit`` permission.","operationId":"revoke_po_approval_api_v1_admin_business_profiles__profile_id__revoke_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessProfileRevokeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/business-profiles/{profile_id}/tax-exempt":{"patch":{"tags":["admin-business-profiles"],"summary":"Toggle Tax Exempt","description":"Toggle tax exemption on a business profile.\n\nCreates an audit log entry for the change.\nRequires ``users:edit`` permission.","operationId":"toggle_tax_exempt_api_v1_admin_business_profiles__profile_id__tax_exempt_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxExemptToggleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__business_profile__BusinessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/suppliers/":{"get":{"tags":["admin-suppliers"],"summary":"List Suppliers","description":"List suppliers (paginated).\n\nRequires ``vendors:manage`` permission.\n\nThe ``active`` query param is tri-state:\n\n* ``?active=true`` (default) — active rows only\n* ``?active=false`` — inactive rows only\n* omit the param (or send ``?active=`` with explicit null) — all rows","operationId":"list_suppliers_api_v1_admin_suppliers__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search name / email / company (case-insensitive ilike)","title":"Q"},"description":"Search name / email / company (case-insensitive ilike)"},{"name":"active","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Three-state filter: true → active only, false → inactive only, omit param → all rows.","default":true,"title":"Active"},"description":"Three-state filter: true → active only, false → inactive only, omit param → all rows."},{"name":"sort","in":"query","required":false,"schema":{"enum":["name","last_contacted_at","created_at"],"type":"string","description":"Sort column","default":"created_at","title":"Sort"},"description":"Sort column"},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"Sort direction","default":"desc","title":"Order"},"description":"Sort direction"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SupplierContactListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["admin-suppliers"],"summary":"Create Supplier","description":"Create a new supplier.\n\nReturns 409 ``{code: \"email_exists\", message: ...}`` if the email is\nalready in use (active or inactive).","operationId":"create_supplier_api_v1_admin_suppliers__post","security":[{"OAuth2PasswordBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/suppliers/{supplier_id}":{"get":{"tags":["admin-suppliers"],"summary":"Get Supplier","description":"Get full supplier detail.\n\nReturns inactive rows too — the admin needs to see + restore them.","operationId":"get_supplier_api_v1_admin_suppliers__supplier_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-suppliers"],"summary":"Update Supplier","description":"Partial update of a supplier.\n\nReturns 409 with the locked envelope if the email change collides\nwith another existing row.","operationId":"update_supplier_api_v1_admin_suppliers__supplier_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-suppliers"],"summary":"Soft Delete Supplier","description":"Soft-delete a supplier (flip ``active=False``).\n\nIdempotent — deleting an already-inactive row is a 204 no-op.","operationId":"soft_delete_supplier_api_v1_admin_suppliers__supplier_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/suppliers/{supplier_id}/restore":{"post":{"tags":["admin-suppliers"],"summary":"Restore Supplier","description":"Restore an inactive supplier (flip ``active=True``).\n\nIdempotent — restoring an already-active row is a 200 no-op. No 409\nbranch is possible: the DB unique index on ``email`` already\nprevents any other row from holding this supplier's email.","operationId":"restore_supplier_api_v1_admin_suppliers__supplier_id__restore_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierContactRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/supplier-quotes":{"get":{"tags":["admin-supplier-quotes"],"summary":"List Project Supplier Quotes","description":"List RFQ-backed and standalone supplier quotes for a project.","operationId":"list_project_supplier_quotes_api_v1_admin_projects__project_id__supplier_quotes_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SupplierQuoteRead"},"title":"Response List Project Supplier Quotes Api V1 Admin Projects  Project Id  Supplier Quotes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["admin-supplier-quotes"],"summary":"Create Project Supplier Quote","description":"Create a standalone supplier quote/invoice without requiring an RFQ thread.","operationId":"create_project_supplier_quote_api_v1_admin_projects__project_id__supplier_quotes_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSupplierQuoteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/vendor-threads":{"get":{"tags":["admin-supplier-quotes"],"summary":"List Project Vendor Threads","description":"List ThreadStates for a project, joined with supplier + latest quote.\n\nSingle source of truth for the project Supplier-quotes tab. Uses\n``selectinload`` + a manual batched query for latest quote summaries\nso the round-trip count stays at <=2 regardless of how many threads\nthe project has (eng-review §4.1).\n\nOrdered by ``ThreadState.created_at DESC`` (most recently engaged\nsuppliers first).","operationId":"list_project_vendor_threads_api_v1_admin_projects__project_id__vendor_threads_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VendorThreadStateListItem"},"title":"Response List Project Vendor Threads Api V1 Admin Projects  Project Id  Vendor Threads Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-quotes/{quote_id}":{"get":{"tags":["admin-supplier-quotes"],"summary":"Get Supplier Quote","description":"Full detail of one SupplierQuote.\n\nJoins the supplier contact's name + email so the FE doesn't need a\nsecond round-trip. ``attachment_r2_keys`` is intentionally NOT\nexposed in V1 — design-review dropped PDF upload from the admin UI;\nadmins keep PDFs in Gmail.","operationId":"get_supplier_quote_api_v1_admin_supplier_quotes__quote_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-supplier-quotes"],"summary":"Update Supplier Quote","description":"Partial PATCH — edits the existing quote row in place.\n\nTo record a *revised* quote (e.g., supplier sent a new number),\nadmin POSTs a new revision via the create endpoint instead — append-on-\nrevision pattern preserves the audit trail (eng-review §1.6).\n\nRe-stamps ``reviewed_at`` + ``reviewed_by`` on every PATCH so the\naudit reflects the latest admin touch.","operationId":"update_supplier_quote_api_v1_admin_supplier_quotes__quote_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendor-threads/{thread_state_id}/quotes":{"post":{"tags":["admin-supplier-quotes"],"summary":"Create Manual Supplier Quote","description":"APPENDS a new SupplierQuote row for a given ThreadState.\n\nAppend-on-revision pattern (eng-review §1.6): every call appends a\nnew row even when the thread already has a recorded quote. The older\nrow stays in ``supplier_quotes`` for audit; ``ThreadState.latest_quote_id``\nflips to the new id.\n\nHitL gate divergence: this path sets ``needs_human_review=False``\n(admin entering data IS the reviewer). The MCP inbound path retains\n``True``.\n\nTransaction atomicity: SupplierQuote insert + ThreadState updates\nland in ONE commit (eng-review §2.3). On any failure the rollback\nleaves no partial state.","operationId":"create_manual_supplier_quote_api_v1_admin_vendor_threads__thread_state_id__quotes_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"thread_state_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread State Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteManualCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendor-threads/{thread_state_id}/decline":{"post":{"tags":["admin-supplier-quotes"],"summary":"Mark Vendor Thread Declined","description":"Transition the ThreadState to ``declined``.\n\nBody is a :class:`MarkDeclinedInput` with an optional ``reason``\n(max 500 chars). When provided, the reason is recorded in\n``ThreadState.last_intent``. When omitted, ``last_intent`` is left\nuntouched (a previously recorded intent isn't accidentally erased).\n\nIf the thread had a ``latest_quote_id`` pointer set, it's cleared.\nThe underlying SupplierQuote row (if any) stays in the table — the\naudit trail is preserved.\n\nNo SupplierQuote row is created — declines are conversation-level\nevents.","operationId":"mark_vendor_thread_declined_api_v1_admin_vendor_threads__thread_state_id__decline_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"thread_state_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread State Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkDeclinedInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorThreadStateListItem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendor-threads/{thread_state_id}":{"delete":{"tags":["admin-supplier-quotes"],"summary":"Discard Vendor Thread","description":"Hard-delete a VendorThreadState row.\n\nUse case: admin discarded the agent-drafted RFQ email in Gmail and\nwants to remove the supplier from this project's Quotes tab view.\nReturns 409 if the thread has a recorded supplier quote — those\nflows must use ``/decline`` so audit history is preserved.\n\nRecovery: discarding is reversible by re-running the outbound agent\nvia the manual \"Draft RFQs\" button. The agent's ``log_rfq_sent``\ntool is idempotent on ``(project_id, supplier_contact_id)`` — a\nfresh ThreadState will be created on the next draft.","operationId":"discard_vendor_thread_api_v1_admin_vendor_threads__thread_state_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"thread_state_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread State Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-quotes/{quote_id}/accept":{"post":{"tags":["admin-supplier-quotes"],"summary":"Accept Supplier Quote","description":"Accept an inbound-agent-extracted SupplierQuote (PRO-113).\n\nClears every ``line_items[*].needs_review`` flag, flips\n``quote.needs_human_review = False`` (HitL gate cleared), and stamps\n``reviewed_at`` + ``reviewed_by``. Idempotent — accepting an\nalready-accepted quote re-stamps the reviewer fields but leaves the\nstructured data untouched.\n\nRe-mapping rows to different project parts is handled by the existing\nPATCH endpoint — admin corrects rows in-place THEN clicks Accept.","operationId":"accept_supplier_quote_api_v1_admin_supplier_quotes__quote_id__accept_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptSupplierQuoteInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-quotes/{quote_id}/accept-won":{"post":{"tags":["admin-supplier-quotes"],"summary":"Accept Supplier Quote Won","description":"Mark a SupplierQuote as the winning supplier for the RFQ.\n\nStamps ``SupplierQuote.accepted_at = utcnow()`` and writes an\n``AgentAction(action_type=\"vendors_ranker_outcome\")`` capturing which\nsupplier won + which suppliers were considered at routing time. The\noutcome feeds the v2 ranker's history bonus with a precise per-supplier\nsignal (replaces the approximate ``Quote.status == APPROVED`` join).\n\nIdempotent (eng-review §accept-won-idempotency): a second call against\nthe same quote does NOT duplicate the AgentAction row, but DOES\nre-stamp ``accepted_at``. See :meth:`SupplierQuoteService.accept_won`\nfor the full contract.\n\nDistinct from :func:`accept_supplier_quote` (the PRO-113 HitL gate\nclear). Accept-won is a higher-level signal: \"this is the supplier\nwe're going with\"; the legacy ``accept`` only clears the per-row\nreview flags.\n\nPlan reference:\n``.claude/plans/active/vendors-agent-supplier-ranking-and-intelligent-routing.md``\n(Phase 3 — Outcome capture + Calibration loop hook).","operationId":"accept_supplier_quote_won_api_v1_admin_supplier_quotes__quote_id__accept_won_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-quotes/{quote_id}/source-preview-url":{"get":{"tags":["admin-supplier-quotes"],"summary":"Get Source Preview Url","description":"Return a presigned R2 URL for one of the quote's attachments (PRO-113).\n\nPowers the V2 Quote Correction View's left-side source preview when\nthe supplier replied with a file attachment (PDF / CSV / XLSX). The\nURL has a 24h TTL — long enough for an admin review session, short\nenough to limit replay if leaked.\n\nPhase 4: accepts an optional ``attachment_index`` query parameter so\nthe admin UI can preview ANY attachment on the quote, not just the\nfirst. The agent's ``prepare_quote_attachment`` flow persists\nattachments in upload order; the admin UI now lets users page\nthrough them (and any admin-uploaded follow-up attachments).\n\nReturns 404 when the quote has no attachments, or when\n``attachment_index`` is out of range (frontend falls back to the\ninline-body source via ``source_email_body`` on the read schema, or\nshows the empty state).\n\nMIME type is inferred from the R2 key's filename extension —\nsufficient for the V2 UI to pick between iframe (PDF), HTML table\n(CSV), or generic download (XLSX or unknown). Server-side parsing\nof CSV / XLSX content for inline highlighting is deferred to a\nfuture iteration; V1 fetches the URL client-side and parses there.","operationId":"get_source_preview_url_api_v1_admin_supplier_quotes__quote_id__source_preview_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"attachment_index","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"0-based index into the quote's ``attachment_r2_keys`` array. Defaults to 0 (the first / primary source). Use higher indices to preview follow-up attachments (e.g. an invoice alongside the original quote).","default":0,"title":"Attachment Index"},"description":"0-based index into the quote's ``attachment_r2_keys`` array. Defaults to 0 (the first / primary source). Use higher indices to preview follow-up attachments (e.g. an invoice alongside the original quote)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourcePreviewUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-documents/{document_id}/apply-extraction":{"post":{"tags":["admin-supplier-quotes"],"summary":"Apply Supplier Document Extraction","description":"Apply the latest supplier document extraction into its SupplierQuote.","operationId":"apply_supplier_document_extraction_api_v1_admin_supplier_documents__document_id__apply_extraction_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-quotes/{quote_id}/attachments":{"post":{"tags":["admin-supplier-quotes"],"summary":"Upload Supplier Quote Attachment","description":"Append an admin-uploaded attachment to a SupplierQuote (Phase 4).\n\nThe inbound agent persists supplier attachments automatically (see\n``prepare_quote_attachment`` MCP tool), but two failure modes call\nfor a manual admin upload:\n\n* The Anthropic Files API was down AND the local PDF fallback\n  returned empty text (the agent escalated rather than persisted).\n* The supplier sent a follow-up document (an invoice) on a thread\n  that was already closed at the ``quoted`` state.\n\nBehavior:\n\n* Streams the file to R2 under the SAME prefix the inbound agent\n  uses (``vendors/inbound-attachments/<gmail_message_id>/<filename>``)\n  so the existing ``source-preview-url`` endpoint serves admin and\n  agent uploads uniformly.\n* Appends the R2 key to ``SupplierQuote.attachment_r2_keys`` AND the\n  kind tag to ``SupplierQuote.attachment_kinds`` (parallel-array\n  invariant). When the quote was created by the inbound agent\n  BEFORE Phase 3 shipped, ``attachment_kinds`` may be empty; the\n  handler synthesizes ``[\"quote\"] * len(attachment_r2_keys)`` to\n  backfill before appending the new tag.\n* Returns the updated :class:`SupplierQuoteRead` so the FE can\n  immediately re-render the attachment list without a second GET.\n\nEnforces a 25MB cap matching the inbound agent's ceiling.","operationId":"upload_supplier_quote_attachment_api_v1_admin_supplier_quotes__quote_id__attachments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_supplier_quote_attachment_api_v1_admin_supplier_quotes__quote_id__attachments_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-supplier-quotes"],"summary":"Delete Supplier Quote Attachment","description":"Soft-delete an attachment from a SupplierQuote (Phase 4 follow-up).\n\nRemoves the given ``r2_key`` from\n:attr:`SupplierQuote.attachment_r2_keys` AND the parallel kind tag from\n:attr:`SupplierQuote.attachment_kinds`. The actual R2 object is left in\nplace — the codebase's existing R2 retention posture is \"everything is\nforever\" (no lifecycle rules) and the audit-trail principle (plan\ndecision D3) prefers append-only writes. An engineer can manually\nre-link the orphaned R2 key if a delete needs reversing.\n\nKey-based addressing (vs index-based) makes the operation robust against\nracing admins: two admins viewing the same quote can each delete a\ndifferent attachment without colliding on shifting indices. If the\nrequested ``r2_key`` is not in the row's array, returns 404 — idempotent\ntreatment (a retry after success is a no-op from the caller's POV).\n\nLegacy rows where ``attachment_kinds`` is empty (pre-Phase-3) get the\nparallel array synthesized as ``[\"quote\"] * N`` BEFORE the delete, so\nthe post-write parallel-array invariant holds.","operationId":"delete_supplier_quote_attachment_api_v1_admin_supplier_quotes__quote_id__attachments_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Quote Id"}},{"name":"r2_key","in":"query","required":true,"schema":{"type":"string","title":"R2 Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendor-threads/{thread_state_id}/attachments":{"post":{"tags":["admin-supplier-quotes"],"summary":"Upload Vendor Thread Attachment","description":"Attach a quote/invoice document to a thread BEFORE a quote is recorded.\n\nThe \"document received, not yet parsed\" path. An admin has a supplier's\nquote/invoice PDF and wants it on the RFQ thread immediately, without\nfirst hand-keying a structured ``SupplierQuote``. The document gets\nparsed into quote fields later (the admin PATCHes the shell, or a future\nre-parse fills it in).\n\nBehaviour (delegates to\n:meth:`SupplierQuoteService.upload_thread_attachment`):\n\n* **Thread has a recorded quote** (``latest_quote_id`` set) — append the\n  attachment to it; no new quote row is created.\n* **Thread has no quote yet** — create an EMPTY manual-entry\n  ``SupplierQuote`` shell (no amounts, no line items), point\n  ``latest_quote_id`` at it, then append the attachment. The thread's\n  ``status`` is NOT forced to ``\"quoted\"`` for the shell — only a\n  document has arrived, nothing is priced yet.\n\nShares the exact R2 prefix + parallel-array append + file-type / size\nhandling with ``POST /admin/supplier-quotes/{quote_id}/attachments``\n(same shared helpers). Returns the updated :class:`SupplierQuoteRead`\nso the FE can re-render the row with the new attachment.\n\nSame ``vendors:manage`` gate as its siblings. 404 if the thread is\nmissing; 400 on an empty file; 413 over the 25MB cap; 422 on an\ninvalid ``document_kind``; 502 if the R2 upload fails.","operationId":"upload_vendor_thread_attachment_api_v1_admin_vendor_threads__thread_state_id__attachments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"thread_state_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread State Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_vendor_thread_attachment_api_v1_admin_vendor_threads__thread_state_id__attachments_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/suppliers/{supplier_contact_id}/attachments":{"post":{"tags":["admin-supplier-quotes"],"summary":"Upload Project Supplier Attachment","description":"Attach a quote/invoice document to any active project supplier.\n\nUsed by the V2 Supplier panel rows for suppliers that do not yet have an\nRFQ ``VendorThreadState``. The service creates or reuses the appropriate\nproject-level quote/invoice shell, appends the file, persists a\n``SupplierQuoteDocument`` row, and starts document extraction.","operationId":"upload_project_supplier_attachment_api_v1_admin_projects__project_id__suppliers__supplier_contact_id__attachments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"supplier_contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Contact Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_project_supplier_attachment_api_v1_admin_projects__project_id__suppliers__supplier_contact_id__attachments_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierQuoteRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/supplier-order":{"post":{"tags":["admin-supplier-orders"],"summary":"Select Project Manufacturer","description":"Select a manufacturer for the project (auto-creates the SupplierOrder).\n\nMark ANY active supplier as the manufacturer — with or without an RFQ\nquote. Idempotent + repoint-safe via\n:meth:`SupplierOrderService.select_manufacturer`:\n\n* no order yet → create one for the picked supplier,\n* order exists for the same supplier → update the quote link + their_*,\n* order exists for a DIFFERENT supplier → repoint it AND clear the\n  previously-won quote's ``accepted_at`` (single-winner).\n\nWhen ``supplier_quote_id`` is supplied, ``their_price_cents`` /\n``their_lead_time_days`` default from that quote unless explicitly set here.\n\nAn optional ``order_confirmed_at`` calendar date (normalized to UTC noon)\nsets the supplier confirmation date the buy-side ETA counts from; when\nomitted the service defaults it to now().","operationId":"select_project_manufacturer_api_v1_admin_projects__project_id__supplier_order_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectManufacturerInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierOrderRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["admin-supplier-orders"],"summary":"Get Project Supplier Order","description":"Read the project's buy-side SupplierOrder.\n\nReturns 404 when the project has no SupplierOrder — that's the in-house /\nunsourced case (no supplier has won the RFQ). The admin overview LIST\nrenders the in-house state inline via the ``manufacturer`` object; this\ndetail endpoint 404s so the FE can distinguish \"no order\" cleanly.","operationId":"get_project_supplier_order_api_v1_admin_projects__project_id__supplier_order_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierOrderRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-orders/{supplier_order_id}":{"patch":{"tags":["admin-supplier-orders"],"summary":"Update Supplier Order","description":"Partial PATCH — edit the buy-side order's mfg / shipping / AP fields.\n\nApplies only the keys present in the body. ``None`` clears a nullable\nfield; an omitted key leaves it untouched.","operationId":"update_supplier_order_api_v1_admin_supplier_orders__supplier_order_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Order Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierOrderUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierOrderRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-orders/{supplier_order_id}/mark-supplier-invoice-paid":{"post":{"tags":["admin-supplier-orders"],"summary":"Mark Supplier Invoice Paid","description":"Record that we paid the supplier (buy-side AP closure).\n\nStamps ``we_paid_at`` (defaults to now when not supplied) and optionally\nthe paid amount + supplier invoice number. After this the buy-side state\nderives to ``paid``.","operationId":"mark_supplier_invoice_paid_api_v1_admin_supplier_orders__supplier_order_id__mark_supplier_invoice_paid_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Order Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkSupplierInvoicePaidInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierOrderRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/vendor-routing":{"get":{"tags":["admin-vendor-routing"],"summary":"Get Vendor Routing Preview","description":"Preview the ranker output for a project + return any active override.\n\nReturns 404 when the project doesn't exist.","operationId":"get_vendor_routing_preview_api_v1_admin_projects__project_id__vendor_routing_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorRoutingPreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/vendor-routing/override":{"post":{"tags":["admin-vendor-routing"],"summary":"Record Vendor Routing Override","description":"Record an admin override of the ranker's top-N as an ``AgentAction``.\n\nWrites ``AgentAction(action_type=\"vendors_ranker_override\")`` capturing\nboth the ranker's would-be top-N (so the future calibration loop can\ndiff override vs ranker decisions) AND the admin's chosen supplier list\n+ free-text reason. Storage lives in ``AgentAction.output_data`` JSONB\n(decision D2 — no schema change).\n\nValidation:\n\n* Every ``supplier_contact_id`` must refer to an ACTIVE supplier row.\n  Inactive / soft-deleted suppliers are rejected — admins should\n  restore the supplier first if they really want to route to them.\n* Project must exist.\n\n**Out of scope for this phase:** consuming the override at agent\nkickoff. Phase 2 ships the capture surface; the agent kickoff hook\nis a follow-up. See plan §Phase 2 task 12.\n\nReturns 201 with the created override row.","operationId":"record_vendor_routing_override_api_v1_admin_projects__project_id__vendor_routing_override_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorRoutingOverrideRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorRoutingOverride"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/unmatched":{"get":{"tags":["admin-unmatched-replies"],"summary":"List Unmatched Replies","description":"List supplier replies the inbound webhook couldn't route.\n\nReturns only rows still awaiting reassignment (``reassigned_at IS\nNULL``), ordered newest-first by ``received_at``.","operationId":"list_unmatched_replies_api_v1_admin_agent_unmatched_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UnmatchedReplyRead"},"type":"array","title":"Response List Unmatched Replies Api V1 Admin Agent Unmatched Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/agent/unmatched/{reply_id}/reassign":{"post":{"tags":["admin-unmatched-replies"],"summary":"Reassign Unmatched Reply","description":"Link an unmatched reply to a project.\n\nProject-only — the model has no supplier-contact column, so the body\nis just ``{project_id}``. Stamps the ``reassigned_*`` audit columns\nwith the supplied project + the acting admin.\n\nReturns 404 when the reply or project is missing, 409 when the reply\nhas already been reassigned (reassignment is terminal).","operationId":"reassign_unmatched_reply_api_v1_admin_agent_unmatched__reply_id__reassign_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"reply_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reply Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnmatchedReplyReassignRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnmatchedReplyRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cad-files/":{"get":{"tags":["admin-cad-files"],"summary":"List Cad Files","description":"List all CAD files across all projects with optional filters.\n\nRequires ``projects:view`` permission.","operationId":"list_cad_files_api_v1_admin_cad_files__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by file name","title":"Search"},"description":"Search by file name"},{"name":"file_format","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by file format (e.g. stl, step)","title":"File Format"},"description":"Filter by file format (e.g. stl, step)"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by project ID","title":"Project Id"},"description":"Filter by project ID"},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter from date (inclusive)","title":"Date From"},"description":"Filter from date (inclusive)"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter to date (inclusive)","title":"Date To"},"description":"Filter to date (inclusive)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminCadFileListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cad-files/{cad_file_id}":{"get":{"tags":["admin-cad-files"],"summary":"Get Cad File Detail","description":"Get full CAD file version details including geometry analysis data.\n\nReturns all fields from the ``CadFileVersion`` record including\ndimensions, volume, DFM issues, and presigned URLs for converted files.\nRequires ``projects:view`` permission.\n\nThe ``detected_features`` blob is filtered against the part's selected\nmanufacturing process (so a sheet metal part doesn't show CNC-only\nfeatures and vice versa). Pass ``?unfiltered=true`` to skip the filter\n— the admin part viewer panel does this so its in-page \"Show all\"\ntoggle can flip without invalidating the TanStack Query cache.","operationId":"get_cad_file_detail_api_v1_admin_cad_files__cad_file_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"cad_file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cad File Id"}},{"name":"unfiltered","in":"query","required":false,"schema":{"type":"boolean","description":"Skip process-aware feature filtering. Admin escape hatch — the admin app passes this by default so the panel-side toggle can re-derive without re-fetching.","default":false,"title":"Unfiltered"},"description":"Skip process-aware feature filtering. Admin escape hatch — the admin app passes this by default so the panel-side toggle can re-derive without re-fetching."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CadFileVersionDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cad-files/{cad_file_id}/download":{"get":{"tags":["admin-cad-files"],"summary":"Download Cad File","description":"Generate a presigned download URL for a specific CAD file.\n\nWhen ``key`` is omitted, the original CAD file is served with a 5-minute\nTTL.  When ``key`` is provided it must match one of the version's R2 keys\n(``r2_key``, ``glb_r2_key``, or ``thumbnail_r2_key``); the TTL is adjusted\nby file type.\n\nRequires ``projects:view`` permission.","operationId":"download_cad_file_api_v1_admin_cad_files__cad_file_id__download_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"cad_file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cad File Id"}},{"name":"key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Specific R2 key to download (GLB, thumbnail). If omitted, downloads the original CAD file.","title":"Key"},"description":"Specific R2 key to download (GLB, thumbnail). If omitted, downloads the original CAD file."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCadFileDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cad/initiate":{"post":{"tags":["admin-cad-uploads"],"summary":"Admin Initiate Cad Upload","description":"Initiate a CAD upload under the project owner's R2 namespace.","operationId":"admin_initiate_cad_upload_api_v1_admin_parts__part_id__cad_initiate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cad/upload/{version_id}":{"post":{"tags":["admin-cad-uploads"],"summary":"Admin Upload Cad File","description":"Proxy-upload CAD bytes for an admin-created CAD version.","operationId":"admin_upload_cad_file_api_v1_admin_parts__part_id__cad_upload__version_id__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_upload_cad_file_api_v1_admin_parts__part_id__cad_upload__version_id__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Admin Upload Cad File Api V1 Admin Parts  Part Id  Cad Upload  Version Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cad/confirm":{"post":{"tags":["admin-cad-uploads"],"summary":"Admin Confirm Cad Upload","description":"Confirm an admin CAD upload and start the normal CAD Temporal workflow.","operationId":"admin_confirm_cad_upload_api_v1_admin_parts__part_id__cad_confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"reason","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CadFileVersionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/cam-generator-config":{"get":{"tags":["admin-cam"],"summary":"Runnable generator brains for the CAM Generate dropdown","description":"The brains an admin can pick as the primary generator: \"pipeline\"\nplus every configured provider:model whose API key is present.","operationId":"get_cam_generator_config_api_v1_admin_parts_cam_generator_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamGeneratorConfigResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/parts/{part_id}/cam/generate":{"post":{"tags":["admin-cam"],"summary":"Kick off a CAM generation workflow for a part","description":"Create a pending artifact + start a Temporal workflow.\n\nThree gating layers apply in order:\n  1. ``CAM_PIPELINE_ENABLED`` env → 501 if disabled\n  2. Monthly cost cap → 429 if the admin is over budget\n  3. DB partial unique index → 409 if another run is already in flight\n\nThe optional JSON body (:class:`CamGenerateRequest`) selects the emitted\nG-code dialect via ``post_processor`` (``None`` → grbl default). The choice\nis baked into the CamSpec synthesized here (persisted on the artifact\nsnapshot) AND threaded into the workflow so the re-synthesizing activity\nemits the same dialect.","operationId":"generate_cam_api_v1_admin_parts__part_id__cam_generate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CamGenerateRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamGenerateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam":{"get":{"tags":["admin-cam"],"summary":"Return the latest CamArtifact for a part","operationId":"get_latest_cam_artifact_api_v1_admin_parts__part_id__cam_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamArtifactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/download-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the .nc file (10 min TTL)","operationId":"get_cam_download_url_api_v1_admin_parts__part_id__cam__artifact_id__download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/agent-download-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the agent-reference .nc (10 min TTL)","description":"Presigned URL for one agent brain's reference .nc.\n\n``index`` selects the entry in ``agent_references`` (one per configured\nbrain — e.g. 0 = Fable 5, 1 = GPT-5.6). Same auth/TTL as the pipeline\nprogram; 404 until that brain's pass has shipped a program.","operationId":"get_cam_agent_download_url_api_v1_admin_parts__part_id__cam__artifact_id__agent_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}},{"name":"index","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/setup-sheet-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the Markdown setup sheet (Phase 4+)","description":"Phase 4+: setup sheet only exists for the local_fusion_mcp engine path.\n\nReturns 404 if:\n- The artifact doesn't exist\n- The artifact belongs to a different part\n- The artifact has no setup_sheet_r2_key (FreeCAD path, or pre-Phase-4)","operationId":"get_cam_setup_sheet_url_api_v1_admin_parts__part_id__cam__artifact_id__setup_sheet_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/setup-sheet-html-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the formatted HTML setup sheet","description":"Return a presigned URL for the HTML-rendered setup sheet.\n\nTwo producers write setup sheets at ``cam-artifacts/{artifact_id}/``:\n\n* The C2 deterministic renderer (all engines) writes ``setup_sheet.html``\n  and claims the ``setup_sheet_r2_key`` slot with that .html key — the\n  canonical sheet going forward. When the key already ends ``.html`` we\n  serve it directly (no suffix dance).\n* The agentic Fusion path writes ``setup_sheet.md`` (canonical slot) with\n  a rendered ``setup_sheet.html`` sibling. For those we suffix-swap and\n  prefer the .html when it exists, else fall back to the .md so the\n  frontend's \"open in new tab\" UX still works.","operationId":"get_cam_setup_sheet_html_url_api_v1_admin_parts__part_id__cam__artifact_id__setup_sheet_html_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/setup-sheet-pdf-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the PDF-rendered setup sheet (C2)","description":"Return a presigned URL for the PDF sibling of the setup sheet.\n\nThe C2 deterministic renderer writes ``setup_sheet.pdf`` next to\n``setup_sheet.html`` at ``cam-artifacts/{artifact_id}/``. The PDF key is\nderived from the canonical ``setup_sheet_r2_key`` by swapping the suffix,\nso no DB column is needed. Returns 404 when the artifact has no setup\nsheet, or when the PDF wasn't produced (e.g. Playwright unavailable in the\nworker — the HTML sheet still is, via ``setup-sheet-html-url``).","operationId":"get_cam_setup_sheet_pdf_url_api_v1_admin_parts__part_id__cam__artifact_id__setup_sheet_pdf_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/recording-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the toolpath simulation MP4 (Phase 5C)","description":"Phase 5C: simulation MP4 only exists for the agentic local_fusion_mcp path.\n\nBest-effort capture during Phase 4 (Validate). Returns 404 if:\n- The artifact doesn't exist\n- The artifact belongs to a different part\n- The artifact has no recording_r2_key (FreeCAD path, deterministic\n  Phase 4 path, or agent's recording step skipped/failed)","operationId":"get_cam_recording_url_api_v1_admin_parts__part_id__cam__artifact_id__recording_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/failure-screenshot-url":{"get":{"tags":["admin-cam"],"summary":"Presigned R2 URL for the agent's failure screenshot (Phase 5+)","description":"Phase 5+: when the agent loop fails, it captures a Fusion VM\ndesktop screenshot and uploads it to a deterministic R2 key\n(``cam-artifacts/{artifact_id}/failure_screenshot.png``). The admin\nUI's CamErrorBanner fetches this URL and renders the screenshot\ninline so the operator can see what state Fusion was in when the\nagent gave up. No DB column needed — the path is deterministic.\n\nReturns 404 if the artifact doesn't exist, isn't in `failed`\nstate, or has no screenshot at the expected path (Phase 4 failures\nwon't have one).","operationId":"get_cam_failure_screenshot_url_api_v1_admin_parts__part_id__cam__artifact_id__failure_screenshot_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamDownloadUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/{artifact_id}/cancel":{"post":{"tags":["admin-cam"],"summary":"Cancel an in-flight CAM generation workflow","description":"Terminate the Temporal workflow for an in-flight artifact and mark it failed.\n\nReturns 404 if the artifact doesn't exist or belongs to a different part.\nReturns 409 if the artifact is already in a terminal state.","operationId":"cancel_cam_api_v1_admin_parts__part_id__cam__artifact_id__cancel_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CamArtifactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/cam/events":{"get":{"tags":["admin-cam"],"summary":"SSE stream of CAM generation events for a part","operationId":"cam_events_stream_api_v1_admin_parts__part_id__cam_events_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/initiate":{"post":{"tags":["admin-drawings"],"summary":"Admin Initiate Drawing Upload","description":"Reserve a drawing R2 key under the project owner's namespace.","operationId":"admin_initiate_drawing_upload_api_v1_admin_parts__part_id__drawings_initiate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateDrawingUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateDrawingUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/upload":{"post":{"tags":["admin-drawings"],"summary":"Admin Upload Drawing File","description":"Proxy-upload an admin drawing file to R2.","operationId":"admin_upload_drawing_file_api_v1_admin_parts__part_id__drawings_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"r2_key","in":"query","required":true,"schema":{"type":"string","description":"R2 object key from initiate.","title":"R2 Key"},"description":"R2 object key from initiate."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_upload_drawing_file_api_v1_admin_parts__part_id__drawings_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Admin Upload Drawing File Api V1 Admin Parts  Part Id  Drawings Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/confirm":{"post":{"tags":["admin-drawings"],"summary":"Admin Confirm Drawing Upload","description":"Save drawing metadata and trigger native drawing analysis/redaction.","operationId":"admin_confirm_drawing_upload_api_v1_admin_parts__part_id__drawings_confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"reason","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmDrawingUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Admin Confirm Drawing Upload Api V1 Admin Parts  Part Id  Drawings Confirm Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/download-url":{"get":{"tags":["admin-drawings"],"summary":"Admin Get Drawing Download Url","description":"Generate a presigned download URL for a part's original drawing.\n\nRequires ``projects:view`` permission.","operationId":"admin_get_drawing_download_url_api_v1_admin_parts__part_id__drawings_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/redacted-download-url":{"get":{"tags":["admin-drawings"],"summary":"Admin Get Redacted Drawing Download Url","description":"Generate a presigned download URL for a part's redacted drawing.\n\nThe redacted drawing has logos, company data, and PII removed —\nsafe for sharing with suppliers.\n\nRequires ``projects:view`` permission.","operationId":"admin_get_redacted_drawing_download_url_api_v1_admin_parts__part_id__drawings_redacted_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrawingDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings/redaction-report":{"get":{"tags":["admin-drawings"],"summary":"Admin Get Part Redaction Report","description":"Redaction status + 'what was redacted' summary for a part's drawing.\n\nInformational, non-blocking: redaction is best-effort automatic; the\nadmin reviews the draft RFQ (with the redacted PDF attached) before\nsending. This report lets them sanity-check what was removed.\n\nRequires ``projects:view`` permission.","operationId":"admin_get_part_redaction_report_api_v1_admin_parts__part_id__drawings_redaction_report_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartRedactionReportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/drawings":{"delete":{"tags":["admin-drawings"],"summary":"Admin Delete Drawing","description":"Remove drawing metadata on behalf of the customer.","operationId":"admin_delete_drawing_api_v1_admin_parts__part_id__drawings_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"reason","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/dropdowns":{"get":{"tags":["admin-dropdowns"],"summary":"List Dropdowns","description":"List all dropdown options including inactive ones.\n\nOrdered by category and sort_order. Requires ``settings:view`` permission.","operationId":"list_dropdowns_api_v1_admin_dropdowns_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AdminDropdownResponse"},"type":"array","title":"Response List Dropdowns Api V1 Admin Dropdowns Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"post":{"tags":["admin-dropdowns"],"summary":"Create Dropdown","description":"Create a new dropdown option.\n\nRequires ``settings:create`` permission.","operationId":"create_dropdown_api_v1_admin_dropdowns_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminDropdownCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminDropdownResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/dropdowns/{dropdown_id}":{"patch":{"tags":["admin-dropdowns"],"summary":"Update Dropdown","description":"Partially update a dropdown option.\n\nRequires ``settings:edit`` permission.","operationId":"update_dropdown_api_v1_admin_dropdowns__dropdown_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"dropdown_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Dropdown Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminDropdownUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminDropdownResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-dropdowns"],"summary":"Deactivate Dropdown","description":"Soft-delete a dropdown by deactivating it.\n\nChecks referential integrity: returns 409 if the dropdown is still\nreferenced by any parts. Requires ``settings:delete`` permission.","operationId":"deactivate_dropdown_api_v1_admin_dropdowns__dropdown_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"dropdown_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Dropdown Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/process-mappings":{"get":{"tags":["admin-dropdowns"],"summary":"List Process Mappings","description":"List all process mappings with resolved dropdown labels.\n\nRequires ``settings:view`` permission.","operationId":"list_process_mappings_api_v1_admin_process_mappings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AdminProcessMappingResponse"},"type":"array","title":"Response List Process Mappings Api V1 Admin Process Mappings Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"post":{"tags":["admin-dropdowns"],"summary":"Create Process Mapping","description":"Create a new process mapping.\n\nValidates that all dropdown references are valid and belong to the\ncorrect categories. Requires ``settings:create`` permission.","operationId":"create_process_mapping_api_v1_admin_process_mappings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProcessMappingCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProcessMappingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/process-mappings/{mapping_id}":{"delete":{"tags":["admin-dropdowns"],"summary":"Delete Process Mapping","description":"Delete a process mapping.\n\nRequires ``settings:delete`` permission.","operationId":"delete_process_mapping_api_v1_admin_process_mappings__mapping_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Mapping Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/email/test":{"post":{"tags":["admin-email"],"summary":"Send Test Email","description":"Send a test email to verify SendGrid configuration.\n\nOnly available in development and staging environments.","operationId":"send_test_email_api_v1_admin_email_test_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/pricing-config":{"get":{"tags":["admin-pricing"],"summary":"Get Active Config","description":"Return the currently active pricing config.\n\nRequires ``settings:view`` permission.","operationId":"get_active_config_api_v1_admin_pricing_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingConfigResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"put":{"tags":["admin-pricing"],"summary":"Update Config","description":"Create a new pricing config version, deactivating the current one.\n\nThe ``config`` field must contain the full config document. The new\nversion number is auto-incremented. Invalidates the pricing cache.\n\nRequires ``settings:edit`` permission.","operationId":"update_config_api_v1_admin_pricing_config_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingConfigUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/pricing-config/history":{"get":{"tags":["admin-pricing"],"summary":"Get Config History","description":"List all pricing config versions ordered by version DESC.\n\nRequires ``settings:view`` permission.","operationId":"get_config_history_api_v1_admin_pricing_config_history_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PricingConfigHistoryItem"},"type":"array","title":"Response Get Config History Api V1 Admin Pricing Config History Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/pricing-config/rollback/{config_id}":{"post":{"tags":["admin-pricing"],"summary":"Rollback Config","description":"Rollback to a previous pricing config version.\n\nDeactivates the currently active config and reactivates the target\nversion. Invalidates the pricing cache.\n\nRequires ``settings:edit`` permission.","operationId":"rollback_config_api_v1_admin_pricing_config_rollback__config_id__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"config_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Config Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/pricing-calibration":{"get":{"tags":["admin-pricing"],"summary":"List Pricing Calibration","description":"List Track B calibration buckets with summary stats.\n\nSurfaces bucket coverage on the admin Pricing Settings page (Phase 6\nUI). Each row reports median uplift, Q1/Q3, sample size, confidence\ntier, and how many samples were flagged as outliers.\n\nAuth: ``settings:view``.","operationId":"list_pricing_calibration_api_v1_admin_pricing_calibration_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"process","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional filter by process slug (e.g. 'cnc_machining').","title":"Process"},"description":"Optional filter by process slug (e.g. 'cnc_machining')."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PricingCalibrationResponse"},"title":"Response List Pricing Calibration Api V1 Admin Pricing Calibration Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/pricing-calibration/recompute":{"post":{"tags":["admin-pricing"],"summary":"Recompute Pricing Calibration","description":"Manually trigger a full recompute of all Track B calibration buckets.\n\nEquivalent to the Phase 5 backfill script. Use cases:\n  - Force a refresh after editing the Track A pricing config\n    (the calibration rows reference older config versions)\n  - Diagnostics / cache-busting after data fixes\n  - Initial seeding on a fresh environment\n\n``recompute_bucket`` itself only flushes — this endpoint owns the\ntransaction boundary and commits at the end so all bucket upserts\npersist atomically.\n\nAuth: ``settings:edit``.","operationId":"recompute_pricing_calibration_api_v1_admin_pricing_calibration_recompute_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecomputeReport"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/pricing/backtest-runs":{"get":{"tags":["admin-pricing-backtest"],"summary":"List Backtest Runs","description":"List historical pricing-engine-v2 backtest runs, newest-first.\n\nReturns an empty list (not 404) when the output directory does not\nexist or contains no runs — this is the expected state on a fresh\ncontainer before any backtest has been executed.","operationId":"list_backtest_runs_api_v1_admin_pricing_backtest_runs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/BacktestRunSummary"},"type":"array","title":"Response List Backtest Runs Api V1 Admin Pricing Backtest Runs Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/pricing/backtest-runs/{run_id}":{"get":{"tags":["admin-pricing-backtest"],"summary":"Get Backtest Run","description":"Return full detail for one backtest run.\n\nCarries the markdown report inline plus URLs to the CSV streaming\nsub-endpoint and (when available) the distribution histogram PNG.","operationId":"get_backtest_run_api_v1_admin_pricing_backtest_runs__run_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestRunDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/pricing/backtest-runs/{run_id}/csv":{"get":{"tags":["admin-pricing-backtest"],"summary":"Stream Backtest Run Csv","description":"Stream the per-part backtest CSV for one run.\n\nUses ``StreamingResponse`` over ``FileResponse`` so the response\nexposes a stable ``Content-Disposition: attachment`` header and\nkeeps a single representation of the CSV content type. Files are\ntypically small (<5 MB) — chunking is for memory hygiene, not\nbandwidth.","operationId":"stream_backtest_run_csv_api_v1_admin_pricing_backtest_runs__run_id__csv_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/pricing/backtest-runs/{run_id}/distribution.png":{"get":{"tags":["admin-pricing-backtest"],"summary":"Get Backtest Run Distribution Png","description":"Return the matplotlib distribution PNG for a run.\n\nOnly present when the harness ran in an env with matplotlib\ninstalled; otherwise this returns 404. The list/detail endpoints\nsurface the URL conditionally so the admin UI knows when to render\na thumbnail link.","operationId":"get_backtest_run_distribution_png_api_v1_admin_pricing_backtest_runs__run_id__distribution_png_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/notifications/":{"get":{"tags":["admin-notifications"],"summary":"List Admin Notifications","operationId":"list_admin_notifications_api_v1_admin_notifications__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"unread_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Unread Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/notifications/unread-count":{"get":{"tags":["admin-notifications"],"summary":"Get Admin Unread Count","operationId":"get_admin_unread_count_api_v1_admin_notifications_unread_count_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreadCountResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/notifications/{notification_id}/read":{"patch":{"tags":["admin-notifications"],"summary":"Mark Admin Read","operationId":"mark_admin_read_api_v1_admin_notifications__notification_id__read_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/notifications/read-all":{"patch":{"tags":["admin-notifications"],"summary":"Mark All Admin Read","operationId":"mark_all_admin_read_api_v1_admin_notifications_read_all_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Mark All Admin Read Api V1 Admin Notifications Read All Patch"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/payments/":{"get":{"tags":["admin-payments"],"summary":"List Payments","description":"List all payments with optional status, method, and project filtering.\n\nRequires ``payments:view`` permission.","operationId":"list_payments_api_v1_admin_payments__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by payment status","title":"Status"},"description":"Filter by payment status"},{"name":"method","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by payment method","title":"Method"},"description":"Filter by payment method"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by project ID","title":"Project Id"},"description":"Filter by project ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminPaymentListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}":{"get":{"tags":["admin-payments"],"summary":"Get Payment Detail","description":"Get full payment detail including invoice and PO document download URL.\n\nRequires ``payments:view`` permission.","operationId":"get_payment_detail_api_v1_admin_payments__payment_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/confirm-po":{"post":{"tags":["admin-payments"],"summary":"Confirm Po","description":"Confirm a Purchase Order — advances project to ORDER_CONFIRMED.\n\nThe B2B \"we have your PO, work can begin\" event. Decoupled from\ninvoice-paid semantics: this endpoint advances the project\nlifecycle and fires an admin in-app notification, but DOES NOT\ntouch ``payment.status`` or ``invoice.status``, and does NOT email\nthe customer. The customer's payment is still expected on the\nagreed Net-30/60/90 terms.\n\nUse ``POST /admin/payments/{id}/mark-invoice-paid`` separately\nwhen the customer's check actually clears (typically weeks or\nmonths later).\n\nIdempotent: if the project is already past ``PAYMENT_PENDING``\nthis is a successful no-op.\n\nRequires ``payments:edit`` permission.","operationId":"confirm_po_api_v1_admin_payments__payment_id__confirm_po_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminConfirmPORequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/mark-invoice-paid":{"post":{"tags":["admin-payments"],"summary":"Mark Invoice Paid","description":"Mark an issued invoice as paid — financial closure.\n\nSets ``payment.status = COMPLETED``, ``invoice.status = PAID``,\nrecords ``paid_at`` on both. Fires the customer \"Payment\nConfirmed\" email + admin \"Payment Received\" notification + Stripe\nTax transaction + Temporal invoice-PDF regeneration. Does NOT\ntouch ``project.status`` — the admin controls lifecycle separately\nvia ``confirm-po`` and the Start Production / Mark Shipped /\nMark Completed buttons.\n\nMost commonly called 30-90 days AFTER ``confirm-po``, when the\ncustomer's Net-30/60/90 payment arrives.\n\nRequires ``payments:edit`` permission.","operationId":"mark_invoice_paid_api_v1_admin_payments__payment_id__mark_invoice_paid_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/mark-received":{"patch":{"tags":["admin-payments"],"summary":"Mark Payment Received","description":"[DEPRECATED] Combined forwarder for the two new lifecycle actions.\n\nPre-decoupling, this endpoint did both events in one shot:\nadvancing the project past PAYMENT_PENDING and marking the invoice\nas PAID. That conflation was wrong for PO customers on\nNet-30/60/90 terms (work was unblocked weeks before the check\narrived but the email said \"Payment Confirmed\").\n\nModern callers should use:\n  * ``POST /admin/payments/{id}/confirm-po`` to advance the project.\n  * ``POST /admin/payments/{id}/mark-invoice-paid`` when the payment\n    actually arrives.\n\nThis forwarder calls both in sequence so in-flight automation\ndoesn't break. Logs a deprecation warning on every call; the\nendpoint will be removed in a follow-up PR once prod log scrape\nshows no callers remain.\n\nRequires ``payments:edit`` permission.","operationId":"mark_payment_received_api_v1_admin_payments__payment_id__mark_received_patch","deprecated":true,"security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/issue-invoice":{"post":{"tags":["admin-payments"],"summary":"Issue Po Invoice","description":"Issue a pre-payment invoice for a Purchase Order.\n\nWhen a customer pays by PO, the business needs to send them an\ninvoice BEFORE payment arrives so their AP team can cut the check.\nThis endpoint generates the invoice (status=ISSUED) without touching\nthe payment's status or the project's state. The customer will see\nthe invoice in their dashboard and can forward to AP. When payment\nlater arrives, ``mark-received`` flips the same invoice to PAID.\n\n``exclude_tax=true`` renders the invoice tax-free (e.g. tax-exempt org,\nor tax accidentally added to the quote) without touching the quote.\n\nOptional ``additional_line_items_post_tax`` (request body) adds admin-entered\npost-tax extras (shipping, …) to the invoice — billed beyond the quote,\nsummed into the total after tax, quote untouched.\n\n``acknowledge_total_drift=true`` bypasses the reconciliation gate below.\nUse it when the recorded settlement genuinely differs from the quote (the\nnormal case for a MANUAL out-of-band payment); leave it false so a stale\n``quote.total_amount`` can never silently become a bill.\n\nGates: PO method, payment PENDING, PO number submitted, no invoice\nalready issued, recorded amount reconciles with the quote (400\n``quote_total_drift`` otherwise). Requires ``payments:edit`` permission.","operationId":"issue_po_invoice_api_v1_admin_payments__payment_id__issue_invoice_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}},{"name":"exclude_tax","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Exclude Tax"}},{"name":"acknowledge_total_drift","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Acknowledge Total Drift"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InvoiceLineItemsBody"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPaymentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/invoice-pdf":{"get":{"tags":["admin-payments"],"summary":"Get Invoice Pdf","description":"Get presigned download URL for an invoice PDF.","operationId":"get_invoice_pdf_api_v1_admin_payments__payment_id__invoice_pdf_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payments/{payment_id}/regenerate-invoice-pdf":{"post":{"tags":["admin-payments"],"summary":"Regenerate Invoice Pdf","description":"Regenerate the invoice PDF synchronously and return the fresh invoice.\n\nApplies any requested tax-mode / post-tax line-item adjustments (gated to\nPO + unpaid invoices), then re-renders the invoice PDF **inline** and\noverwrites the existing object at the same R2 key. Because the render\ncompletes before this returns, the response carries the up-to-date invoice\n(with a freshly-signed PDF URL) and the next download is guaranteed current\n— no client-side polling for ``pdf_generated_at`` to advance. Useful after\ntemplate changes (e.g. adding the Remit To block) or after corrections to\nquote line items on an already-issued invoice.\n\n``exclude_tax`` (optional) flips the invoice's tax mode before\nre-rendering — ``true`` removes tax, ``false`` restores it from the\nPayment. ``additional_line_items_post_tax`` (optional body) replaces the\ninvoice's post-tax extras (``[]`` clears, omitted = unchanged). Both are\ngated to PO + unpaid invoices. Omit both to re-render unchanged.\n\nRequires ``payments:edit`` permission.","operationId":"regenerate_invoice_pdf_api_v1_admin_payments__payment_id__regenerate_invoice_pdf_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"payment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Payment Id"}},{"name":"exclude_tax","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Exclude Tax"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InvoiceLineItemsBody"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/packing-slip":{"post":{"tags":["admin-packing-slips"],"summary":"Generate Packing Slip","description":"Generate (or regenerate) the packing slip for an order.\n\nIdempotent — if a packing slip already exists for the project, this\nupdates the admin-input override fields and re-renders the PDF\n(preserving the original ``PS-{YYYY}-{NNNNN}`` number).\n\nReturns 202 immediately; the Temporal workflow handles the actual\nPDF render + R2 upload in the background. Frontend re-fetches the\nparent admin-payment detail query to see the populated PDF URL.\n\nRequires ``payments:edit`` permission.","operationId":"generate_packing_slip_api_v1_admin_projects__project_id__packing_slip_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackingSlipCreate"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackingSlipGenerateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["admin-packing-slips"],"summary":"Get Packing Slip","description":"Get the packing slip metadata + presigned PDF URL for a project.","operationId":"get_packing_slip_api_v1_admin_projects__project_id__packing_slip_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackingSlipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/packing-slip-pdf":{"get":{"tags":["admin-packing-slips"],"summary":"Get Packing Slip Pdf","description":"Get presigned download URL for the packing slip PDF (admin only).","operationId":"get_packing_slip_pdf_api_v1_admin_projects__project_id__packing_slip_pdf_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/roles":{"get":{"tags":["admin-roles"],"summary":"List Roles","description":"List all roles with permission and admin counts.\n\nRequires ``settings:view`` permission.","operationId":"list_roles_api_v1_admin_roles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RoleResponse"},"type":"array","title":"Response List Roles Api V1 Admin Roles Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/roles/{role_id}":{"get":{"tags":["admin-roles"],"summary":"Get Role Detail","description":"Get full role detail with permissions and assigned admins.\n\nRequires ``settings:view`` permission.","operationId":"get_role_detail_api_v1_admin_roles__role_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Role Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-roles"],"summary":"Update Role Permissions","description":"Update a role's permissions.\n\nDoes not use ``require_permission`` -- the service enforces that only\nsuper-admins can modify role permissions. The ``super_admin`` role\nitself cannot be modified.","operationId":"update_role_permissions_api_v1_admin_roles__role_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Role Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolePermissionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/permissions":{"get":{"tags":["admin-roles"],"summary":"List Permissions","description":"List all permissions grouped by resource.\n\nRequires ``settings:view`` permission.","operationId":"list_permissions_api_v1_admin_permissions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PermissionGroupResponse"},"type":"array","title":"Response List Permissions Api V1 Admin Permissions Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/projects/{project_id}/shipping-workspace":{"get":{"tags":["admin-shipping-logistics"],"summary":"Get Shipping Workspace","description":"Return the drawer-ready inbound/outbound shipping workspace.","operationId":"get_shipping_workspace_api_v1_admin_projects__project_id__shipping_workspace_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingWorkspaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/supplier-orders/{supplier_order_id}/inbound-shipments":{"post":{"tags":["admin-shipping-logistics"],"summary":"Create Inbound Shipment","operationId":"create_inbound_shipment_api_v1_admin_supplier_orders__supplier_order_id__inbound_shipments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"supplier_order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Supplier Order Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundShipmentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/inbound-shipments/{inbound_shipment_id}":{"patch":{"tags":["admin-shipping-logistics"],"summary":"Update Inbound Shipment","operationId":"update_inbound_shipment_api_v1_admin_inbound_shipments__inbound_shipment_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"inbound_shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Inbound Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundShipmentUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-shipping-logistics"],"summary":"Delete Inbound Shipment","operationId":"delete_inbound_shipment_api_v1_admin_inbound_shipments__inbound_shipment_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"inbound_shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Inbound Shipment Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/inbound-shipments/{inbound_shipment_id}/refresh-tracking":{"post":{"tags":["admin-shipping-logistics"],"summary":"Refresh Inbound Tracking","operationId":"refresh_inbound_tracking_api_v1_admin_inbound_shipments__inbound_shipment_id__refresh_tracking_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"inbound_shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Inbound Shipment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/outbound-shipment":{"post":{"tags":["admin-shipping-logistics"],"summary":"Create Or Update Outbound Shipment","operationId":"create_or_update_outbound_shipment_api_v1_admin_projects__project_id__outbound_shipment_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/outbound-shipment":{"patch":{"tags":["admin-shipping-logistics"],"summary":"Update Outbound Shipment","operationId":"update_outbound_shipment_api_v1_admin_shipments__shipment_id__outbound_shipment_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/packages":{"put":{"tags":["admin-shipping-logistics"],"summary":"Replace Outbound Packages","operationId":"replace_outbound_packages_api_v1_admin_shipments__shipment_id__packages_put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentPackageListUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/seed-packages-from-inbound":{"post":{"tags":["admin-shipping-logistics"],"summary":"Seed Packages From Inbound","operationId":"seed_packages_from_inbound_api_v1_admin_shipments__shipment_id__seed_packages_from_inbound_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/refresh-tracking":{"post":{"tags":["admin-shipping-logistics"],"summary":"Refresh Outbound Tracking","operationId":"refresh_outbound_tracking_api_v1_admin_shipments__shipment_id__refresh_tracking_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/labels":{"post":{"tags":["admin-shipping-logistics"],"summary":"Purchase Labels","operationId":"purchase_labels_api_v1_admin_shipments__shipment_id__labels_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CarrierActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/packages/{package_id}/void-label":{"post":{"tags":["admin-shipping-logistics"],"summary":"Void Package Label","operationId":"void_package_label_api_v1_admin_shipments__shipment_id__packages__package_id__void_label_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}},{"name":"package_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Package Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/pickup":{"post":{"tags":["admin-shipping-logistics"],"summary":"Schedule Pickup","operationId":"schedule_pickup_api_v1_admin_shipments__shipment_id__pickup_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentPickupCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentPickupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/packing-slip":{"post":{"tags":["admin-shipping-logistics"],"summary":"Generate Shipment Packing Slip","description":"Generate package-aware packing slip from the outbound shipment context.","operationId":"generate_shipment_packing_slip_api_v1_admin_shipments__shipment_id__packing_slip_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackingSlipCreate"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackingSlipGenerateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-shipping-logistics"],"summary":"Delete Shipment Packing Slip","operationId":"delete_shipment_packing_slip_api_v1_admin_shipments__shipment_id__packing_slip_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/":{"get":{"tags":["admin-shipments"],"summary":"List Shipments","description":"List all shipments with pagination and optional status/project filter.","operationId":"list_shipments_api_v1_admin_shipments__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by shipment status","title":"Status"},"description":"Filter by shipment status"},{"name":"public_status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by public shipment state: preparing, shipped, delivered, exception","title":"Public Status"},"description":"Filter by public shipment state: preparing, shipped, delivered, exception"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by project ID","title":"Project Id"},"description":"Filter by project ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminShipmentListItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["admin-shipments"],"summary":"Create Shipment","description":"Create a shipment for a project.","operationId":"create_shipment_api_v1_admin_shipments__post","security":[{"OAuth2PasswordBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}":{"get":{"tags":["admin-shipments"],"summary":"Get Shipment","description":"Get shipment detail with tracking events.","operationId":"get_shipment_api_v1_admin_shipments__shipment_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-shipments"],"summary":"Update Shipment","description":"Update shipment details. Validates status transitions.","operationId":"update_shipment_api_v1_admin_shipments__shipment_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/shipments/{shipment_id}/events":{"post":{"tags":["admin-shipments"],"summary":"Add Event","description":"Add a tracking event to a shipment.","operationId":"add_event_api_v1_admin_shipments__shipment_id__events_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"shipment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Shipment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentEventCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentEventResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/waitlist/":{"get":{"tags":["admin-waitlist"],"summary":"List Waitlist Entries","description":"List all waitlist entries with optional search and status filtering.\n\nRequires ``waitlist:view`` permission.","operationId":"list_waitlist_entries_api_v1_admin_waitlist__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by email, first name, last name, or company","title":"Search"},"description":"Search by email, first name, last name, or company"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by waitlist status (pending, approved, denied, converted)","title":"Status"},"description":"Filter by waitlist status (pending, approved, denied, converted)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_WaitlistEntryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/waitlist/stats":{"get":{"tags":["admin-waitlist"],"summary":"Get Waitlist Stats","description":"Return aggregate waitlist counts by status.\n\nRequires ``waitlist:view`` permission.","operationId":"get_waitlist_stats_api_v1_admin_waitlist_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistStatsResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/waitlist/{entry_id}":{"get":{"tags":["admin-waitlist"],"summary":"Get Waitlist Entry","description":"Get a single waitlist entry by ID.\n\nRequires ``waitlist:view`` permission.","operationId":"get_waitlist_entry_api_v1_admin_waitlist__entry_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entry_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Entry Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin-waitlist"],"summary":"Update Waitlist Entry","description":"Update admin notes or status on a waitlist entry.\n\nOnly ``\"denied\"`` is accepted as a status transition via PATCH;\napproval has its own dedicated endpoint that also triggers the\ninvite email.\n\nRequires ``waitlist:edit`` permission.","operationId":"update_waitlist_entry_api_v1_admin_waitlist__entry_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entry_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Entry Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-waitlist"],"summary":"Delete Waitlist Entry","description":"Hard-delete a waitlist entry.\n\nRequires ``waitlist:delete`` permission.","operationId":"delete_waitlist_entry_api_v1_admin_waitlist__entry_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entry_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Entry Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/waitlist/{entry_id}/approve":{"post":{"tags":["admin-waitlist"],"summary":"Approve Waitlist Entry","description":"Approve a waitlist entry: generate invite token, send invite email.\n\nRequires ``waitlist:edit`` permission.","operationId":"approve_waitlist_entry_api_v1_admin_waitlist__entry_id__approve_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entry_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Entry Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/waitlist/{entry_id}/resend-invite":{"post":{"tags":["admin-waitlist"],"summary":"Resend Waitlist Invite","description":"Re-send an invite email for an already-approved entry.\n\nRegenerates the invite token and resets the expiry timer.\nRequires ``waitlist:edit`` permission.","operationId":"resend_waitlist_invite_api_v1_admin_waitlist__entry_id__resend_invite_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entry_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Entry Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/ai/status":{"get":{"tags":["admin-ai"],"summary":"Get Ai Status","description":"Get AI service health: budget remaining, daily spend, API key status.","operationId":"get_ai_status_api_v1_admin_ai_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/parts/{part_id}/dfm-check":{"post":{"tags":["admin-dfm"],"summary":"Admin Run Dfm Check","description":"Recalculate DFM rules + cost/lead time for any part (admin only).\n\nMirrors the user-facing ``POST /parts/{part_id}/dfm-check`` but skips\nthe project-ownership check since admins manage parts across all\ncustomers. Delegates to the same ``_run_dfm_check_for_part`` core\nhelper so pricing logic stays in one place.\n\nAuth: requires the ``projects:edit`` permission on the admin's role.","operationId":"admin_run_dfm_check_api_v1_admin_parts__part_id__dfm_check_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"preview","in":"query","required":false,"schema":{"type":"boolean","description":"Cost/lead-time preview only","default":false,"title":"Preview"},"description":"Cost/lead-time preview only"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DfmCheckRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DfmCheckResponse"},{"$ref":"#/components/schemas/CostPreviewResponse"}],"title":"Response Admin Run Dfm Check Api V1 Admin Parts  Part Id  Dfm Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/pricing-prediction":{"get":{"tags":["admin-dfm"],"summary":"Get Pricing Prediction","description":"Return Track A + Track B pricing prediction for a part at given quantity.\n\nTrack A is the deterministic cost-floor output from\n``calculate_cost`` (unit_price + breakdown).\n\nTrack B is the empirical predictor — populated when the\n(process, complexity, qty) bucket has ``sample_size >= 3`` calibration\nsamples. Returns ``None`` for cold-start buckets (Phase 2 wires\n`track_b` onto the cost preview response).\n\nRead-only: ``preview=True`` takes the cost-preview branch which never\npersists anything. Auth: ``projects:view``.","operationId":"get_pricing_prediction_api_v1_admin_parts__part_id__pricing_prediction_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"quantity","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Order quantity","default":1,"title":"Quantity"},"description":"Order quantity"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostPreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/dfm-synthesis":{"post":{"tags":["admin-dfm"],"summary":"Trigger Dfm Synthesis","description":"Manually re-trigger AI DFM synthesis for a part.\n\nRuns Claude AI to synthesize DFM findings into human-readable\nrecommendations. Stores result in CadFileVersion.ai_dfm_synthesis.","operationId":"trigger_dfm_synthesis_api_v1_admin_parts__part_id__dfm_synthesis_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Trigger Dfm Synthesis Api V1 Admin Parts  Part Id  Dfm Synthesis Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/quote-estimate":{"post":{"tags":["admin-dfm"],"summary":"Generate Quote Estimate","description":"Generate AI quote estimation for a part.\n\nAdmin-triggered. Stores the estimate in Quote.ai_estimate and sets\nai_estimate_generated_at. The is_human_reviewed gate prevents the\nquote from being sent to the user until an admin reviews it.","operationId":"generate_quote_estimate_api_v1_admin_parts__part_id__quote_estimate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Generate Quote Estimate Api V1 Admin Parts  Part Id  Quote Estimate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/ai/budget":{"get":{"tags":["admin-ai"],"summary":"Get Ai Budget Status","description":"Get current AI budget status (daily spend, remaining, cap).","operationId":"get_ai_budget_status_api_v1_admin_ai_budget_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Ai Budget Status Api V1 Admin Ai Budget Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/parts/{part_id}/agent-actions":{"get":{"tags":["admin-agent-actions"],"summary":"List Agent Actions","description":"List agent actions for a part, ordered by most recent first.","operationId":"list_agent_actions_api_v1_admin_parts__part_id__agent_actions_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentActionListItem"},"title":"Response List Agent Actions Api V1 Admin Parts  Part Id  Agent Actions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent-actions/{action_id}":{"get":{"tags":["admin-agent-actions"],"summary":"Get Agent Action","description":"Get full detail of a single agent action.","operationId":"get_agent_action_api_v1_admin_agent_actions__action_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"action_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Action Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/conversation":{"get":{"tags":["admin-ops-agent"],"summary":"Get Conversation","description":"The admin's rolling thread, newest-last, paginated backwards via\n``before`` (message id).","operationId":"get_conversation_api_v1_admin_agent_conversation_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"before","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Before"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAgentConversationPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/messages":{"post":{"tags":["admin-ops-agent"],"summary":"Post Message","description":"One agent turn, streamed as SSE (event vocabulary: ``agent_*``).","operationId":"post_message_api_v1_admin_agent_messages_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAgentTurnRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/agent/nudges":{"get":{"tags":["admin-ops-agent"],"summary":"Get Nudges","description":"Deterministic nudge candidates for the admin's current page.","operationId":"get_nudges_api_v1_admin_agent_nudges_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"route","in":"query","required":false,"schema":{"type":"string","default":"","title":"Route"}},{"name":"entity_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"}},{"name":"entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAgentNudgesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/actions/pending":{"get":{"tags":["admin-ops-agent"],"summary":"List Pending Proposals","description":"This admin's open Tier-B proposals (single + batch) for the cards.\nLazily reaps expired rows so dead cards leave the list.","operationId":"list_pending_proposals_api_v1_admin_agent_actions_pending_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Pending Proposals Api V1 Admin Agent Actions Pending Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/agent/actions/{action_id}/confirm":{"post":{"tags":["admin-ops-agent"],"summary":"Confirm Proposal","description":"Execute a Tier-B proposal after re-validation (TTL, freshness,\nidempotency, permission). The ONLY execution path for Tier B.","operationId":"confirm_proposal_api_v1_admin_agent_actions__action_id__confirm_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"action_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Action Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Confirm Proposal Api V1 Admin Agent Actions  Action Id  Confirm Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/actions/{action_id}/reject":{"post":{"tags":["admin-ops-agent"],"summary":"Reject Proposal","operationId":"reject_proposal_api_v1_admin_agent_actions__action_id__reject_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"action_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Action Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/actions/{action_id}/undo":{"post":{"tags":["admin-ops-agent"],"summary":"Undo Tier A","description":"Single-step Tier-A undo (re-applies prior values via the service).","operationId":"undo_tier_a_api_v1_admin_agent_actions__action_id__undo_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"action_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Action Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Undo Tier A Api V1 Admin Agent Actions  Action Id  Undo Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/agent/nudges/dismiss":{"post":{"tags":["admin-ops-agent"],"summary":"Dismiss Nudge","description":"Server-side dismissal — survives the frontend's refetch cycle.","operationId":"dismiss_nudge_api_v1_admin_agent_nudges_dismiss_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAgentNudgeDismissRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/v1/admin/parts/{part_id}/manufacturing-package":{"post":{"tags":["admin-manufacturing-packages"],"summary":"Generate Manufacturing Package","description":"Generate a manufacturing package for a part using AI.","operationId":"generate_manufacturing_package_api_v1_admin_parts__part_id__manufacturing_package_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingPackageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["admin-manufacturing-packages"],"summary":"Get Manufacturing Package","description":"Get the latest manufacturing package for a part.","operationId":"get_manufacturing_package_api_v1_admin_parts__part_id__manufacturing_package_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ManufacturingPackageResponse"},{"type":"null"}],"title":"Response Get Manufacturing Package Api V1 Admin Parts  Part Id  Manufacturing Package Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/manufacturing-packages/{package_id}/approve":{"post":{"tags":["admin-manufacturing-packages"],"summary":"Approve Package","description":"Approve a pending manufacturing package.","operationId":"approve_package_api_v1_admin_manufacturing_packages__package_id__approve_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"package_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Package Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingPackageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/manufacturing-packages/{package_id}/reject":{"post":{"tags":["admin-manufacturing-packages"],"summary":"Reject Package","description":"Reject a pending manufacturing package with reason.","operationId":"reject_package_api_v1_admin_manufacturing_packages__package_id__reject_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"package_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Package Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingPackageApproval"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingPackageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/shop-drawing/generate":{"post":{"tags":["admin-shop-drawings"],"summary":"Generate Shop Drawing","description":"Kick off a shop-drawing generation workflow.\n\nDeduplication:\n  * Compute the annotations hash before touching Temporal.\n  * If the most recent drawing already carries the same hash and is\n    already ``ready`` OR ``generating``, return its identifiers\n    without starting a new workflow.\n  * Otherwise create a fresh ``pending`` row and start a workflow\n    whose id is ``mfg-drawing-{version_id}-{hash[:16]}``. Temporal's\n    ``REJECT_DUPLICATE`` reuse policy guarantees that concurrent\n    POSTs collapse onto a single workflow even if we raced the DB\n    check.","operationId":"generate_shop_drawing_api_v1_admin_parts__part_id__shop_drawing_generate_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingDrawingGenerateRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManufacturingDrawingGenerateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-shop-drawings"],"summary":"Cancel Shop Drawing Generation","description":"Cancel a running shop-drawing workflow, if any.\n\nNo-op when there is no in-flight generation — we never 404 here so\nthe admin UI can safely \"cancel before every Generate\" without\nraising noise.","operationId":"cancel_shop_drawing_generation_api_v1_admin_parts__part_id__shop_drawing_generate_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/shop-drawing":{"get":{"tags":["admin-shop-drawings"],"summary":"Get Shop Drawing","description":"Return the latest drawing + computed_status + coverage summary.\n\nReturns ``null`` (not 404) when the part has never had a shop drawing\ngenerated -- the admin UI uses this as the \"first-visit empty state\"\nsignal.","operationId":"get_shop_drawing_api_v1_admin_parts__part_id__shop_drawing_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ManufacturingDrawingResponse"},{"type":"null"}],"title":"Response Get Shop Drawing Api V1 Admin Parts  Part Id  Shop Drawing Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/shop-drawing/download-url":{"get":{"tags":["admin-shop-drawings"],"summary":"Get Shop Drawing Download Url","description":"Presigned GET URL (5 min TTL) for downloading the PDF.\n\nResponse: ``{\"url\": ..., \"expires_at\": ..., \"filename\": ...}``.","operationId":"get_shop_drawing_download_url_api_v1_admin_parts__part_id__shop_drawing_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Shop Drawing Download Url Api V1 Admin Parts  Part Id  Shop Drawing Download Url Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/shop-drawing/preview-url":{"get":{"tags":["admin-shop-drawings"],"summary":"Get Shop Drawing Preview Url","description":"Presigned GET URL (15 min TTL) for inline iframe display.","operationId":"get_shop_drawing_preview_url_api_v1_admin_parts__part_id__shop_drawing_preview_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Shop Drawing Preview Url Api V1 Admin Parts  Part Id  Shop Drawing Preview Url Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/parts/{part_id}/annotations":{"get":{"tags":["admin-annotations"],"summary":"Get Part Annotations","description":"Return all user annotations for a part, grouped by feature_id.\n\nRequires ``projects:view`` permission.","operationId":"get_part_annotations_api_v1_admin_parts__part_id__annotations_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"part_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Part Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartAnnotationBundle"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/rfq-package/preview":{"get":{"tags":["admin-rfq-package"],"summary":"Rfq Package Preview","description":"Return the per-part decision so the dialog can render truthfully.\n\nCheap query — does not download from R2, only inspects flags on the\nPart + ManufacturingDrawing rows already loaded for the project.","operationId":"rfq_package_preview_api_v1_admin_projects__project_id__rfq_package_preview_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RfqPackagePreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/rfq-package/zip":{"get":{"tags":["admin-rfq-package"],"summary":"Download Rfq Package Zip","description":"Build and return the RFQ package ZIP for ``project_id``.\n\nReturned as a single buffered ``application/zip`` response. Typical\nprojects have 10-15 parts with small files — streaming the assembly\nisn't worth the complexity.\n\n``include_originals`` defaults to **False**: the archive ships\nredacted PDFs only, so it is safe to forward to a shop. Passing\n``true`` opts into the raw both-variants bundle and is audit-logged.","operationId":"download_rfq_package_zip_api_v1_admin_projects__project_id__rfq_package_zip_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"include_originals","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Originals"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/rfq-package/draft-email":{"post":{"tags":["admin-rfq-package"],"summary":"Draft Rfq Package Email","description":"Draft a supplier RFQ email for ``project_id`` via Claude.","operationId":"draft_rfq_package_email_api_v1_admin_projects__project_id__rfq_package_draft_email_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Draft Rfq Package Email Api V1 Admin Projects  Project Id  Rfq Package Draft Email Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/design-files/zip":{"get":{"tags":["admin-rfq-package"],"summary":"Download Design Files Zip","description":"Stream the design-files ZIP for ``project_id``.\n\nBundles every part's latest CAD version + drawing, the project\ndocuments, and the assembly file.\n\n``variant`` defaults to ``supplier_safe``: PDFs are redacted variants\nonly, with omissions listed in ``MANIFEST.txt``. ``raw`` ships the\nunredacted originals for internal use and is audit-logged with the\nrequesting admin's id, so a manual leak is traceable after the fact.\n\nThe archive is **streamed** chunk-wise: the project is loaded and\nplanned into plain ``(zip_path, source)`` entries up front (while the\nDB session is live), then each R2 object is read and zipped lazily so\npeak memory stays bounded even when a part carries a multi-GB CAD\nfile. This keeps a large download from OOMing the worker or stalling\nother admin workflows.","operationId":"download_design_files_zip_api_v1_admin_projects__project_id__design_files_zip_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"variant","in":"query","required":false,"schema":{"enum":["supplier_safe","raw"],"type":"string","default":"supplier_safe","title":"Variant"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/assembly-file":{"get":{"tags":["admin-assembly-files"],"summary":"Admin Get Assembly File","description":"Return any project's current assembly file (admin RBAC bypasses ownership).\n\nIncludes a presigned GET URL when status is ``validated``. Returns\nnull if no assembly file exists for the project.","operationId":"admin_get_assembly_file_api_v1_admin_projects__project_id__assembly_file_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AssemblyFileResponse"},{"type":"null"}],"title":"Response Admin Get Assembly File Api V1 Admin Projects  Project Id  Assembly File Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-assembly-files"],"summary":"Admin Delete Assembly File","operationId":"admin_delete_assembly_file_api_v1_admin_projects__project_id__assembly_file_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/assembly-file/initiate-upload":{"post":{"tags":["admin-assembly-files"],"summary":"Admin Initiate Assembly Upload","operationId":"admin_initiate_assembly_upload_api_v1_admin_projects__project_id__assembly_file_initiate_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateAssemblyUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateAssemblyUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/assembly-file/upload":{"post":{"tags":["admin-assembly-files"],"summary":"Admin Upload Assembly File","operationId":"admin_upload_assembly_file_api_v1_admin_projects__project_id__assembly_file_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_upload_assembly_file_api_v1_admin_projects__project_id__assembly_file_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Admin Upload Assembly File Api V1 Admin Projects  Project Id  Assembly File Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/assembly-file/confirm-upload":{"post":{"tags":["admin-assembly-files"],"summary":"Admin Confirm Assembly Upload","operationId":"admin_confirm_assembly_upload_api_v1_admin_projects__project_id__assembly_file_confirm_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmAssemblyUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssemblyFileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents":{"get":{"tags":["admin-project-documents"],"summary":"Admin List Project Documents","operationId":"admin_list_project_documents_api_v1_admin_projects__project_id__documents_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminProjectDocumentResponse"},"title":"Response Admin List Project Documents Api V1 Admin Projects  Project Id  Documents Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/initiate-upload":{"post":{"tags":["admin-project-documents"],"summary":"Admin Initiate Project Document Upload","operationId":"admin_initiate_project_document_upload_api_v1_admin_projects__project_id__documents_initiate_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateProjectDocumentUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateProjectDocumentUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/{document_id}/upload":{"post":{"tags":["admin-project-documents"],"summary":"Admin Upload Project Document","operationId":"admin_upload_project_document_api_v1_admin_projects__project_id__documents__document_id__upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_upload_project_document_api_v1_admin_projects__project_id__documents__document_id__upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Admin Upload Project Document Api V1 Admin Projects  Project Id  Documents  Document Id  Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/confirm-upload":{"post":{"tags":["admin-project-documents"],"summary":"Admin Confirm Project Document Upload","operationId":"admin_confirm_project_document_upload_api_v1_admin_projects__project_id__documents_confirm_upload_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmProjectDocumentUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDocumentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/{document_id}/download-url":{"get":{"tags":["admin-project-documents"],"summary":"Admin Get Project Document Download Url","operationId":"admin_get_project_document_download_url_api_v1_admin_projects__project_id__documents__document_id__download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Admin Get Project Document Download Url Api V1 Admin Projects  Project Id  Documents  Document Id  Download Url Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/{document_id}/redacted-download-url":{"get":{"tags":["admin-project-documents"],"summary":"Admin Get Redacted Project Document Download Url","operationId":"admin_get_redacted_project_document_download_url_api_v1_admin_projects__project_id__documents__document_id__redacted_download_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Admin Get Redacted Project Document Download Url Api V1 Admin Projects  Project Id  Documents  Document Id  Redacted Download Url Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/projects/{project_id}/documents/{document_id}":{"delete":{"tags":["admin-project-documents"],"summary":"Admin Delete Project Document","operationId":"admin_delete_project_document_api_v1_admin_projects__project_id__documents__document_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Document Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendors/oauth/init":{"get":{"tags":["admin-vendors"],"summary":"Init Oauth","description":"Start the OAuth flow — redirect to Google's authorization screen.\n\nGenerates a single-use state token (uuid4 hex), stores\n``{admin_id, env}`` in Redis under ``vendors_oauth_state:{state}`` with\na 10-minute TTL, then 302s to Google. The callback verifies + deletes\nthe state token on consumption.\n\n``access_type=offline`` and ``prompt=consent`` are BOTH required so\nGoogle always returns a refresh token (without prompt=consent, repeat\nconsents skip issuing one).","operationId":"init_oauth_api_v1_admin_vendors_oauth_init_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env","in":"query","required":true,"schema":{"enum":["staging","prod"],"type":"string","title":"Env"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendors/oauth/callback":{"get":{"tags":["admin-vendors"],"summary":"Oauth Callback","description":"Handle Google's callback — verify state, exchange code, persist tokens.\n\nOn success: redirects to ``/admin/vendors?connected={env}``. On a\nforged state token: 401 + Sentry breadcrumb. On an expired state\ntoken: 400 with a friendly message linking to ``/admin/vendors`` to\nrestart.\n\n``env`` is OPTIONAL: Google preserves only ``code`` + ``state`` across\nthe redirect, not arbitrary query params on the registered\n``redirect_uri``. The canonical env source is the Redis state token\n(which stores ``{admin_id, env}`` at init time). If callers DO pass\n``env`` (e.g. tests, or manual replay), we cross-verify it against\nthe stored value as defense-in-depth.","operationId":"oauth_callback_api_v1_admin_vendors_oauth_callback_get","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string","title":"Code"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"env","in":"query","required":false,"schema":{"anyOf":[{"enum":["staging","prod"],"type":"string"},{"type":"null"}],"title":"Env"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendors/{env}/revoke":{"post":{"tags":["admin-vendors"],"summary":"Revoke Oauth","description":"Admin-initiated mailbox disconnect.\n\nClears the refresh token from Secrets Manager + invalidates the\nin-process access-token cache. Returns 204 on success. Idempotent —\nsafe to call even when no mailbox is currently connected.","operationId":"revoke_oauth_api_v1_admin_vendors__env__revoke_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"env","in":"path","required":true,"schema":{"enum":["staging","prod"],"type":"string","title":"Env"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/vendors/trigger-rfq/{project_id}":{"post":{"tags":["admin-vendors"],"summary":"Trigger Rfq","description":"Manually retry the vendors-agent outbound run for ``project_id``.\n\nIdempotent — schedules a new outbound session via the same hook the\nSUBMIT flow uses. If a session is already in flight Anthropic\nde-dupes via the idempotency key, so duplicate triggers within the\nsame second collapse into one run.\n\nReturns 202 ACCEPTED with ``{action_id}`` so the admin UI can poll\nAgentAction status.\n\nRequires ``vendors:manage`` permission. Feature-flagged like the\nSUBMIT hook — returns 503 if vendors-agent is not enabled for this\nenv.","operationId":"trigger_rfq_api_v1_admin_vendors_trigger_rfq__project_id__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":"Response Trigger Rfq Api V1 Admin Vendors Trigger Rfq  Project Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/comments":{"get":{"tags":["comments"],"summary":"List Project Comments","description":"List non-internal comments for a project owned by the current user.","operationId":"list_project_comments_api_v1_projects__project_id__comments_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectCommentResponse"},"title":"Response List Project Comments Api V1 Projects  Project Id  Comments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["comments"],"summary":"Create Project Comment","description":"Create a customer comment on a project.\n\nThe ``is_internal`` flag is always forced to ``False`` for user-created\ncomments regardless of the request payload.","operationId":"create_project_comment_api_v1_projects__project_id__comments_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCommentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCommentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AcceptSupplierQuoteInput":{"properties":{},"type":"object","title":"AcceptSupplierQuoteInput","description":"Body for ``POST /admin/supplier-quotes/{quote_id}/accept`` (PRO-113).\n\nBody is currently empty — accept doesn't need any fields beyond the\nURL path id and the authenticated admin. Wrapped as a model so future\nadditions (e.g. ``notes`` for the audit row) don't break the wire shape."},"AdditionalLineItem-Input":{"properties":{"label":{"type":"string","maxLength":100,"minLength":1,"title":"Label"},"quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Quantity","description":"Optional display quantity for admin-entered misc line items. When set, the PDF shows the quantity alongside the label. The amount remains the line amount, not a unit price."},"amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"}],"title":"Amount"}},"type":"object","required":["label","amount"],"title":"AdditionalLineItem","description":"An admin-entered misc line item on a quote (shipping, expedite, etc.).\n\nRendered on the quote PDF between the parts subtotal and tax, and on\nthe user-facing quote card so the customer sees what they're paying."},"AdditionalLineItem-Output":{"properties":{"label":{"type":"string","maxLength":100,"minLength":1,"title":"Label"},"quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Quantity","description":"Optional display quantity for admin-entered misc line items. When set, the PDF shows the quantity alongside the label. The amount remains the line amount, not a unit price."},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$","title":"Amount"}},"type":"object","required":["label","amount"],"title":"AdditionalLineItem","description":"An admin-entered misc line item on a quote (shipping, expedite, etc.).\n\nRendered on the quote PDF between the parts subtotal and tax, and on\nthe user-facing quote card so the customer sees what they're paying."},"AdminAgentConversationPage":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"messages":{"items":{"$ref":"#/components/schemas/AdminAgentMessageResponse"},"type":"array","title":"Messages"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["conversation_id","messages","has_more"],"title":"AdminAgentConversationPage"},"AdminAgentMessageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"role":{"type":"string","title":"Role"},"content":{"type":"string","title":"Content"},"client_context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Client Context"},"tool_calls":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Tool Calls","default":[]},"citations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Citations","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","role","content","created_at"],"title":"AdminAgentMessageResponse"},"AdminAgentNudge":{"properties":{"key":{"type":"string","title":"Key"},"type":{"type":"string","title":"Type"},"label":{"type":"string","title":"Label"},"count":{"type":"integer","title":"Count"},"seed_prompt":{"type":"string","title":"Seed Prompt"}},"type":"object","required":["key","type","label","count","seed_prompt"],"title":"AdminAgentNudge"},"AdminAgentNudgeDismissRequest":{"properties":{"nudge_key":{"type":"string","maxLength":200,"minLength":1,"title":"Nudge Key"}},"type":"object","required":["nudge_key"],"title":"AdminAgentNudgeDismissRequest"},"AdminAgentNudgesResponse":{"properties":{"nudges":{"items":{"$ref":"#/components/schemas/AdminAgentNudge"},"type":"array","title":"Nudges"},"pending_total":{"type":"integer","title":"Pending Total"}},"type":"object","required":["nudges","pending_total"],"title":"AdminAgentNudgesResponse"},"AdminAgentTurnRequest":{"properties":{"text":{"type":"string","maxLength":4000,"minLength":1,"title":"Text"},"client_context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Client Context"}},"type":"object","required":["text"],"title":"AdminAgentTurnRequest"},"AdminBusinessProfileListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"company_name":{"type":"string","title":"Company Name"},"billing_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Email"},"payment_terms":{"type":"string","title":"Payment Terms"},"credit_limit":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Credit Limit"},"is_approved_for_po":{"type":"boolean","title":"Is Approved For Po"},"po_approval_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Po Approval Date"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"user":{"$ref":"#/components/schemas/UserSummary"}},"type":"object","required":["id","user_id","company_name","payment_terms","is_approved_for_po","created_at","user"],"title":"AdminBusinessProfileListItem","description":"Business profile summary for admin list views."},"AdminCadFileDownloadResponse":{"properties":{"download_url":{"type":"string","title":"Download Url"},"file_name":{"type":"string","title":"File Name"},"expires_in":{"type":"integer","title":"Expires In","default":300}},"type":"object","required":["download_url","file_name"],"title":"AdminCadFileDownloadResponse","description":"Presigned download URL for a CAD file."},"AdminCadFileListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version_number":{"type":"integer","title":"Version Number"},"file_name":{"type":"string","title":"File Name"},"original_file_name":{"type":"string","title":"Original File Name"},"file_format":{"type":"string","title":"File Format"},"file_size":{"type":"integer","title":"File Size"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"part_name":{"type":"string","title":"Part Name"},"project_name":{"type":"string","title":"Project Name"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"user_email":{"type":"string","title":"User Email"}},"type":"object","required":["id","version_number","file_name","original_file_name","file_format","file_size","status","created_at","part_name","project_name","project_id","user_email"],"title":"AdminCadFileListItem","description":"CAD file summary for admin list views."},"AdminConfirmPORequest":{"properties":{"delivery_option_id":{"type":"string","format":"uuid","title":"Delivery Option Id"},"payment_terms_net_days":{"type":"integer","maximum":365.0,"minimum":0.0,"title":"Payment Terms Net Days"}},"type":"object","required":["delivery_option_id","payment_terms_net_days"],"title":"AdminConfirmPORequest","description":"Admin confirmation payload for PO orders."},"AdminDropdownCreate":{"properties":{"category":{"type":"string","maxLength":100,"minLength":1,"title":"Category"},"label":{"type":"string","maxLength":255,"minLength":1,"title":"Label"},"value":{"type":"string","maxLength":255,"minLength":1,"title":"Value"},"sort_order":{"type":"integer","title":"Sort Order","default":0},"base_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Base Price"},"pricing_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricing Metadata"}},"type":"object","required":["category","label","value"],"title":"AdminDropdownCreate","description":"Create a new dropdown option."},"AdminDropdownResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"category":{"type":"string","title":"Category"},"label":{"type":"string","title":"Label"},"value":{"type":"string","title":"Value"},"sort_order":{"type":"integer","title":"Sort Order"},"is_active":{"type":"boolean","title":"Is Active"},"base_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Base Price"},"pricing_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricing Metadata"}},"type":"object","required":["id","category","label","value","sort_order","is_active"],"title":"AdminDropdownResponse","description":"Admin view of a dropdown option including inactive, base_price, and pricing_metadata."},"AdminDropdownUpdate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Label"},"value":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Value"},"sort_order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sort Order"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"base_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Base Price"},"pricing_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricing Metadata"}},"type":"object","title":"AdminDropdownUpdate","description":"Update a dropdown option. All fields optional."},"AdminFinishUpdate":{"properties":{"finish_dropdown_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finish Dropdown Id","description":"Selected dropdown row id. Must reference an active 'finishing' or 'coating' Dropdown. Set to null to clear the finish."},"color":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Color","description":"Selected color name (must match one of the dropdown's ``color_options[].name`` values, or the literal 'Custom')."},"custom_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Custom Name","description":"Free-text custom finish descriptor."},"spec":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Spec","description":"MIL-spec or drawing callout."},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}},"type":"object","title":"AdminFinishUpdate","description":"Admin finish update plus optional customer-request edit note."},"AdminLossReasonRequest":{"properties":{"reason":{"$ref":"#/components/schemas/QuoteLostReason"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note"}},"type":"object","required":["reason"],"title":"AdminLossReasonRequest","description":"Admin manual loss-reason entry (may overwrite)."},"AdminPartAiEstimate":{"properties":{"unit_price_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price Mid"},"total_price_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Price Mid"},"confidence":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Confidence"},"manual_quote_required":{"type":"boolean","title":"Manual Quote Required","default":false},"raw_shop_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Raw Shop Days"},"standard_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Standard Days"},"buffer_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Buffer Days"},"customer_lead_time_min_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Customer Lead Time Min Days"},"customer_lead_time_max_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Customer Lead Time Max Days"}},"type":"object","title":"AdminPartAiEstimate","description":"Lean AI pricing and lead-time summary for admin project rows."},"AdminPartCreateRequest":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","minimum":1.0,"title":"Required Quantity","default":1},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Finishing Name"},"custom_coating_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Custom Coating Name"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Coating Spec"},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason","description":"Optional admin note explaining why this part was added."}},"type":"object","required":["name"],"title":"AdminPartCreateRequest","description":"Admin request body for adding a part to an existing customer project."},"AdminPartDeleteRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}},"type":"object","title":"AdminPartDeleteRequest","description":"Optional admin note when deleting a customer-request part."},"AdminPartDetail":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","title":"Required Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"machining_process_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Label"},"material_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Label"},"finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Label"},"custom_material_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Finishing Name"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Label"},"coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Spec"},"custom_coating_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Coating Name"},"general_tolerance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"General Tolerance"},"edge_break_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Edge Break Default"},"ai_estimate":{"anyOf":[{"$ref":"#/components/schemas/AdminPartAiEstimate"},{"type":"null"}]},"effective_coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Label"},"effective_finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Label"},"versions":{"items":{"$ref":"#/components/schemas/app__schemas__admin__CadVersionSummary"},"type":"array","title":"Versions","default":[]},"drawing_file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing File Name"},"drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing R2 Key"},"drawing_file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Drawing File Size"},"drawing_analysis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drawing Analysis"},"redacted_drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redacted Drawing R2 Key"},"redaction_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redaction Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","required_quantity","created_at","updated_at"],"title":"AdminPartDetail","description":"Part detail with resolved dropdown labels for admin views.\n\nThe ``effective_*`` fields surface the legacy-fallback rendering for\nparts whose ``finishing_id`` still points at a coating-style slug\n(anodize_black, etc.) — these come from\n:func:`app.services.parts.PartService.resolve_part_dropdown_labels`\nand let admin views show a clean two-line \"Surface Finish\" / \"Coating\"\nsplit regardless of whether the part has been migrated."},"AdminPartQuantityUpdate":{"properties":{"quantity":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"general_tolerance":{"anyOf":[{"type":"string","enum":["ISO_2768_c","ISO_2768_m","ISO_2768_f","ISO_2768_v"]},{"type":"null"}],"title":"General Tolerance","description":"ISO 2768 tolerance class for the part. Optional admin override for customer-uploaded parts where the customer didn't pick one. Spec-level change: marks active reviewed quotes stale."},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason","description":"Optional admin note explaining the customer-request edit."}},"type":"object","title":"AdminPartQuantityUpdate","description":"Admin-only request body: update quantity and/or specs on a part.\n\nLooser gate than the user ``PartUpdate`` flow — admins can edit\ncustomer-request specs after submission and through payment-pending.\nQuote-relevant edits mark active customer quotes as\nCHANGES_REQUESTED so stale prices cannot be approved or paid.\n\nAll fields are optional — only the fields that are provided will be\napplied. Spec fields (process/material/finishing) are used by the\nadmin \"submit on behalf of user\" flow to fill in missing specs on a\nDRAFT project before submitting."},"AdminPaymentDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"method":{"type":"string","title":"Method"},"status":{"type":"string","title":"Status"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"total_with_tax":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total With Tax"},"deposit_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Deposit Amount"},"currency":{"type":"string","title":"Currency"},"stripe_payment_intent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Payment Intent Id"},"po_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Number"},"po_document_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Document R2 Key"},"po_document_download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Document Download Url"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user":{"$ref":"#/components/schemas/UserSummary"},"project_name":{"type":"string","title":"Project Name"},"invoice":{"anyOf":[{"$ref":"#/components/schemas/InvoiceResponse"},{"type":"null"}]},"packing_slip":{"anyOf":[{"$ref":"#/components/schemas/PackingSlipResponse"},{"type":"null"}]},"customer_name":{"type":"string","title":"Customer Name"},"customer_email":{"type":"string","title":"Customer Email"},"customer_billing_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Billing Address"},"submitted_by_admin_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Submitted By Admin Id"},"submitted_by_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitted By Label"},"payment_terms_net_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Payment Terms Net Days"},"po_document_extraction":{"anyOf":[{"$ref":"#/components/schemas/CommercialDocumentExtractionSummary"},{"type":"null"}]},"po_document_validation":{"anyOf":[{"$ref":"#/components/schemas/POExtractionValidationSummary"},{"type":"null"}]},"order_placed_at_override":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At Override"},"order_placed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At"}},"type":"object","required":["id","project_id","quote_id","user_id","method","status","amount","currency","created_at","updated_at","user","project_name","customer_name","customer_email"],"title":"AdminPaymentDetailResponse","description":"Full payment detail for admin view."},"AdminPaymentListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"method":{"type":"string","title":"Method"},"status":{"type":"string","title":"Status"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"total_with_tax":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total With Tax"},"currency":{"type":"string","title":"Currency"},"po_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Number"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"payment_terms_net_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Payment Terms Net Days"},"user":{"$ref":"#/components/schemas/UserSummary"},"project_name":{"type":"string","title":"Project Name"},"submitted_by_admin_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Submitted By Admin Id"},"submitted_by_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitted By Label"}},"type":"object","required":["id","project_id","method","status","amount","currency","created_at","user","project_name"],"title":"AdminPaymentListItem","description":"Payment summary for admin list views."},"AdminProcessMappingCreate":{"properties":{"machining_process_id":{"type":"string","format":"uuid","title":"Machining Process Id"},"material_id":{"type":"string","format":"uuid","title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true}},"type":"object","required":["machining_process_id","material_id"],"title":"AdminProcessMappingCreate","description":"Create a new process mapping."},"AdminProcessMappingResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"machining_process_id":{"type":"string","format":"uuid","title":"Machining Process Id"},"material_id":{"type":"string","format":"uuid","title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"is_valid":{"type":"boolean","title":"Is Valid"},"machining_process_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Label"},"material_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Label"},"finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Label"}},"type":"object","required":["id","machining_process_id","material_id","is_valid"],"title":"AdminProcessMappingResponse","description":"Process mapping with resolved dropdown labels."},"AdminProjectBulkDeleteFailure":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"error":{"type":"string","title":"Error","description":"Human-readable reason the delete failed"}},"type":"object","required":["project_id","error"],"title":"AdminProjectBulkDeleteFailure","description":"A single project that could not be deleted, and why."},"AdminProjectBulkDeleteRequest":{"properties":{"project_ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":50,"minItems":1,"title":"Project Ids","description":"Projects to permanently delete. Duplicates are ignored."}},"type":"object","required":["project_ids"],"title":"AdminProjectBulkDeleteRequest","description":"Request to permanently delete several projects in one call.\n\nCapped at the admin projects table page size (50). Selection in the UI is\nscoped to the current page, so a larger batch cannot be produced legitimately\n— and each project costs ~20 DB round trips plus one R2 delete per stored\nfile, so an unbounded batch risks exceeding the request timeout."},"AdminProjectBulkDeleteResponse":{"properties":{"deleted_count":{"type":"integer","title":"Deleted Count","description":"Number of projects actually deleted"},"deleted_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Deleted Ids"},"failed":{"items":{"$ref":"#/components/schemas/AdminProjectBulkDeleteFailure"},"type":"array","title":"Failed"}},"type":"object","required":["deleted_count"],"title":"AdminProjectBulkDeleteResponse","description":"Outcome of a bulk delete.\n\nBulk delete is partial-success by design: each project is deleted in its\nown transaction, so one failure does not roll back the others. Callers\nMUST check ``failed`` — a 200 does not mean everything was deleted."},"AdminProjectDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"internal_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Status"},"internal_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Notes"},"status":{"type":"string","title":"Status"},"priority":{"type":"string","title":"Priority"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressResponse"},{"type":"null"}]},"customer_billing_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Billing Address"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user":{"$ref":"#/components/schemas/UserSummary"},"parts":{"items":{"$ref":"#/components/schemas/AdminPartDetail"},"type":"array","title":"Parts","default":[]},"quotes":{"items":{"$ref":"#/components/schemas/QuoteDetailResponse"},"type":"array","title":"Quotes","default":[]},"comments":{"items":{"$ref":"#/components/schemas/ProjectCommentResponse"},"type":"array","title":"Comments","default":[]},"request_for_order_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Request For Order Date"},"order_placed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At"},"expected_delivery_date_min":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Min"},"expected_delivery_date_max":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Max"},"is_locked":{"type":"boolean","title":"Is Locked","default":false},"quote_needs_resend":{"type":"boolean","title":"Quote Needs Resend","default":false}},"type":"object","required":["id","name","status","priority","created_at","updated_at","user"],"title":"AdminProjectDetailResponse","description":"Full project detail for admin view with all nested data."},"AdminProjectDocumentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"file_name":{"type":"string","title":"File Name"},"file_size":{"type":"integer","title":"File Size"},"content_type":{"type":"string","title":"Content Type"},"status":{"$ref":"#/components/schemas/ProjectDocumentStatus"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"uploaded_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Uploaded By User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Download Url"},"redaction_status":{"$ref":"#/components/schemas/ProjectDocumentRedactionStatus"},"redacted_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redacted R2 Key"},"redaction_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redaction Error"},"redaction_report":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Redaction Report"},"redacted_download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redacted Download Url"}},"type":"object","required":["id","project_id","file_name","file_size","content_type","status","created_at","updated_at","redaction_status"],"title":"AdminProjectDocumentResponse"},"AdminProjectForceStatusUpdate":{"properties":{"status":{"$ref":"#/components/schemas/ProjectStatus","description":"Target project status"},"reason":{"type":"string","maxLength":2000,"minLength":5,"title":"Reason","description":"Required justification, recorded in the audit log"}},"type":"object","required":["status","reason"],"title":"AdminProjectForceStatusUpdate","description":"Request for the manual status override (any state → any state).\n\nUnlike :class:`AdminProjectStatusUpdate`, the reason is REQUIRED —\nmanual overrides bypass the lifecycle state machine and the\njustification is the audit trail's only context for why."},"AdminProjectInternalStateResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"internal_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Status"},"internal_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Notes"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","updated_at"],"title":"AdminProjectInternalStateResponse","description":"Response after updating admin-only internal project state."},"AdminProjectInternalUpdate":{"properties":{"internal_status":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Internal Status","description":"Internal-only operational status slug. Null clears the status."},"internal_notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Internal Notes","description":"Internal-only notes for admins. Null or blank clears the notes."}},"type":"object","title":"AdminProjectInternalUpdate","description":"Admin-only operational status and notes for a project."},"AdminProjectListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","title":"Status"},"internal_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Status"},"internal_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Notes"},"priority":{"type":"string","title":"Priority"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user":{"$ref":"#/components/schemas/UserSummary"},"part_count":{"type":"integer","title":"Part Count","default":0},"quote_count":{"type":"integer","title":"Quote Count","default":0},"latest_quote_intent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Quote Intent"},"quote_needs_resend":{"type":"boolean","title":"Quote Needs Resend","default":false},"total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount Cents"},"latest_quote_customer_name_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Quote Customer Name Override"},"latest_quote_customer_email_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Quote Customer Email Override"},"po_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Number"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"request_for_order_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Request For Order Date"},"order_placed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At"},"payment_method_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Method Label"},"estimated_ship_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Ship Date"},"selected_delivery_option_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Delivery Option Label"},"selected_delivery_option_lead_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Selected Delivery Option Lead Days"},"price_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Price Cents"},"payment_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment State"},"invoice_issued_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Invoice Issued At"},"blocked_on":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Blocked On"},"manufacturer":{"$ref":"#/components/schemas/ManufacturerSummary"},"at_risk":{"type":"boolean","title":"At Risk","default":false}},"type":"object","required":["id","name","status","priority","created_at","updated_at","user"],"title":"AdminProjectListItem","description":"Project summary for admin list views with denormalized user info."},"AdminProjectStatusUpdate":{"properties":{"status":{"$ref":"#/components/schemas/ProjectStatus","description":"New project status"},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason","description":"Reason for status change"}},"type":"object","required":["status"],"title":"AdminProjectStatusUpdate","description":"Request to transition a project's status."},"AdminResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"role_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role Name"},"permissions":{"items":{"type":"string"},"type":"array","title":"Permissions","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","email","first_name","last_name","created_at"],"title":"AdminResponse","description":"Public representation of an admin user with RBAC context."},"AdminShipmentListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Name"},"carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"status":{"type":"string","title":"Status"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","status","created_at","updated_at"],"title":"AdminShipmentListItem","description":"Denormalized shipment for admin list views."},"AdminSimilarPartsResponse":{"properties":{"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"parts":{"items":{"$ref":"#/components/schemas/PartSimilarityResult"},"type":"array","title":"Parts"}},"type":"object","required":["quote_id","parts"],"title":"AdminSimilarPartsResponse","description":"Per-part similar-parts response for one quote."},"AdminSubmitOnBehalfRequest":{"properties":{"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes","description":"Optional notes passed through to the quote request"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date","description":"Optional target delivery date on the project"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id","description":"Existing saved address belonging to the project's user. Mutually exclusive with ``shipping_address``."},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressCreate"},{"type":"null"}],"description":"New shipping address to persist to the user's address book and link to this project. Mutually exclusive with ``shipping_address_id``."}},"type":"object","title":"AdminSubmitOnBehalfRequest","description":"Admin request to advance a DRAFT project to SUBMITTED on behalf of the user.\n\nMirrors the user's ``QuoteRequestCreate`` payload plus an optional shipping\naddress resolution:\n\n* ``shipping_address_id`` — pick one of the user's saved addresses. The\n  service verifies it belongs to the project's user.\n* ``shipping_address`` — create a new address, persisted to the user's\n  address book (same as if the user had saved it themselves).\n\nAt most one of the two address fields may be set. If neither is set, the\nproject must already have ``shipping_address_id`` populated; otherwise\nthe service returns 400."},"AdminSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"}},"type":"object","required":["id","email","first_name","last_name"],"title":"AdminSummary","description":"Minimal admin info for role detail views."},"AdminUploadPOOnBehalfRequest":{"properties":{"po_number":{"type":"string","maxLength":100,"minLength":1,"title":"Po Number"},"po_document_r2_key":{"type":"string","maxLength":500,"minLength":1,"title":"Po Document R2 Key"},"order_placed_at":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Order Placed At"}},"type":"object","required":["po_number","po_document_r2_key"],"title":"AdminUploadPOOnBehalfRequest","description":"Admin request to submit a PO on the user's behalf for a QUOTED/APPROVED project.\n\nTax/shipping intentionally omitted — admin uploads use the resolved\nshipping address already on the project + the tax already attached\nto the approved quote (admin set tax during quote prep). No\nre-calculation here."},"AdminUserDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"project_count":{"type":"integer","title":"Project Count","default":0},"business_profile":{"anyOf":[{"$ref":"#/components/schemas/app__schemas__admin__BusinessProfileResponse"},{"type":"null"}]}},"type":"object","required":["id","email","first_name","last_name","status","created_at","updated_at"],"title":"AdminUserDetailResponse","description":"Full user detail for admin view."},"AdminUserListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"project_count":{"type":"integer","title":"Project Count","default":0},"last_activity_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Activity At"},"last_order_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Order At"},"last_outreach_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Outreach At"},"total_orders":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Orders"},"total_revenue":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Revenue"},"committed_orders":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Committed Orders"},"committed_revenue":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Committed Revenue"},"committed_unpaid_revenue":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Committed Unpaid Revenue"},"brokered_orders":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Brokered Orders"},"brokered_revenue":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Brokered Revenue"},"open_quotes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Open Quotes"},"lost_quotes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lost Quotes"},"suppressed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Suppressed"},"stats_computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Stats Computed At"}},"type":"object","required":["id","email","first_name","last_name","status","created_at"],"title":"AdminUserListItem","description":"User summary for admin list views.\n\nThe CRM rollup block (last_activity_at → stats_computed_at) is populated\nONLY when the caller also holds ``customer_followups:view`` — gated\nserver-side in the users router so a ``users:view``-only role never\nreceives revenue in the payload. ``None`` means \"not authorized\";\nzeroes mean \"authorized, no activity yet\"."},"AdminUserStatusUpdate":{"properties":{"status":{"$ref":"#/components/schemas/UserStatus","description":"New user status (active, inactive, suspended)"}},"type":"object","required":["status"],"title":"AdminUserStatusUpdate","description":"Request to update a user's status."},"AgentActionListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"action_type":{"type":"string","title":"Action Type"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"status":{"type":"string","title":"Status"},"cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Usd"},"triggered_by_role":{"type":"string","title":"Triggered By Role"},"approval_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approval Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","action_type","part_id","status","triggered_by_role","created_at"],"title":"AgentActionListItem","description":"Summary for list views."},"AgentActionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"action_type":{"type":"string","title":"Action Type"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"triggered_by":{"type":"string","title":"Triggered By"},"triggered_by_role":{"type":"string","title":"Triggered By Role"},"status":{"type":"string","title":"Status"},"input_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Input Data"},"output_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Data"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Usd"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prompt Tokens"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completion Tokens"},"duration_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Ms"},"approval_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approval Status"},"approved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approved By"},"approved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Approved At"},"approval_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approval Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","action_type","part_id","triggered_by","triggered_by_role","status","created_at","updated_at"],"title":"AgentActionResponse","description":"Full detail response."},"AgentConversationMessageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"role":{"type":"string","enum":["user","ollie","system"],"title":"Role"},"content":{"type":"string","title":"Content"},"tool_calls":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Tool Calls"},"citations":{"items":{"$ref":"#/components/schemas/Citation"},"type":"array","title":"Citations"},"model_used":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Used"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"user_feedback":{"anyOf":[{"type":"string","enum":["up","down"]},{"type":"null"}],"title":"User Feedback"},"trace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Trace Id"}},"type":"object","required":["id","conversation_id","role","content","tool_calls","citations","created_at"],"title":"AgentConversationMessageResponse","description":"Single message as returned by the API."},"AgentConversationPageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"muted":{"type":"boolean","title":"Muted"},"message_count":{"type":"integer","title":"Message Count"},"messages":{"items":{"$ref":"#/components/schemas/AgentConversationMessageResponse"},"type":"array","title":"Messages"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["id","project_id","muted","message_count","messages","has_more"],"title":"AgentConversationPageResponse","description":"Paginated conversation response.\n\nMessages are returned in chronological (oldest-first) order within the\npage. ``has_more`` tells the caller whether an older page exists beyond\nthe current window (fetched via ``before_id``)."},"AiStatusResponse":{"properties":{"daily_spend_usd":{"type":"number","title":"Daily Spend Usd"},"budget_usd":{"type":"number","title":"Budget Usd"},"budget_remaining_usd":{"type":"number","title":"Budget Remaining Usd"},"budget_exceeded":{"type":"boolean","title":"Budget Exceeded"},"date":{"type":"string","title":"Date"},"anthropic_configured":{"type":"boolean","title":"Anthropic Configured"},"openai_configured":{"type":"boolean","title":"Openai Configured"},"drawing_provider":{"type":"string","title":"Drawing Provider"},"drawing_openai_zdr_enabled":{"type":"boolean","title":"Drawing Openai Zdr Enabled"},"drawing_claude_zdr_enabled":{"type":"boolean","title":"Drawing Claude Zdr Enabled"}},"type":"object","required":["daily_spend_usd","budget_usd","budget_remaining_usd","budget_exceeded","date","anthropic_configured","openai_configured","drawing_provider","drawing_openai_zdr_enabled","drawing_claude_zdr_enabled"],"title":"AiStatusResponse","description":"Response for GET /admin/ai/status."},"AnalysisStatus":{"type":"string","enum":["not_started","pending_cad","computing","complete","failed"],"title":"AnalysisStatus","description":"Single source of truth for deterministic DFM/pricing readiness.\n\nReplaces the fragile inference from ``dfm_pending`` + ``process_dfm_results``\n+ ``ai_dfm_synthesis``. See ``.claude/plans/active/dfm-cost-stuck-state-elimination.md``.\n\nNOT_STARTED:  No specs set yet.\nPENDING_CAD:  Specs set, CAD pipeline still running — finalize will pick up.\nCOMPUTING:    DFM rule engine / pricing refresh in flight.\nCOMPLETE:     DFM and pricing written; AI/Ollie synthesis is optional.\nFAILED:       See ``analysis_error_message`` + ``analysis_failed_step``."},"AssemblyFileFormat":{"type":"string","enum":["step","stp"],"title":"AssemblyFileFormat","description":"Allowed formats for project-level assembly reference files.\n\nIntentionally a narrow subset — assembly files are reference docs\nonly, not processed through the geometry pipeline."},"AssemblyFileResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"file_name":{"type":"string","title":"File Name"},"file_size":{"type":"integer","title":"File Size"},"file_format":{"$ref":"#/components/schemas/AssemblyFileFormat"},"status":{"$ref":"#/components/schemas/AssemblyFileStatus"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"uploaded_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Uploaded By User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Download Url","description":"Presigned GET URL for downloading the assembly file. None when status is not 'validated' (file isn't ready or has failed)."}},"type":"object","required":["id","project_id","file_name","file_size","file_format","status","created_at","updated_at"],"title":"AssemblyFileResponse","description":"Full assembly file metadata + presigned GET URL when validated."},"AssemblyFileStatus":{"type":"string","enum":["uploading","uploaded","validated","failed"],"title":"AssemblyFileStatus","description":"Lifecycle for ``ProjectAssemblyFile``.\n\nUPLOADING:  presigned URL issued, waiting on browser PUT\nUPLOADED:   confirm received; magic-bytes validation queued\nVALIDATED:  passed magic-bytes check; downloadable\nFAILED:     validation rejected (``failure_reason`` populated)"},"AuthMeResponse":{"properties":{"type":{"type":"string","title":"Type"},"user":{"anyOf":[{"$ref":"#/components/schemas/UserResponse"},{"type":"null"}]},"admin":{"anyOf":[{"$ref":"#/components/schemas/AdminResponse"},{"type":"null"}]}},"type":"object","required":["type"],"title":"AuthMeResponse","description":"Wrapper returned by GET /auth/me.\n\nExactly one of ``user`` or ``admin`` will be populated, indicated\nby the ``type`` discriminator field."},"AutoPriceRequest":{"properties":{"margin_pct":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Margin Pct","description":"Percentage margin to add on top of the AI mid estimate (0-100)","default":0}},"type":"object","title":"AutoPriceRequest","description":"Request body for the auto-price endpoint.\n\n``margin_pct`` is added on top of the AI mid estimate.  A value of\n``10`` means unit_price = mid * 1.10."},"AutoPriceResponse":{"properties":{"applied":{"type":"integer","title":"Applied","description":"Number of parts that had AI estimates applied"},"skipped":{"type":"integer","title":"Skipped","description":"Number of parts without AI estimates (skipped)"},"skipped_parts":{"items":{"type":"string"},"type":"array","title":"Skipped Parts","description":"Names of the parts that were skipped"},"total_estimated":{"type":"number","title":"Total Estimated","description":"Sum of all line item totals after applying auto-pricing"}},"type":"object","required":["applied","skipped","skipped_parts","total_estimated"],"title":"AutoPriceResponse","description":"Result of the auto-price batch operation."},"BacktestRunDetail":{"properties":{"run_id":{"type":"string","title":"Run Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"parts_processed":{"type":"integer","title":"Parts Processed"},"quotes_processed":{"type":"integer","title":"Quotes Processed"},"median_v1_delta_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median V1 Delta Pct"},"median_v2_delta_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median V2 Delta Pct"},"v2_beats_v1":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"V2 Beats V1"},"clean_cohort_size":{"type":"integer","title":"Clean Cohort Size"},"markdown_report":{"type":"string","title":"Markdown Report"},"csv_url":{"type":"string","title":"Csv Url"},"distribution_png_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Distribution Png Url"},"has_outliers":{"type":"boolean","title":"Has Outliers"},"outliers_count":{"type":"integer","title":"Outliers Count"}},"type":"object","required":["run_id","created_at","parts_processed","quotes_processed","median_v1_delta_pct","median_v2_delta_pct","v2_beats_v1","clean_cohort_size","markdown_report","csv_url","has_outliers","outliers_count"],"title":"BacktestRunDetail","description":"Full detail for a single run.\n\nUsed by ``GET /admin/pricing/backtest-runs/{run_id}``. Carries the\nfull markdown report content plus pointers to the CSV streaming\nsub-endpoint and the distribution PNG (if matplotlib was available\nwhen the run completed)."},"BacktestRunSummary":{"properties":{"run_id":{"type":"string","title":"Run Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"parts_processed":{"type":"integer","title":"Parts Processed"},"quotes_processed":{"type":"integer","title":"Quotes Processed"},"median_v1_delta_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median V1 Delta Pct"},"median_v2_delta_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median V2 Delta Pct"},"v2_beats_v1":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"V2 Beats V1"},"clean_cohort_size":{"type":"integer","title":"Clean Cohort Size"}},"type":"object","required":["run_id","created_at","parts_processed","quotes_processed","median_v1_delta_pct","median_v2_delta_pct","v2_beats_v1","clean_cohort_size"],"title":"BacktestRunSummary","description":"Headline metrics for a single backtest run.\n\nSourced from ``summary.json`` in the run output dir. Used by\n``GET /admin/pricing/backtest-runs`` to list runs newest-first."},"BatchCorrectionCreate":{"properties":{"feature_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Feature Ids"},"correction_type":{"type":"string","enum":["feature_intent","feature_reclassification","dfm_acknowledgment","dfm_dismissal","solid_classification","feature_note","tolerance_specification"],"title":"Correction Type"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}},"type":"object","required":["feature_ids","correction_type"],"title":"BatchCorrectionCreate","description":"Request body for POST /parts/{part_id}/corrections/batch."},"BatchCorrectionResponse":{"properties":{"count":{"type":"integer","title":"Count"},"feature_ids":{"items":{"type":"string"},"type":"array","title":"Feature Ids"}},"type":"object","required":["count","feature_ids"],"title":"BatchCorrectionResponse","description":"Response for batch correction endpoint."},"Body_admin_upload_assembly_file_api_v1_admin_projects__project_id__assembly_file_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_admin_upload_assembly_file_api_v1_admin_projects__project_id__assembly_file_upload_post"},"Body_admin_upload_cad_file_api_v1_admin_parts__part_id__cad_upload__version_id__post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_admin_upload_cad_file_api_v1_admin_parts__part_id__cad_upload__version_id__post"},"Body_admin_upload_drawing_file_api_v1_admin_parts__part_id__drawings_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_admin_upload_drawing_file_api_v1_admin_parts__part_id__drawings_upload_post"},"Body_admin_upload_po_document_api_v1_admin_projects__project_id__po_document_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_admin_upload_po_document_api_v1_admin_projects__project_id__po_document_post"},"Body_admin_upload_project_document_api_v1_admin_projects__project_id__documents__document_id__upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_admin_upload_project_document_api_v1_admin_projects__project_id__documents__document_id__upload_post"},"Body_upload_assembly_file_api_v1_projects__project_id__assembly_file_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_assembly_file_api_v1_projects__project_id__assembly_file_upload_post"},"Body_upload_cad_file_api_v1_parts__part_id__cad_upload__version_id__post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_cad_file_api_v1_parts__part_id__cad_upload__version_id__post"},"Body_upload_drawing_file_api_v1_parts__part_id__drawings_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_drawing_file_api_v1_parts__part_id__drawings_upload_post"},"Body_upload_po_document_api_v1_payments_po_document_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_po_document_api_v1_payments_po_document_post"},"Body_upload_project_document_api_v1_projects__project_id__documents__document_id__upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_project_document_api_v1_projects__project_id__documents__document_id__upload_post"},"Body_upload_project_supplier_attachment_api_v1_admin_projects__project_id__suppliers__supplier_contact_id__attachments_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"document_kind":{"type":"string","enum":["quote","invoice"],"title":"Document Kind","default":"quote"}},"type":"object","required":["file"],"title":"Body_upload_project_supplier_attachment_api_v1_admin_projects__project_id__suppliers__supplier_contact_id__attachments_post"},"Body_upload_supplier_quote_attachment_api_v1_admin_supplier_quotes__quote_id__attachments_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"document_kind":{"type":"string","enum":["quote","invoice"],"title":"Document Kind","default":"quote"}},"type":"object","required":["file"],"title":"Body_upload_supplier_quote_attachment_api_v1_admin_supplier_quotes__quote_id__attachments_post"},"Body_upload_tax_exempt_cert_api_v1_business_profile_tax_exempt_cert_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_tax_exempt_cert_api_v1_business_profile_tax_exempt_cert_post"},"Body_upload_vendor_thread_attachment_api_v1_admin_vendor_threads__thread_state_id__attachments_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"document_kind":{"type":"string","enum":["quote","invoice"],"title":"Document Kind","default":"quote"}},"type":"object","required":["file"],"title":"Body_upload_vendor_thread_attachment_api_v1_admin_vendor_threads__thread_state_id__attachments_post"},"BusinessProfileApproveRequest":{"properties":{"credit_limit":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Credit Limit","description":"Optional credit limit"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"BusinessProfileApproveRequest","description":"Request to approve a business profile for PO eligibility."},"BusinessProfileCreate":{"properties":{"company_name":{"type":"string","maxLength":255,"title":"Company Name"},"tax_id":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Tax Id"},"billing_email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Billing Email"},"billing_address":{"type":"string","maxLength":2000,"title":"Billing Address"},"shipping_address":{"type":"string","maxLength":2000,"title":"Shipping Address"},"payment_terms":{"type":"string","maxLength":50,"title":"Payment Terms"}},"type":"object","required":["company_name","billing_address","shipping_address","payment_terms"],"title":"BusinessProfileCreate","description":"Create a new business profile for PO eligibility."},"BusinessProfileRevokeRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}},"type":"object","title":"BusinessProfileRevokeRequest","description":"Request to revoke PO eligibility."},"BusinessProfileUpdate":{"properties":{"company_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Company Name"},"tax_id":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Tax Id"},"billing_email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Billing Email"},"billing_address":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Billing Address"},"shipping_address":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Shipping Address"},"payment_terms":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Payment Terms"},"tax_exempt_cert_r2_key":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Tax Exempt Cert R2 Key"}},"type":"object","title":"BusinessProfileUpdate","description":"Update an existing business profile. All fields optional."},"CadFileVersionDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version_number":{"type":"integer","title":"Version Number"},"is_latest":{"type":"boolean","title":"Is Latest"},"file_name":{"type":"string","title":"File Name"},"original_file_name":{"type":"string","title":"Original File Name"},"file_format":{"type":"string","title":"File Format"},"file_size":{"type":"integer","title":"File Size"},"status":{"type":"string","title":"Status"},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"latest_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Run Id"},"analysis_milestone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Milestone"},"analysis_authority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Authority"},"analysis_seq":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Seq"},"preliminary_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceResponse"},{"type":"null"}]},"glb_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Glb Url"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"topology_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Topology Url"},"width":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Height"},"depth":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Depth"},"dimension_unit":{"type":"string","title":"Dimension Unit","default":"mm"},"volume":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Volume"},"surface_area":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Surface Area"},"wall_thickness_min":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Wall Thickness Min"},"is_manifold":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Manifold"},"mesh_quality_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mesh Quality Score"},"dfm_issues":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Dfm Issues"},"geometry_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Geometry Metadata"},"detected_features":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Detected Features"},"feature_projection_v2":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Feature Projection V2"},"process_dfm_results":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Process Dfm Results"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"ai_dfm_synthesis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Ai Dfm Synthesis"},"analysis_status":{"$ref":"#/components/schemas/AnalysisStatus","default":"not_started"},"analysis_error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Error Message"},"analysis_failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Failed Step"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"lane_a_facts":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Lane A Facts"}},"type":"object","required":["id","version_number","is_latest","file_name","original_file_name","file_format","file_size","status","part_id","created_at","updated_at"],"title":"CadFileVersionDetailResponse","description":"Full single-version detail, including the exact Lane A facts strip."},"CadFileVersionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version_number":{"type":"integer","title":"Version Number"},"is_latest":{"type":"boolean","title":"Is Latest"},"file_name":{"type":"string","title":"File Name"},"original_file_name":{"type":"string","title":"Original File Name"},"file_format":{"type":"string","title":"File Format"},"file_size":{"type":"integer","title":"File Size"},"status":{"type":"string","title":"Status"},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"latest_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Run Id"},"analysis_milestone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Milestone"},"analysis_authority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Authority"},"analysis_seq":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Seq"},"preliminary_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceResponse"},{"type":"null"}]},"glb_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Glb Url"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"topology_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Topology Url"},"width":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Height"},"depth":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Depth"},"dimension_unit":{"type":"string","title":"Dimension Unit","default":"mm"},"volume":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Volume"},"surface_area":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Surface Area"},"wall_thickness_min":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Wall Thickness Min"},"is_manifold":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Manifold"},"mesh_quality_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mesh Quality Score"},"dfm_issues":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Dfm Issues"},"geometry_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Geometry Metadata"},"detected_features":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Detected Features"},"feature_projection_v2":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Feature Projection V2"},"process_dfm_results":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Process Dfm Results"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"ai_dfm_synthesis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Ai Dfm Synthesis"},"analysis_status":{"$ref":"#/components/schemas/AnalysisStatus","default":"not_started"},"analysis_error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Error Message"},"analysis_failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Failed Step"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","version_number","is_latest","file_name","original_file_name","file_format","file_size","status","part_id","created_at","updated_at"],"title":"CadFileVersionResponse","description":"Customer-safe representation of a ``CadFileVersion`` record.\n\nReturned by detail endpoints and included in part detail responses.\nFields populated by the processing pipeline (geometry analysis, DFM,\nconverted files) will be ``None`` until the relevant worker completes."},"CalloutAction":{"properties":{"label":{"type":"string","maxLength":64,"title":"Label"},"action_type":{"type":"string","maxLength":32,"title":"Action Type"},"payload":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Payload"}},"type":"object","required":["label","action_type"],"title":"CalloutAction","description":"A single action button rendered in the callout popover."},"CalloutSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"callout_type":{"type":"string","title":"Callout Type"},"severity":{"type":"string","title":"Severity"},"title":{"type":"string","title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"},"state":{"type":"string","title":"State"},"answered":{"type":"boolean","title":"Answered"},"answer_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Text"}},"type":"object","required":["id","callout_type","severity","title","state","answered"],"title":"CalloutSummary"},"CamArtifactResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"type":"string","format":"uuid","title":"Cad File Version Id"},"status":{"type":"string","title":"Status"},"engine":{"type":"string","title":"Engine"},"post_processor":{"type":"string","title":"Post Processor"},"feeds_speeds_profile_version":{"type":"string","title":"Feeds Speeds Profile Version"},"r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"R2 Key"},"external_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Job Id"},"cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Usd"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"generation_started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generation Started At"},"generation_completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generation Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Id"},"setup_sheet_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Setup Sheet R2 Key"},"screenshot_r2_keys":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Screenshot R2 Keys"},"recording_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording R2 Key"},"cam_spec_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cam Spec Snapshot"},"coverage_report":{"anyOf":[{"$ref":"#/components/schemas/CoverageReport"},{"type":"null"}]},"context_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Context Snapshot"},"verification_report":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Verification Report"},"agent_references":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Agent References"},"agent_completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Agent Completed At"},"primary_brain":{"type":"string","title":"Primary Brain","default":"pipeline"}},"type":"object","required":["id","part_id","cad_file_version_id","status","engine","post_processor","feeds_speeds_profile_version","created_at","updated_at"],"title":"CamArtifactResponse","description":"200 response from ``GET /admin/parts/{id}/cam`` — latest artifact."},"CamDownloadUrlResponse":{"properties":{"url":{"type":"string","title":"Url"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["url","expires_at"],"title":"CamDownloadUrlResponse","description":"Response from ``GET /admin/parts/{id}/cam/{artifact_id}/download-url``."},"CamGenerateRequest":{"properties":{"post_processor":{"anyOf":[{"type":"string","enum":["grbl","linuxcnc","haas","Haas - Next Generation"]},{"type":"null"}],"title":"Post Processor"},"brain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brain"}},"additionalProperties":false,"type":"object","title":"CamGenerateRequest","description":"Optional JSON body for ``POST /admin/parts/{id}/cam/generate``.\n\nAll fields optional so the endpoint keeps its 202 contract for callers that\nPOST with no body. ``post_processor`` selects the emitted G-code dialect\n(``None`` → the synthesizer default, currently ``grbl``). The choice is\nthreaded into synthesis at generate time (persisted on the artifact's\n``cam_spec_snapshot``) AND into the workflow input so the re-synthesizing\nactivity produces the same dialect."},"CamGenerateResponse":{"properties":{"artifact_id":{"type":"string","format":"uuid","title":"Artifact Id"},"workflow_id":{"type":"string","title":"Workflow Id"},"status":{"type":"string","title":"Status"}},"type":"object","required":["artifact_id","workflow_id","status"],"title":"CamGenerateResponse","description":"202 response from ``POST /admin/parts/{id}/cam/generate``."},"CamGeneratorConfigResponse":{"properties":{"brains":{"items":{"type":"string"},"type":"array","title":"Brains"}},"type":"object","required":["brains"],"title":"CamGeneratorConfigResponse","description":"Response from ``GET /admin/parts/cam-generator-config`` — the brains\nthe admin can pick as the primary generator (\"pipeline\" + every\nconfigured provider:model whose API key is present)."},"CarrierActionResponse":{"properties":{"status":{"type":"string","title":"Status"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"outbound_shipment":{"anyOf":[{"$ref":"#/components/schemas/OutboundShipmentResponse"},{"type":"null"}]},"inbound_shipment":{"anyOf":[{"$ref":"#/components/schemas/InboundShipmentResponse"},{"type":"null"}]}},"type":"object","required":["status"],"title":"CarrierActionResponse"},"CarrierCode":{"type":"string","enum":["ups","dhl","fedex","usps","other"],"title":"CarrierCode"},"CarrierSyncStatus":{"type":"string","enum":["never_synced","syncing","synced","failed"],"title":"CarrierSyncStatus"},"Citation":{"properties":{"type":{"type":"string","enum":["web","internal_ref","tool_result","lookup"],"title":"Type"},"title":{"type":"string","title":"Title"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Id"},"section":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section"},"snippet":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Snippet"},"confidence":{"type":"string","enum":["definitive","confident","hedged","unknown"],"title":"Confidence"}},"type":"object","required":["type","title","confidence"],"title":"Citation","description":"Unified citation schema.\n\nNormalizes the three (currently four) places citations come from:\n  * Anthropic ``web_search`` tool results -> ``type=\"web\"``\n  * Tier 2 authored article references    -> ``type=\"internal_ref\"``\n  * Other tool-result grounding           -> ``type=\"tool_result\"``\n  * Generic lookups (spec/tap tables, …) -> ``type=\"lookup\"``"},"CoatingMaskCreate":{"properties":{"face_id":{"type":"string","minLength":1,"title":"Face Id","description":"Topology face ID (e.g. ``face_42``)."},"reason":{"type":"string","enum":["thread_fit","press_fit_bore","mating_surface","electrical_contact","o_ring_groove","other"],"title":"Reason","description":"Why this face should be excluded from the coating."}},"type":"object","required":["face_id","reason"],"title":"CoatingMaskCreate","description":"Payload for ``POST /parts/{part_id}/coating-masks``."},"CoatingMaskRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"face_id":{"type":"string","title":"Face Id"},"reason":{"type":"string","title":"Reason"},"state":{"type":"string","title":"State"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","part_id","cad_file_version_id","face_id","reason","state","created_at","updated_at"],"title":"CoatingMaskRead","description":"Response projection for a coating mask OutcomeEvent."},"ColorOption":{"properties":{"name":{"type":"string","title":"Name","description":"Display name of the color (e.g. 'Black')"},"surcharge":{"type":"number","minimum":0.0,"title":"Surcharge","description":"Per-part USD adder when this color is selected.","default":0.0}},"type":"object","required":["name"],"title":"ColorOption","description":"A single color choice on a coating's palette.\n\nSurcharge is a per-part USD adder (e.g. Gold Anodize +$8 vs Clear\nAnodize +$0). Sourced from ``Dropdown.pricing_metadata.color_options``\non coating rows. Mechanical finishes carry an empty list."},"CommercialDocumentExtractionReview":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"provider":{"type":"string","title":"Provider"},"schema_version":{"type":"string","title":"Schema Version"},"normalized_payload":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Normalized Payload"},"field_evidence":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Field Evidence"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","status","provider","schema_version","created_at","updated_at"],"title":"CommercialDocumentExtractionReview","description":"Admin-facing extraction payload for review/apply screens."},"CommercialDocumentExtractionSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"provider":{"type":"string","title":"Provider"},"schema_version":{"type":"string","title":"Schema Version"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence"},"aggregate_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Aggregate Total Cents"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"max_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Lead Time Days"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","status","provider","schema_version","created_at","updated_at"],"title":"CommercialDocumentExtractionSummary","description":"Compact extraction status for list/detail views."},"CompanyPromptResponse":{"properties":{"should_prompt":{"type":"boolean","title":"Should Prompt"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"dismissed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dismissed At"},"next_prompt_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Prompt At"}},"type":"object","required":["should_prompt","company","dismissed_at","next_prompt_at"],"title":"CompanyPromptResponse","description":"State for the optional missing-company onboarding prompt."},"ConfirmAssemblyUploadRequest":{"properties":{"assembly_file_id":{"type":"string","format":"uuid","title":"Assembly File Id","description":"The ProjectAssemblyFile ID returned by the initiate endpoint."},"r2_key":{"type":"string","title":"R2 Key","description":"R2 object key from initiate endpoint (echoed back for verification)."}},"type":"object","required":["assembly_file_id","r2_key"],"title":"ConfirmAssemblyUploadRequest","description":"Confirm that the browser PUT to R2 completed successfully.\n\nTransitions the row from ``uploading`` -> ``uploaded`` and queues\nthe magic-bytes validation activity on the light worker."},"ConfirmDrawingUploadRequest":{"properties":{"r2_key":{"type":"string","minLength":1,"title":"R2 Key","description":"R2 object key from the initiate endpoint (echoed back for verification)."},"file_size":{"type":"integer","maximum":52428800.0,"exclusiveMinimum":0.0,"title":"File Size","description":"File size in bytes to store on the Part record."}},"type":"object","required":["r2_key","file_size"],"title":"ConfirmDrawingUploadRequest","description":"Confirm that the client-side drawing upload to R2 completed successfully.\n\nAfter the client PUTs the file to the presigned URL it calls this\nendpoint so the backend can save the drawing metadata on the Part."},"ConfirmProjectDocumentUploadRequest":{"properties":{"document_id":{"type":"string","format":"uuid","title":"Document Id"},"r2_key":{"type":"string","title":"R2 Key"}},"type":"object","required":["document_id","r2_key"],"title":"ConfirmProjectDocumentUploadRequest"},"ConfirmUploadRequest":{"properties":{"version_id":{"type":"string","format":"uuid","title":"Version Id","description":"The CadFileVersion ID returned by the initiate endpoint."},"r2_key":{"type":"string","title":"R2 Key","description":"R2 object key from initiate endpoint (echoed back for verification)."}},"type":"object","required":["version_id","r2_key"],"title":"ConfirmUploadRequest","description":"Confirm that the client-side upload to R2 completed successfully.\n\nAfter the client PUTs the file to the presigned URL it calls this\nendpoint so the backend can transition the ``CadFileVersion`` status\nfrom ``uploading`` to ``uploaded`` and enqueue the Temporal processing\nworkflow."},"ConflictResolveRequest":{"properties":{"choice":{"type":"string","pattern":"^(drawing|mine)$","title":"Choice"}},"type":"object","required":["choice"],"title":"ConflictResolveRequest","description":"Customer resolution of a spec_mismatch conflict (Part B fast-follow)."},"ConflictUpdateRequest":{"properties":{"status":{"type":"string","pattern":"^(open|dismissed)$","title":"Status"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note"}},"type":"object","required":["status"],"title":"ConflictUpdateRequest"},"CorrectionCreate":{"properties":{"feature_id":{"type":"string","maxLength":36,"minLength":1,"title":"Feature Id"},"correction_type":{"type":"string","enum":["feature_intent","feature_reclassification","dfm_acknowledgment","dfm_dismissal","solid_classification","feature_note","tolerance_specification"],"title":"Correction Type"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason"}},"type":"object","required":["feature_id","correction_type"],"title":"CorrectionCreate","description":"Request body for POST /parts/{part_id}/outcome-events."},"CorrectionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"outcome_type":{"type":"string","title":"Outcome Type"},"source":{"type":"string","title":"Source"},"severity":{"type":"string","title":"Severity"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","part_id","outcome_type","source","severity","data","created_at"],"title":"CorrectionResponse","description":"Response for a single correction (OutcomeEvent with source=user_correction)."},"CorrectionWithDfmResponse":{"properties":{"correction":{"$ref":"#/components/schemas/CorrectionResponse"},"dfm_rescored":{"type":"boolean","title":"Dfm Rescored","default":false},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"findings":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Findings"}},"type":"object","required":["correction"],"title":"CorrectionWithDfmResponse","description":"Response for POST correction — includes the correction and optional DFM re-score."},"CostBreakdown":{"properties":{"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"},"material":{"type":"number","title":"Material","default":0.0},"programming":{"type":"number","title":"Programming","default":0.0},"setup":{"type":"number","title":"Setup","default":0.0},"cycle_time":{"type":"number","title":"Cycle Time","default":0.0},"tooling":{"type":"number","title":"Tooling","default":0.0},"secondary_ops":{"type":"number","title":"Secondary Ops","default":0.0},"risk_buffer":{"type":"number","title":"Risk Buffer","default":0.0},"material_detail":{"additionalProperties":true,"type":"object","title":"Material Detail"},"programming_detail":{"additionalProperties":true,"type":"object","title":"Programming Detail"},"setup_detail":{"additionalProperties":true,"type":"object","title":"Setup Detail"},"cycle_time_detail":{"additionalProperties":true,"type":"object","title":"Cycle Time Detail"},"tooling_detail":{"additionalProperties":true,"type":"object","title":"Tooling Detail"},"secondary_ops_detail":{"additionalProperties":true,"type":"object","title":"Secondary Ops Detail"},"risk_detail":{"additionalProperties":true,"type":"object","title":"Risk Detail"}},"type":"object","title":"CostBreakdown","description":"Cost estimate breakdown by category.\n\n``version`` is the breakdown schema version (current: 2 — added the\nmulti-line ``secondary_ops_detail`` shape on 2026-04-27). Old\npersisted breakdowns lack this field; treat missing as v1."},"CostEstimate":{"properties":{"unit_price_low":{"type":"number","title":"Unit Price Low"},"unit_price_high":{"type":"number","title":"Unit Price High"},"unit_price_mid":{"type":"number","title":"Unit Price Mid"},"total_price_low":{"type":"number","title":"Total Price Low"},"total_price_high":{"type":"number","title":"Total Price High"},"quantity":{"type":"integer","title":"Quantity"},"breakdown":{"$ref":"#/components/schemas/CostBreakdown"},"user_breakdown":{"additionalProperties":{"type":"number"},"type":"object","title":"User Breakdown"},"discount_rate":{"type":"number","title":"Discount Rate","default":0.0},"lead_time_multiplier":{"type":"number","title":"Lead Time Multiplier","default":1.0},"profit_multiplier":{"type":"number","title":"Profit Multiplier","default":1.35},"confidence":{"type":"string","title":"Confidence","default":"estimate"},"disclaimer":{"type":"string","title":"Disclaimer","default":"Preliminary estimate — subject to admin review"},"track_b":{"anyOf":[{"$ref":"#/components/schemas/TrackBPrediction"},{"type":"null"}]},"pricing_engine_delta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricing Engine Delta"},"markup_applied":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Markup Applied"},"complexity_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Complexity Score"},"cycle_minutes_for_complexity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cycle Minutes For Complexity"},"v1_markup_would_be":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"V1 Markup Would Be"},"pricing_operations_source":{"type":"string","enum":["legacy_summary","projection_v2"],"title":"Pricing Operations Source","default":"legacy_summary"}},"type":"object","required":["unit_price_low","unit_price_high","unit_price_mid","total_price_low","total_price_high","quantity","breakdown"],"title":"CostEstimate","description":"Preliminary cost estimate."},"CostPreviewResponse":{"properties":{"unit_price_low":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price Low"},"unit_price_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price Mid"},"unit_price_high":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price High"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"lead_time_options":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/LeadTimeOption"},"type":"object"},{"type":"null"}],"title":"Lead Time Options"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"track_b":{"anyOf":[{"$ref":"#/components/schemas/TrackBPrediction"},{"type":"null"}]},"pricing_operations_source":{"type":"string","enum":["legacy_summary","projection_v2"],"title":"Pricing Operations Source","default":"legacy_summary"}},"type":"object","title":"CostPreviewResponse","description":"Lightweight cost/lead-time preview returned when preview=true.\n\nAll fields are nullable so the frontend can render a skeleton or\nplaceholder when geometry or process is not yet available."},"CoverageReport":{"properties":{"covered":{"items":{"type":"string"},"type":"array","title":"Covered"},"uncovered":{"items":{"$ref":"#/components/schemas/UncoveredFeature"},"type":"array","title":"Uncovered"},"mode":{"type":"string","enum":["warn","strict"],"title":"Mode"},"covered_ratio":{"type":"number","title":"Covered Ratio"},"outside_envelope":{"items":{"$ref":"#/components/schemas/UncoveredFeature"},"type":"array","title":"Outside Envelope"}},"type":"object","required":["covered","uncovered","mode","covered_ratio"],"title":"CoverageReport","description":"Which detected cuttable features the CamSpec addressed vs. missed.\n\nProduced in warn mode on every successful CAM run and stashed on\n``cam_artifacts.coverage_report``. ``covered_ratio`` is over the\n*cuttable* denominator only — non-v1-cuttable features (fillet,\nchamfer, …) live in ``outside_envelope`` and never count against it."},"CreatePaymentOnBehalfRequest":{"properties":{"method":{"type":"string","const":"manual","title":"Method"},"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*(?:\\d{0,10}|(?=[\\d.]{1,13}0*$)\\d{0,10}\\.\\d{0,2}0*$)"}],"title":"Amount"},"order_placed_at":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Order Placed At"}},"type":"object","required":["method","amount"],"title":"CreatePaymentOnBehalfRequest","description":"Admin request to create a payment record for a project with none.\n\nUsed when a project was force-advanced past the payment flow (the\nforce-status override never creates a ``payments`` row) so the admin\nPayment panel is stuck in a dead \"pending\" state. This is a\n**reconciliation override**: it does NOT require an APPROVED/reviewed\nquote — a force-advanced project's quote is typically\n``changes_requested`` / unreviewed. The admin records the\nout-of-band settlement ``amount`` directly (the editable field defaults\nto the latest quote's grand total client-side); the payment is linked\nto the project's latest quote (any status) to satisfy the non-null\n``Payment.quote_id`` FK. A project with no quote at all is rejected\nwith a 400 ``no_quote``.\n\nThe entered ``amount`` is the **settlement total**: it is stamped as\nboth ``Payment.amount`` and ``Payment.total_with_tax`` with no tax\nbreakout (``tax_amount = NULL``) — no fabricated split from a stale\nquote.\n\nThis endpoint creates a MANUAL (out-of-band — wire/check/ACH/paid-\nelsewhere) record that supports issue-invoice + mark-invoice-paid but\nhas no PO doc and skips confirm-PO. Purchase-order records are created\nvia the separate ``upload-po-on-behalf`` flow (the admin attaches the\ncustomer PO doc + number there), NOT here — routing a force-advanced\nproject back through the PO submit path would regress it to\nAWAITING_CONFIRMATION and fire a spurious ``on_po_submitted``\nnotification. ``method`` is therefore constrained to ``\"manual\"``;\na ``\"purchase_order\"`` body now 422s."},"CriticalFeatureEntry":{"properties":{"feature_id":{"type":"string","title":"Feature Id"},"reason":{"type":"string","maxLength":500,"title":"Reason"},"source_certainty":{"type":"string","enum":["user_asserted","user_hypothetical","agent_inferred"],"title":"Source Certainty"}},"type":"object","required":["feature_id","reason","source_certainty"],"title":"CriticalFeatureEntry"},"CriticalSurfaceCreate":{"properties":{"face_id":{"type":"string","minLength":1,"title":"Face Id","description":"Topology face ID (e.g. ``face_7``)."},"is_critical":{"type":"boolean","title":"Is Critical","description":"Set True to mark as critical, False to un-mark an existing critical designation."}},"type":"object","required":["face_id","is_critical"],"title":"CriticalSurfaceCreate","description":"Payload for ``POST /parts/{part_id}/critical-surfaces``."},"CriticalSurfaceRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"face_id":{"type":"string","title":"Face Id"},"is_critical":{"type":"boolean","title":"Is Critical"},"state":{"type":"string","title":"State"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","part_id","cad_file_version_id","face_id","is_critical","state","created_at","updated_at"],"title":"CriticalSurfaceRead","description":"Response projection for a critical surface OutcomeEvent."},"CustomerDetail":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_activity_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Activity At"},"last_sign_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Sign In At"},"total_orders":{"type":"integer","title":"Total Orders"},"total_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Revenue"},"committed_orders":{"type":"integer","title":"Committed Orders","default":0},"committed_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Revenue","default":"0"},"committed_unpaid_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Unpaid Revenue","default":"0"},"brokered_orders":{"type":"integer","title":"Brokered Orders","default":0},"brokered_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Brokered Revenue","default":"0"},"open_quotes":{"type":"integer","title":"Open Quotes"},"lost_quotes":{"type":"integer","title":"Lost Quotes"},"last_outreach_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Outreach At"},"last_outreach_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Outreach Kind"},"stats_computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Stats Computed At"},"suppressions":{"items":{"$ref":"#/components/schemas/SuppressionItem"},"type":"array","title":"Suppressions"},"timeline":{"items":{"$ref":"#/components/schemas/TimelineEntry"},"type":"array","title":"Timeline"}},"type":"object","required":["user_id","name","email","company","status","created_at","last_activity_at","last_sign_in_at","total_orders","total_revenue","open_quotes","lost_quotes","last_outreach_at","stats_computed_at","suppressions","timeline"],"title":"CustomerDetail"},"DashboardStats":{"properties":{"total_users":{"type":"integer","title":"Total Users","default":0},"active_users":{"type":"integer","title":"Active Users","default":0},"total_projects":{"type":"integer","title":"Total Projects","default":0},"projects_by_status":{"additionalProperties":{"type":"integer"},"type":"object","title":"Projects By Status","default":{}},"pending_quotes":{"type":"integer","title":"Pending Quotes","default":0},"total_cad_files":{"type":"integer","title":"Total Cad Files","default":0},"cad_files_by_format":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cad Files By Format","default":{}},"recent_activity":{"items":{"$ref":"#/components/schemas/RecentActivityItem"},"type":"array","title":"Recent Activity","default":[]}},"type":"object","title":"DashboardStats","description":"Aggregate stats for the admin dashboard."},"DesignIntentPatch":{"properties":{"purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purpose"},"primary_function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Function"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment"},"critical_features":{"anyOf":[{"items":{"$ref":"#/components/schemas/CriticalFeatureEntry"},"type":"array"},{"type":"null"}],"title":"Critical Features"},"mating_surfaces":{"anyOf":[{"items":{"$ref":"#/components/schemas/MatingSurfaceEntry"},"type":"array"},{"type":"null"}],"title":"Mating Surfaces"},"load_paths":{"anyOf":[{"items":{"$ref":"#/components/schemas/LoadPathEntry"},"type":"array"},{"type":"null"}],"title":"Load Paths"},"tolerance_rationale":{"anyOf":[{"items":{"$ref":"#/components/schemas/ToleranceRationaleEntry"},"type":"array"},{"type":"null"}],"title":"Tolerance Rationale"},"performance_requirements":{"anyOf":[{"items":{"$ref":"#/components/schemas/PerformanceRequirementEntry"},"type":"array"},{"type":"null"}],"title":"Performance Requirements"},"free_text_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Free Text Notes"}},"type":"object","title":"DesignIntentPatch","description":"Human-edit PATCH body (inline chip edits).\n\nThe user may omit any field. Must NOT include ``interview_status``,\n``confidence_score``, ``source_certainty`` directly, or any inferred_*\nfield — those are agent-only. Edits to list entries promote their\n``source_certainty`` to ``user_asserted`` automatically in the service\nlayer."},"DesignIntentRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"type":"string","format":"uuid","title":"Cad File Version Id"},"captured_via_conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Captured Via Conversation Id"},"interview_status":{"type":"string","enum":["not_started","in_progress","completed","skipped","superseded","carry_forward_pending"],"title":"Interview Status"},"nudge_dismissed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Nudge Dismissed At"},"inferred_purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inferred Purpose"},"inferred_primary_function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inferred Primary Function"},"purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purpose"},"primary_function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Function"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment"},"critical_features":{"items":{"$ref":"#/components/schemas/CriticalFeatureEntry"},"type":"array","title":"Critical Features"},"mating_surfaces":{"items":{"$ref":"#/components/schemas/MatingSurfaceEntry"},"type":"array","title":"Mating Surfaces"},"load_paths":{"items":{"$ref":"#/components/schemas/LoadPathEntry"},"type":"array","title":"Load Paths"},"tolerance_rationale":{"items":{"$ref":"#/components/schemas/ToleranceRationaleEntry"},"type":"array","title":"Tolerance Rationale"},"performance_requirements":{"items":{"$ref":"#/components/schemas/PerformanceRequirementEntry"},"type":"array","title":"Performance Requirements"},"free_text_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Free Text Notes"},"confidence_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence Score"},"fields_captured_count":{"type":"integer","title":"Fields Captured Count"},"questions_asked":{"type":"integer","title":"Questions Asked"},"passive_writes_count":{"type":"integer","title":"Passive Writes Count"},"interview_started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Interview Started At"},"interview_completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Interview Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","part_id","cad_file_version_id","captured_via_conversation_id","interview_status","nudge_dismissed_at","inferred_purpose","inferred_primary_function","purpose","primary_function","environment","critical_features","mating_surfaces","load_paths","tolerance_rationale","performance_requirements","free_text_notes","confidence_score","fields_captured_count","questions_asked","passive_writes_count","interview_started_at","interview_completed_at","created_at","updated_at"],"title":"DesignIntentRead","description":"Full DesignIntent state sent to the frontend."},"DesignIntentSummary":{"properties":{"purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purpose"},"primary_function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Function"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment"},"critical_features":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Critical Features"},"mating_surfaces":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Mating Surfaces"},"load_paths":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Load Paths"},"tolerance_rationale":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Tolerance Rationale"},"free_text_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Free Text Notes"},"interview_status":{"type":"string","title":"Interview Status"}},"type":"object","required":["critical_features","mating_surfaces","load_paths","tolerance_rationale","interview_status"],"title":"DesignIntentSummary"},"DfmAcknowledgment":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"action":{"type":"string","title":"Action"},"finding_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finding Id"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"outcome_type":{"type":"string","title":"Outcome Type"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","action","outcome_type","created_at"],"title":"DfmAcknowledgment"},"DfmCheckRequest":{"properties":{"process_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Process Id"},"material_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Id"},"quantity":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Quantity"}},"type":"object","title":"DfmCheckRequest","description":"Request body for POST /parts/{part_id}/dfm-check."},"DfmCheckResponse":{"properties":{"process":{"type":"string","title":"Process"},"material":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material"},"findings":{"items":{"$ref":"#/components/schemas/DfmFinding"},"type":"array","title":"Findings"},"dfm_score":{"type":"string","title":"Dfm Score"},"score_breakdown":{"$ref":"#/components/schemas/ScoreBreakdown"},"highlight_overlay":{"items":{"$ref":"#/components/schemas/DfmHighlightItem"},"type":"array","title":"Highlight Overlay"},"cost_estimate":{"anyOf":[{"$ref":"#/components/schemas/CostEstimate"},{"type":"null"}]},"lead_time":{"anyOf":[{"$ref":"#/components/schemas/LeadTimeEstimate"},{"type":"null"}]},"manual_quote_required":{"type":"boolean","title":"Manual Quote Required","default":false},"manual_quote_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manual Quote Message"},"checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checked At"},"is_2d_file":{"type":"boolean","title":"Is 2D File","default":false},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"feature_source":{"type":"string","enum":["legacy","projection_v2"],"title":"Feature Source","default":"legacy"},"suppressed_uncertain_count":{"type":"integer","title":"Suppressed Uncertain Count","default":0},"review_items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Review Items"}},"type":"object","required":["process","dfm_score","score_breakdown"],"title":"DfmCheckResponse","description":"Response for POST /parts/{part_id}/dfm-check."},"DfmFinding":{"properties":{"rule_id":{"type":"string","title":"Rule Id"},"severity":{"type":"string","title":"Severity"},"description":{"type":"string","title":"Description"},"measured_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measured Value"},"threshold_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold Value"},"unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unit"},"feature_ref":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Feature Ref"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"feature_ids":{"items":{"type":"string"},"type":"array","title":"Feature Ids","description":"Stable feature IDs represented by a grouped finding"},"face_indices":{"items":{"type":"integer"},"type":"array","title":"Face Indices"},"centroid":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Centroid"},"suggestion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggestion"},"occurrence_count":{"type":"integer","title":"Occurrence Count","description":"Number of repeated feature occurrences represented by this finding","default":1},"review_required":{"type":"boolean","title":"Review Required","description":"True when the finding is not an automatic failure but needs manufacturing review","default":false},"presentation_category":{"type":"string","enum":["blocker","review","cost_note"],"title":"Presentation Category","description":"How the finding should be presented to users and admins","default":"review"},"cost_direction":{"type":"string","enum":["neutral","higher_cost","higher_lead_time"],"title":"Cost Direction","description":"Display-only hint for which way this finding pushes the quote (cost vs lead time). Presentation parity with Xometry/Fictiv; never gates an order.","default":"higher_cost"},"confidence":{"type":"string","enum":["high","medium","low"],"title":"Confidence","description":"Confidence level for the finding after rule post-processing","default":"medium"},"confidence_score":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Confidence Score","description":"Optional numeric confidence score in the range 0-1"},"score_weight":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Score Weight","description":"Optional scoring weight used after grouping repeated findings"},"standard_refs":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Standard Refs","description":"Industry standards for this finding"}},"type":"object","required":["rule_id","severity","description"],"title":"DfmFinding","description":"A single DFM rule finding."},"DfmHighlightItem":{"properties":{"feature_ref":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Feature Ref"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"bbox":{"anyOf":[{"additionalProperties":{"items":{"type":"number"},"type":"array"},"type":"object"},{"type":"null"}],"title":"Bbox"},"centroid":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Centroid"},"color":{"type":"string","title":"Color"},"severity":{"type":"string","title":"Severity"},"label":{"type":"string","title":"Label"}},"type":"object","required":["color","severity","label"],"title":"DfmHighlightItem","description":"A single 3D highlight overlay item."},"DfmHighlightsResponse":{"properties":{"highlights":{"items":{"$ref":"#/components/schemas/DfmHighlightItem"},"type":"array","title":"Highlights"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"}},"type":"object","title":"DfmHighlightsResponse","description":"Response for GET /parts/{part_id}/dfm-highlights."},"DownloadUrlResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Presigned download URL"},"expires_in":{"type":"integer","title":"Expires In","description":"URL expiry in seconds"}},"type":"object","required":["url","expires_in"],"title":"DownloadUrlResponse","description":"Presigned download URL returned to the client for R2 object retrieval.\n\nThe client should GET the file from ``url`` before the TTL expires."},"DrawingDownloadResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Presigned download URL"},"expires_in":{"type":"integer","title":"Expires In","description":"URL expiry in seconds"}},"type":"object","required":["url","expires_in"],"title":"DrawingDownloadResponse","description":"Presigned download URL returned to the client for drawing retrieval."},"DrawingModelConflictResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"conflict_type":{"type":"string","title":"Conflict Type"},"category":{"type":"string","title":"Category"},"suspected_cause":{"type":"string","title":"Suspected Cause"},"severity":{"type":"string","title":"Severity"},"status":{"type":"string","title":"Status"},"drawing_says":{"additionalProperties":true,"type":"object","title":"Drawing Says"},"model_says":{"additionalProperties":true,"type":"object","title":"Model Says"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"resolution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Resolution"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","part_id","conflict_type","category","suspected_cause","severity","status","drawing_says","model_says","evidence","created_at","updated_at"],"title":"DrawingModelConflictResponse"},"DropdownListResponse":{"properties":{"machining_processes":{"items":{"$ref":"#/components/schemas/DropdownResponse"},"type":"array","title":"Machining Processes","default":[]},"materials":{"items":{"$ref":"#/components/schemas/DropdownResponse"},"type":"array","title":"Materials","default":[]},"finishings":{"items":{"$ref":"#/components/schemas/DropdownResponse"},"type":"array","title":"Finishings","default":[]},"coatings":{"items":{"$ref":"#/components/schemas/DropdownResponse"},"type":"array","title":"Coatings","default":[]}},"type":"object","title":"DropdownListResponse","description":"All dropdown options grouped by category.\n\nThe frontend fetches this once on load and caches it to populate\nthe machining-process, material, finishing, and coating select inputs."},"DropdownResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"category":{"type":"string","title":"Category"},"label":{"type":"string","title":"Label"},"value":{"type":"string","title":"Value"},"sort_order":{"type":"integer","title":"Sort Order"}},"type":"object","required":["id","category","label","value","sort_order"],"title":"DropdownResponse","description":"A single dropdown option.\n\nMaps to a row in the ``dropdowns`` table.  Only active options\n(``is_active=True``) are returned by the public endpoints, so\n``is_active`` is intentionally excluded from this schema."},"EdgeNoteCreate":{"properties":{"edge_id":{"type":"string","minLength":1,"title":"Edge Id","description":"Topology edge ID (e.g. ``edge_17``)."},"note_text":{"type":"string","maxLength":2000,"minLength":1,"title":"Note Text"},"note_type":{"type":"string","enum":["general","weld"],"title":"Note Type","default":"general"},"weld_process":{"anyOf":[{"type":"string","enum":["tig","mig","spot","laser","other"]},{"type":"null"}],"title":"Weld Process","description":"Required when note_type='weld'. Ignored otherwise."}},"type":"object","required":["edge_id","note_text"],"title":"EdgeNoteCreate","description":"Payload for ``POST /parts/{part_id}/edge-notes``."},"EdgeNoteRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"edge_id":{"type":"string","title":"Edge Id"},"note_text":{"type":"string","title":"Note Text"},"note_type":{"type":"string","title":"Note Type"},"weld_process":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Weld Process"},"state":{"type":"string","title":"State"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","part_id","cad_file_version_id","edge_id","note_text","note_type","weld_process","state","created_at","updated_at"],"title":"EdgeNoteRead","description":"Response projection for an edge note OutcomeEvent."},"EdgeToleranceCreate":{"properties":{"edge_id":{"type":"string","minLength":3,"title":"Edge Id","description":"Topology edge ID (e.g. 'edge_7') — looked up in the topology sidecar JSON."},"tolerance_type":{"type":"string","title":"Tolerance Type","description":"One of EDGE_TOLERANCE_TYPES: as_machined, break_light, break_medium, break_heavy, chamfer, deburr, sharp."},"size_mm":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Size Mm","description":"Chamfer leg length in mm. Required when ``tolerance_type`` = 'chamfer'; ignored otherwise."},"angle_deg":{"anyOf":[{"type":"number","exclusiveMaximum":180.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Angle Deg","description":"Chamfer angle in degrees (0 < angle < 180). Defaults to 45° when ``tolerance_type`` = 'chamfer' and not supplied."},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["edge_id","tolerance_type"],"title":"EdgeToleranceCreate","description":"Payload for ``POST /parts/{part_id}/edge-tolerances``."},"EdgeToleranceRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"edge_id":{"type":"string","title":"Edge Id"},"tolerance_type":{"type":"string","title":"Tolerance Type"},"size_mm":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Size Mm"},"angle_deg":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Angle Deg"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"state":{"type":"string","title":"State"},"source":{"type":"string","title":"Source"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"is_process_mismatch":{"type":"boolean","title":"Is Process Mismatch","default":false}},"type":"object","required":["id","part_id","cad_file_version_id","edge_id","tolerance_type","size_mm","angle_deg","notes","label","state","source","author","created_by","created_at","updated_at"],"title":"EdgeToleranceRead","description":"Flattened edge-tolerance row — built by the service from an OutcomeEvent.\n\nNot an ORM passthrough: the source row is an ``OutcomeEvent`` with\n``data = {tolerance_type, size_mm, angle_deg, notes, ...}``. The\nprojection flattens that payload + adds the computed\n``is_process_mismatch`` flag and the resolved visual label."},"EdgeToleranceSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"edge_id":{"type":"string","title":"Edge Id"},"tolerance_type":{"type":"string","title":"Tolerance Type"},"size_mm":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Size Mm"},"angle_deg":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Angle Deg"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"},"source":{"type":"string","title":"Source"},"state":{"type":"string","title":"State"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","edge_id","tolerance_type","label","source","state","created_at"],"title":"EdgeToleranceSummary","description":"One edge-tolerance annotation. Edge-anchored OutcomeEvent.\n\nSurfaces top-level (parallel to welds + surface finishes) so the admin\ncan see the full edge-treatment list without drilling into per-feature\ncards. Edge tolerances pin to topology edge ids (\"edge_7\"), not\ndetected features, so they don't bucket cleanly under\n``annotated_features``."},"EdgeToleranceUpdate":{"properties":{"tolerance_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tolerance Type"},"size_mm":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Size Mm"},"angle_deg":{"anyOf":[{"type":"number","exclusiveMaximum":180.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Angle Deg"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"EdgeToleranceUpdate","description":"Payload for ``PATCH /edge-tolerances/{tolerance_id}``. All fields optional."},"EditPendingOrderBody":{"properties":{"snapshot_version":{"type":"integer","minimum":0.0,"title":"Snapshot Version","description":"The snapshot_version the user observed. Server returns 409 Conflict if the stored version has advanced since."},"quantity_by_part":{"anyOf":[{"additionalProperties":{"type":"integer"},"propertyNames":{"format":"uuid"},"type":"object"},{"type":"null"}],"title":"Quantity By Part","description":"Updated per-part quantities. Missing parts unchanged."},"material_by_part":{"anyOf":[{"additionalProperties":{"type":"string","format":"uuid"},"propertyNames":{"format":"uuid"},"type":"object"},{"type":"null"}],"title":"Material By Part","description":"Updated per-part material dropdown IDs."},"finish_by_part":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"propertyNames":{"format":"uuid"},"type":"object"},{"type":"null"}],"title":"Finish By Part","description":"Updated per-part finish dropdown IDs (None clears)."},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"po_number":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Po Number"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["snapshot_version"],"title":"EditPendingOrderBody","description":"User edits a pending auto-estimate order request.\n\nAllowed only while the Quote is in ``submitted`` status with\n``intent=auto_estimate``. Process and adding/removing parts are\nlocked. Editing material/finish triggers a fresh DFM evaluation\nand a recomputed cost snapshot.\n\nThe optimistic concurrency check uses ``snapshot_version`` — pass\nthe version you read so the server can detect concurrent admin\nconfirmation and reject with 409."},"ExternalCustomerDetail":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"display_name":{"type":"string","title":"Display Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"broker_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Broker User Id"},"broker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Broker Name"},"broker_count":{"type":"integer","title":"Broker Count"},"committed_orders":{"type":"integer","title":"Committed Orders"},"committed_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Revenue"},"committed_unpaid_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Unpaid Revenue"},"total_orders":{"type":"integer","title":"Total Orders"},"total_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Revenue"},"open_quotes":{"type":"integer","title":"Open Quotes"},"lost_quotes":{"type":"integer","title":"Lost Quotes"},"last_quote_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Quote At"},"last_order_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Order At"},"computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Computed At"},"timeline":{"items":{"$ref":"#/components/schemas/TimelineEntry"},"type":"array","title":"Timeline","default":[]}},"type":"object","required":["id","display_name","email","broker_user_id","broker_count","committed_orders","committed_revenue","committed_unpaid_revenue","total_orders","total_revenue","open_quotes","lost_quotes","last_quote_at","last_order_at","computed_at"],"title":"ExternalCustomerDetail"},"ExternalCustomerListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"display_name":{"type":"string","title":"Display Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"broker_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Broker User Id"},"broker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Broker Name"},"broker_count":{"type":"integer","title":"Broker Count"},"committed_orders":{"type":"integer","title":"Committed Orders"},"committed_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Revenue"},"committed_unpaid_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Committed Unpaid Revenue"},"total_orders":{"type":"integer","title":"Total Orders"},"total_revenue":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Revenue"},"open_quotes":{"type":"integer","title":"Open Quotes"},"lost_quotes":{"type":"integer","title":"Lost Quotes"},"last_quote_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Quote At"},"last_order_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Order At"},"computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Computed At"}},"type":"object","required":["id","display_name","email","broker_user_id","broker_count","committed_orders","committed_revenue","committed_unpaid_revenue","total_orders","total_revenue","open_quotes","lost_quotes","last_quote_at","last_order_at","computed_at"],"title":"ExternalCustomerListItem","description":"Override (\"external\") customer — ordered for via a platform broker."},"FeatureAnnotationSummary":{"properties":{"feature_id":{"type":"string","title":"Feature Id"},"feature_type":{"type":"string","title":"Feature Type"},"feature_subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Subtype"},"dimensions":{"additionalProperties":true,"type":"object","title":"Dimensions"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence"},"notes":{"items":{"$ref":"#/components/schemas/FeatureNote"},"type":"array","title":"Notes"},"tolerances":{"items":{"$ref":"#/components/schemas/ToleranceSpec"},"type":"array","title":"Tolerances"},"reclassifications":{"items":{"$ref":"#/components/schemas/Reclassification"},"type":"array","title":"Reclassifications"},"dfm_acknowledgments":{"items":{"$ref":"#/components/schemas/DfmAcknowledgment"},"type":"array","title":"Dfm Acknowledgments"},"callouts":{"items":{"$ref":"#/components/schemas/CalloutSummary"},"type":"array","title":"Callouts"},"has_surface_finish":{"type":"boolean","title":"Has Surface Finish","default":false}},"type":"object","required":["feature_id","feature_type","dimensions","notes","tolerances","reclassifications","dfm_acknowledgments","callouts"],"title":"FeatureAnnotationSummary"},"FeatureCorrectionRequest":{"properties":{"action":{"type":"string","enum":["confirm","dismiss","reclassify"],"title":"Action"},"new_class":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Class","description":"Required when action='reclassify'. Must be a value from FeatureClass taxonomy."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Optional free-form note from user."}},"type":"object","required":["action"],"title":"FeatureCorrectionRequest","description":"Phase 0: confirm / dismiss / reclassify a single feature on a card."},"FeatureCorrectionResponse":{"properties":{"correction_id":{"type":"string","title":"Correction Id"},"feature_id":{"type":"string","title":"Feature Id"},"action":{"type":"string","enum":["confirm","dismiss","reclassify"],"title":"Action"},"geometry_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geometry Fingerprint"},"source":{"type":"string","enum":["user_correction","admin_label"],"title":"Source"}},"type":"object","required":["correction_id","feature_id","action","source"],"title":"FeatureCorrectionResponse","description":"What the frontend gets back after recording a correction."},"FeatureNote":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"note":{"type":"string","title":"Note"},"author":{"type":"string","title":"Author"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","note","author","created_at"],"title":"FeatureNote"},"FeatureResponse":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Version Id"},"detected_features":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Detected Features"}},"type":"object","required":["part_id"],"title":"FeatureResponse","description":"Response for GET /parts/{part_id}/features."},"FinishResponse":{"properties":{"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id","description":"Underlying ``Dropdown.id`` (either finishing_id or coating_id)."},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug","description":"Underlying ``Dropdown.value`` slug."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Human-readable label for the finish."},"category":{"anyOf":[{"type":"string","enum":["finishing","coating"]},{"type":"null"}],"title":"Category","description":"Whether this finish is mechanical or a coating bath."},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color","description":"Currently selected color name (e.g. 'Black', 'Custom'). Mirrors ``Part.coating_color``."},"color_options":{"items":{"$ref":"#/components/schemas/ColorOption"},"type":"array","title":"Color Options","description":"Available colors for this finish. Empty list means no color picker (mechanical finish or color-locked plating)."},"default_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Color","description":"Pre-selected color when this finish is chosen."},"custom_color_surcharge":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Custom Color Surcharge","description":"One-time USD adder when the user picks 'Custom' RAL/Pantone. None disables the Custom path."},"custom_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Name","description":"Free-text custom finish descriptor (mirrors ``Part.custom_coating_name``)."},"spec":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec","description":"MIL-spec / drawing callout (mirrors ``Part.coating_spec``)."}},"type":"object","title":"FinishResponse","description":"Computed unified finish view of a Part for the frontend.\n\nAll fields default to ``None`` / empty so a part with no finish set\nserialises cleanly. ``category`` distinguishes mechanical surface\nfinish from bath/coating; ``color_options`` is empty for mechanical\nfinishes and color-locked platings."},"FinishUpdate":{"properties":{"finish_dropdown_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finish Dropdown Id","description":"Selected dropdown row id. Must reference an active 'finishing' or 'coating' Dropdown. Set to null to clear the finish."},"color":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Color","description":"Selected color name (must match one of the dropdown's ``color_options[].name`` values, or the literal 'Custom')."},"custom_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Custom Name","description":"Free-text custom finish descriptor."},"spec":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Spec","description":"MIL-spec or drawing callout."}},"type":"object","title":"FinishUpdate","description":"Request body for ``PATCH /parts/{id}/finish``.\n\nA single finish-dropdown row is selected (from either category) and\nthe backend decomposes it onto ``finishing_id`` / ``coating_id``.\n\nSending ``finish_dropdown_id=None`` clears the finish entirely\n(nulls both columns plus color/custom/spec)."},"FollowupEmailOverrideRequest":{"properties":{"subject":{"type":"string","maxLength":500,"title":"Subject"},"html":{"type":"string","maxLength":500000,"title":"Html"}},"type":"object","required":["subject","html"],"title":"FollowupEmailOverrideRequest","description":"Admin-edited subject/HTML from the drawer WYSIWYG editor."},"FollowupEmailPreview":{"properties":{"subject":{"type":"string","title":"Subject"},"html":{"type":"string","title":"Html"},"template_name":{"type":"string","title":"Template Name"},"has_override":{"type":"boolean","title":"Has Override"},"editable":{"type":"boolean","title":"Editable"}},"type":"object","required":["subject","html","template_name","has_override","editable"],"title":"FollowupEmailPreview","description":"Rendered follow-up email — exactly what a send at this moment\nproduces (or reproduced from the snapshot for already-sent tasks)."},"FollowupEventItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"event_type":{"type":"string","title":"Event Type"},"actor_type":{"type":"string","title":"Actor Type"},"actor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Id"},"event_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Event Metadata"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","event_type","actor_type","actor_id","event_metadata","created_at"],"title":"FollowupEventItem"},"FollowupRuleMode":{"type":"string","enum":["disabled","review_required","auto_send"],"title":"FollowupRuleMode","description":"Per-rule runtime mode, DB-backed (rule definitions live in code)."},"FollowupStats":{"properties":{"due_now":{"type":"integer","title":"Due Now"},"scheduled":{"type":"integer","title":"Scheduled"},"snoozed":{"type":"integer","title":"Snoozed"},"sent_30d":{"type":"integer","title":"Sent 30D"},"suppressed":{"type":"integer","title":"Suppressed"},"failed":{"type":"integer","title":"Failed"}},"type":"object","required":["due_now","scheduled","snoozed","sent_30d","suppressed","failed"],"title":"FollowupStats"},"FollowupTaskDetail":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"rule_slug":{"type":"string","title":"Rule Slug"},"audience":{"type":"string","title":"Audience"},"category":{"type":"string","title":"Category"},"status":{"type":"string","title":"Status"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"customer_name":{"type":"string","title":"Customer Name"},"customer_email":{"type":"string","title":"Customer Email"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Quote Id"},"due_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due At"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"snoozed_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Snoozed Until"},"eligibility_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eligibility Reason"},"suppression_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suppression Reason"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"retry_count":{"type":"integer","title":"Retry Count"},"email_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email To"},"subject_snapshot":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject Snapshot"},"provider_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"template_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name"},"template_variables":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Template Variables"},"events":{"items":{"$ref":"#/components/schemas/FollowupEventItem"},"type":"array","title":"Events"}},"type":"object","required":["id","rule_slug","audience","category","status","user_id","customer_name","customer_email","company","project_id","project_name","quote_id","due_at","sent_at","snoozed_until","eligibility_reason","suppression_reason","failure_reason","retry_count","email_to","subject_snapshot","provider_status","created_at","template_name","template_variables","events"],"title":"FollowupTaskDetail"},"FollowupTaskListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"rule_slug":{"type":"string","title":"Rule Slug"},"audience":{"type":"string","title":"Audience"},"category":{"type":"string","title":"Category"},"status":{"type":"string","title":"Status"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"customer_name":{"type":"string","title":"Customer Name"},"customer_email":{"type":"string","title":"Customer Email"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Quote Id"},"due_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due At"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"snoozed_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Snoozed Until"},"eligibility_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eligibility Reason"},"suppression_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suppression Reason"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"retry_count":{"type":"integer","title":"Retry Count"},"email_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email To"},"subject_snapshot":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject Snapshot"},"provider_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","rule_slug","audience","category","status","user_id","customer_name","customer_email","company","project_id","project_name","quote_id","due_at","sent_at","snoozed_until","eligibility_reason","suppression_reason","failure_reason","retry_count","email_to","subject_snapshot","provider_status","created_at"],"title":"FollowupTaskListItem"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"version":{"type":"string","title":"Version"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","required":["status","version","timestamp"],"title":"HealthResponse","description":"Response model for the health check endpoint."},"InboundPackageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"inbound_shipment_id":{"type":"string","format":"uuid","title":"Inbound Shipment Id"},"package_index":{"type":"integer","title":"Package Index"},"carrier_piece_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Piece Id"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"weight":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Weight"},"weight_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Weight Unit"},"length":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Length"},"width":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Height"},"dimension_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dimension Unit"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["id","inbound_shipment_id","package_index"],"title":"InboundPackageResponse"},"InboundShipmentCreate":{"properties":{"carrier":{"$ref":"#/components/schemas/CarrierCode","default":"other"},"tracking_number":{"type":"string","maxLength":255,"minLength":1,"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"}},"type":"object","required":["tracking_number"],"title":"InboundShipmentCreate"},"InboundShipmentEventResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"inbound_shipment_id":{"type":"string","format":"uuid","title":"Inbound Shipment Id"},"carrier_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Event Id"},"status":{"$ref":"#/components/schemas/ShipmentStatus"},"description":{"type":"string","title":"Description"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"occurred_at":{"type":"string","format":"date-time","title":"Occurred At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","inbound_shipment_id","status","description","occurred_at","created_at"],"title":"InboundShipmentEventResponse"},"InboundShipmentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"supplier_order_id":{"type":"string","format":"uuid","title":"Supplier Order Id"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"carrier":{"$ref":"#/components/schemas/CarrierCode"},"tracking_number":{"type":"string","title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"status":{"$ref":"#/components/schemas/ShipmentStatus"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"last_known_location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Known Location"},"origin_location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin Location"},"destination_location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destination Location"},"service_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Service Name"},"last_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Synced At"},"sync_status":{"$ref":"#/components/schemas/CarrierSyncStatus"},"sync_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sync Error"},"packages":{"items":{"$ref":"#/components/schemas/InboundPackageResponse"},"type":"array","title":"Packages"},"events":{"items":{"$ref":"#/components/schemas/InboundShipmentEventResponse"},"type":"array","title":"Events"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","supplier_order_id","supplier_contact_id","carrier","tracking_number","status","sync_status","created_at","updated_at"],"title":"InboundShipmentResponse"},"InboundShipmentUpdate":{"properties":{"carrier":{"anyOf":[{"$ref":"#/components/schemas/CarrierCode"},{"type":"null"}]},"tracking_number":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"},"status":{"anyOf":[{"$ref":"#/components/schemas/ShipmentStatus"},{"type":"null"}]},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"last_known_location":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Known Location"}},"type":"object","title":"InboundShipmentUpdate"},"IngestAssumption":{"properties":{"id":{"type":"string","title":"Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"question_callout_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question Callout Id"}},"type":"object","required":["id","feature_id","label","question_callout_id"],"title":"IngestAssumption"},"IngestRunPartSummary":{"properties":{"part_id":{"type":"string","title":"Part Id"},"part_name":{"type":"string","title":"Part Name"},"version_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version Id"},"feature_count":{"type":"integer","title":"Feature Count"},"feature_summary":{"additionalProperties":{"type":"integer"},"type":"object","title":"Feature Summary"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"questions_pending":{"type":"integer","title":"Questions Pending"},"spec_proposal_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Proposal Source"},"assumptions":{"items":{"$ref":"#/components/schemas/IngestAssumption"},"type":"array","title":"Assumptions"}},"type":"object","required":["part_id","part_name","version_id","feature_count","feature_summary","dfm_score","questions_pending","assumptions"],"title":"IngestRunPartSummary"},"IngestRunResponse":{"properties":{"parts":{"items":{"$ref":"#/components/schemas/IngestRunPartSummary"},"type":"array","title":"Parts"},"project_intent":{"$ref":"#/components/schemas/ProjectIntentStatus"}},"type":"object","required":["parts","project_intent"],"title":"IngestRunResponse"},"InitiateAssemblyUploadRequest":{"properties":{"file_name":{"type":"string","maxLength":500,"minLength":1,"title":"File Name","description":"Original file name including extension (e.g. 'main_assembly.step')."},"content_type":{"type":"string","minLength":1,"title":"Content Type","description":"MIME type of the file (e.g. 'application/octet-stream')."},"file_size":{"type":"integer","maximum":52428800.0,"exclusiveMinimum":0.0,"title":"File Size","description":"Exact file size in bytes. Must not exceed 50 MB."}},"type":"object","required":["file_name","content_type","file_size"],"title":"InitiateAssemblyUploadRequest","description":"Request body to obtain a presigned R2 upload URL for an assembly file.\n\nHard-replace semantics: if the project already has an assembly file,\nthe existing R2 object + DB row are deleted as part of this call."},"InitiateAssemblyUploadResponse":{"properties":{"assembly_file_id":{"type":"string","format":"uuid","title":"Assembly File Id"},"r2_key":{"type":"string","title":"R2 Key"}},"type":"object","required":["assembly_file_id","r2_key"],"title":"InitiateAssemblyUploadResponse","description":"Response from the initiate-upload endpoint.\n\nThe client streams the raw file bytes to the proxy upload endpoint\n``POST /projects/{project_id}/assembly-file/upload`` and then calls\nconfirm-upload with ``assembly_file_id`` and ``r2_key``."},"InitiateDrawingUploadRequest":{"properties":{"file_name":{"type":"string","maxLength":500,"minLength":1,"title":"File Name","description":"Original file name including extension (e.g. 'drawing.pdf')."},"content_type":{"type":"string","minLength":1,"title":"Content Type","description":"MIME type of the file (e.g. 'application/pdf')."},"file_size":{"type":"integer","maximum":52428800.0,"exclusiveMinimum":0.0,"title":"File Size","description":"Exact file size in bytes.  Must not exceed 50 MB."}},"type":"object","required":["file_name","content_type","file_size"],"title":"InitiateDrawingUploadRequest","description":"Request body to obtain a presigned R2 upload URL for a drawing.\n\nThe client provides the original file name, MIME type, and exact size\nso the backend can validate the extension and size *before* generating\nthe presigned URL."},"InitiateDrawingUploadResponse":{"properties":{"r2_key":{"type":"string","title":"R2 Key","description":"The R2 object key where the file will be stored."}},"type":"object","required":["r2_key"],"title":"InitiateDrawingUploadResponse","description":"R2 key returned to the client to begin a drawing upload.\n\nThe client streams the raw file bytes to the proxy upload endpoint\n``POST /parts/{part_id}/drawings/upload`` and then calls the confirm\nendpoint with ``r2_key``."},"InitiateProjectDocumentUploadRequest":{"properties":{"file_name":{"type":"string","maxLength":500,"minLength":1,"title":"File Name"},"content_type":{"type":"string","minLength":1,"title":"Content Type"},"file_size":{"type":"integer","maximum":52428800.0,"exclusiveMinimum":0.0,"title":"File Size"}},"type":"object","required":["file_name","content_type","file_size"],"title":"InitiateProjectDocumentUploadRequest"},"InitiateProjectDocumentUploadResponse":{"properties":{"document_id":{"type":"string","format":"uuid","title":"Document Id"},"r2_key":{"type":"string","title":"R2 Key"}},"type":"object","required":["document_id","r2_key"],"title":"InitiateProjectDocumentUploadResponse"},"InitiateUploadRequest":{"properties":{"file_name":{"type":"string","maxLength":500,"minLength":1,"title":"File Name","description":"Original file name including extension (e.g. 'bracket_v2.step')."},"content_type":{"type":"string","minLength":1,"title":"Content Type","description":"MIME type of the file (e.g. 'application/octet-stream')."},"file_size":{"type":"integer","maximum":20971520.0,"exclusiveMinimum":0.0,"title":"File Size","description":"Exact file size in bytes.  Must not exceed 20 MB."}},"type":"object","required":["file_name","content_type","file_size"],"title":"InitiateUploadRequest","description":"Request body to obtain a presigned R2 upload URL.\n\nThe client provides the original file name, MIME type, and exact size\nso the backend can validate the extension and size *before* generating\nthe presigned URL.  This prevents wasted bandwidth on files that would\nbe rejected after upload."},"InitiateUploadResponse":{"properties":{"r2_key":{"type":"string","title":"R2 Key","description":"The R2 object key where the file will be stored."},"version_id":{"type":"string","format":"uuid","title":"Version Id","description":"Newly created CadFileVersion ID to reference in subsequent calls."}},"type":"object","required":["r2_key","version_id"],"title":"InitiateUploadResponse","description":"R2 key and metadata returned to the client to begin a CAD upload.\n\nThe client streams the raw file bytes to the proxy upload endpoint\n``POST /parts/{part_id}/cad/upload/{version_id}`` and then calls the\nconfirm endpoint with ``version_id`` and ``r2_key``."},"InterviewStartRequest":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"}},"type":"object","required":["part_id"],"title":"InterviewStartRequest","description":"POST body for the intent-interview kick-off endpoint."},"InviteValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"}},"type":"object","required":["valid"],"title":"InviteValidationResponse","description":"Response from invite token validation."},"InvoiceLineItemsBody":{"properties":{"additional_line_items_post_tax":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Input"},"type":"array"},{"type":"null"}],"title":"Additional Line Items Post Tax"}},"type":"object","title":"InvoiceLineItemsBody","description":"Optional request body for issue / regenerate-invoice endpoints carrying\nadmin-entered post-tax line items (shipping, expedite, …).\n\n``additional_line_items_post_tax`` semantics on **regenerate**: ``None``\n(field omitted) leaves the invoice's stored items unchanged; ``[]`` clears\nthem; a non-empty list replaces them. On **issue**, ``None``/omitted = no\nextras."},"InvoiceResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"payment_id":{"type":"string","format":"uuid","title":"Payment Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"invoice_number":{"type":"string","title":"Invoice Number"},"display_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Number"},"status":{"type":"string","title":"Status"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"subtotal":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Subtotal"},"tax_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Amount"},"tax_rate":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Rate"},"tax_excluded":{"type":"boolean","title":"Tax Excluded","default":false},"additional_line_items_post_tax":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Output"},"type":"array"},{"type":"null"}],"title":"Additional Line Items Post Tax"},"currency":{"type":"string","title":"Currency"},"issued_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Issued At"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"invoice_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Pdf Url"},"pdf_generated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Pdf Generated At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","payment_id","project_id","invoice_number","status","amount","currency","created_at","updated_at"],"title":"InvoiceResponse","description":"Invoice summary returned in payment detail views.\n\n``invoice_number`` is the sequential accounting identifier\n(``INV-YYYY-NNNNN``) and stays stable in the DB for accounting\nreconciliation. ``display_number`` is the project-derived short\nform (``INV-{project_id_first8}``) shown in the UI and on PDFs so\nquote + invoice + project share a visually-consistent identifier.\nBackend resolves ``display_number`` at response build time —\nfrontends should prefer it for display and only surface\n``invoice_number`` if accounting context is needed."},"LabelStatus":{"type":"string","enum":["not_created","creating","created","voiding","voided","failed"],"title":"LabelStatus"},"LabeledDatasetRow":{"properties":{"step_r2_key":{"type":"string","title":"Step R2 Key"},"version_id":{"type":"string","title":"Version Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"geometry_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geometry Fingerprint"},"feature_geometry":{"additionalProperties":true,"type":"object","title":"Feature Geometry"},"predicted_class":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Predicted Class"},"ground_truth_class":{"type":"string","title":"Ground Truth Class"},"subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtype"},"source":{"type":"string","title":"Source"},"outcome_type":{"type":"string","title":"Outcome Type"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["step_r2_key","version_id","feature_id","geometry_fingerprint","feature_geometry","predicted_class","ground_truth_class","subtype","source","outcome_type","created_at"],"title":"LabeledDatasetRow"},"LeadTimeEstimate":{"properties":{"standard_days":{"type":"integer","title":"Standard Days"},"options":{"additionalProperties":{"$ref":"#/components/schemas/LeadTimeOption"},"type":"object","title":"Options"},"total_minutes":{"type":"number","title":"Total Minutes","default":0.0},"complexity":{"type":"string","title":"Complexity","default":"medium"},"breakdown_detail":{"additionalProperties":true,"type":"object","title":"Breakdown Detail"},"buffer_days":{"type":"integer","title":"Buffer Days","default":1},"calendar_plan":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Calendar Plan"}},"type":"object","required":["standard_days"],"title":"LeadTimeEstimate","description":"Lead time estimate with options."},"LeadTimeOption":{"properties":{"days":{"type":"integer","title":"Days"},"multiplier":{"type":"number","title":"Multiplier"},"label":{"type":"string","title":"Label"}},"type":"object","required":["days","multiplier","label"],"title":"LeadTimeOption","description":"A single lead time option."},"LineItem":{"properties":{"description":{"type":"string","maxLength":500,"minLength":1,"title":"Description"},"quantity":{"type":"integer","minimum":0.0,"title":"Quantity"},"unit_price_cents":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Unit Price Cents"},"total_cents":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total Cents"},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"USD"},"needs_review":{"type":"boolean","title":"Needs Review","default":false},"extraction_confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Extraction Confidence"},"source_excerpt":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Source Excerpt"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"}},"type":"object","required":["description","quantity"],"title":"LineItem","description":"Typed line item shape (eng-review §2.1 locked).\n\nUsed by BOTH :class:`SupplierQuoteManualCreate` (manual path, this\nmodule) AND :class:`app.agents.vendors.schemas.mcp.RecordSupplierQuoteInput`\n(existing MCP path) so both write paths produce identical JSONB shapes.\n\nJSONB column stays flexible — Pydantic v2's ``extra='ignore'`` default\ntolerates legacy rows with extra keys. Migration to typed shape: both\npaths use this from V1 onward. Legacy MCP-written rows from before this\nPR (if any) are unaffected — read-side ignores extra keys.\n\nPer-row inbound agent extraction signals (PRO-72): ``needs_review``,\n``extraction_confidence``, and ``source_excerpt`` are populated by the\ninbound agent when it parses a supplier reply. Manual-entry callers\nleave them at the defaults (``False`` / ``None`` / ``None``); existing\nJSONB rows that pre-date these fields read back as defaults too. The\nV2 Quote Correction View (PRO-113) consumes these for per-row highlight\n+ verification UX."},"LinkCalloutRequest":{"properties":{"category":{"type":"string","title":"Category","description":"Drawing callout category: tolerances, gd_and_t, surface_finish, threads, bores, chamfers, radii"},"callout_index":{"type":"integer","minimum":0.0,"title":"Callout Index","description":"Zero-based index into drawing_analysis[category]"},"target_feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Feature Id","description":"The 3D feature_id to link this callout to. Required when action='link'. Ignored when action='unlink'."},"action":{"type":"string","title":"Action","description":"'link' or 'unlink'"}},"type":"object","required":["category","callout_index","action"],"title":"LinkCalloutRequest","description":"Manually link (or unlink) a drawing callout to a 3D feature.\n\nUsed by the \"unmatched callouts hopper\" UI — when the user drags a\ncallout that the LLM stitcher couldn't auto-match onto a 3D feature,\nthe frontend POSTs this to persist the manual link as both:\n  1. An OutcomeEvent with ``outcome_type=\"user_drawing_link\"`` for\n     audit + stitcher re-run respect\n  2. An in-place update to ``part.drawing_analysis[category][idx].feature_id``\n     for immediate UI reflection"},"LinkCalloutResponse":{"properties":{"drawing_analysis":{"additionalProperties":true,"type":"object","title":"Drawing Analysis","description":"Updated drawing_analysis after the link/unlink"}},"type":"object","required":["drawing_analysis"],"title":"LinkCalloutResponse","description":"Response after linking/unlinking a callout.\n\nReturns the updated drawing_analysis blob so the frontend can\nrefresh its local state without a separate fetch."},"LoadPathEntry":{"properties":{"path":{"type":"string","maxLength":500,"title":"Path"},"magnitude":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Magnitude"},"direction":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Direction"},"source_certainty":{"type":"string","enum":["user_asserted","user_hypothetical","agent_inferred"],"title":"Source Certainty"}},"type":"object","required":["path","source_certainty"],"title":"LoadPathEntry"},"LossReasonContext":{"properties":{"project_name":{"type":"string","title":"Project Name"},"quote_ref":{"type":"string","title":"Quote Ref"},"preselected_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preselected Reason"},"reasons":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Reasons"},"already_recorded":{"type":"boolean","title":"Already Recorded"},"recorded_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recorded Reason"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recorded At"}},"type":"object","required":["project_name","quote_ref","preselected_reason","reasons","already_recorded","recorded_reason","recorded_at"],"title":"LossReasonContext"},"LossReasonResult":{"properties":{"recorded":{"type":"boolean","title":"Recorded"},"already_recorded":{"type":"boolean","title":"Already Recorded"}},"type":"object","required":["recorded","already_recorded"],"title":"LossReasonResult"},"LossReasonSubmit":{"properties":{"token":{"type":"string","title":"Token"},"reason":{"$ref":"#/components/schemas/QuoteLostReason"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note"}},"type":"object","required":["token","reason"],"title":"LossReasonSubmit"},"ManualContactRequest":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"note":{"type":"string","maxLength":2000,"title":"Note"}},"type":"object","required":["user_id","note"],"title":"ManualContactRequest"},"ManufacturerSummary":{"properties":{"sourced":{"type":"boolean","title":"Sourced","default":false},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"their_price_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Their Price Cents"},"their_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Their Lead Time Days"},"mfg_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mfg Status"},"mfg_eta":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Mfg Eta"},"mfg_actual_shipped_at":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Mfg Actual Shipped At"},"mfg_tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mfg Tracking Number"},"buy_side_payment_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buy Side Payment State"},"we_paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"We Paid At"}},"type":"object","title":"ManufacturerSummary","description":"ADMIN-ONLY buy-side (manufacturer) summary on the projects overview.\n\nSurfaces who is making the parts + the buy-side schedule/AP state for the\nWINNING supplier. Two shapes (plan Decision 3 — never null-that-looks-empty):\n\n* **Sourced** (a supplier won + a SupplierOrder exists): ``sourced=True``,\n  ``name`` = the won supplier's :attr:`SupplierContact.name`, plus the\n  buy-side mfg status / ETA / tracking / payment state.\n* **In-house / unsourced** (no won SupplierOrder): ``sourced=False`` with\n  ``status=\"in_house\"`` and every other field ``None``. This is the\n  EXPLICIT empty state — the FE renders \"In-house\" rather than a blank.\n\nCRITICAL: this object lives ONLY on admin schemas. It must NEVER be added\nto the customer-facing ``ProjectResponse`` — the customer never sees who\nmanufactures their parts or what we pay the supplier."},"ManufacturingDrawingGenerateRequest":{"properties":{"sheet_format":{"type":"string","enum":["A3","A4","Letter"],"title":"Sheet Format","default":"A3"},"projection_standard":{"type":"string","enum":["third_angle","first_angle"],"title":"Projection Standard","default":"third_angle"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","title":"ManufacturingDrawingGenerateRequest","description":"Request body for POST /shop-drawing/generate."},"ManufacturingDrawingGenerateResponse":{"properties":{"drawing_id":{"type":"string","format":"uuid","title":"Drawing Id"},"workflow_id":{"type":"string","title":"Workflow Id"},"status":{"type":"string","title":"Status"}},"type":"object","required":["drawing_id","workflow_id","status"],"title":"ManufacturingDrawingGenerateResponse","description":"202 response from POST /shop-drawing/generate."},"ManufacturingDrawingResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"type":"string","format":"uuid","title":"Cad File Version Id"},"sheet_format":{"type":"string","title":"Sheet Format"},"projection_standard":{"type":"string","title":"Projection Standard"},"status":{"type":"string","title":"Status"},"annotations_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Annotations Hash"},"generation_started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generation Started At"},"generation_completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generation Completed At"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"computed_status":{"type":"string","title":"Computed Status"},"coverage_summary":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Coverage Summary"}},"type":"object","required":["id","part_id","cad_file_version_id","sheet_format","projection_standard","status","created_at","updated_at","computed_status"],"title":"ManufacturingDrawingResponse","description":"Response schema — adds service-layer computed fields.\n\n``computed_status`` folds the on-read staleness check into the DB\nstatus. ``coverage_summary`` reports annotation coverage tied to the\nartifact (counts by source, unmatched specs, etc.)."},"ManufacturingIntentConfirmRequest":{"properties":{"idempotency_key":{"type":"string","maxLength":255,"minLength":8,"title":"Idempotency Key"},"scope":{"type":"string","enum":["project","part","feature","drawing"],"title":"Scope"},"intent_type":{"type":"string","maxLength":64,"minLength":1,"title":"Intent Type"},"label":{"type":"string","maxLength":500,"minLength":1,"title":"Label"},"value":{"additionalProperties":true,"type":"object","title":"Value"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"feature_id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Feature Id"},"source":{"type":"string","enum":["user_confirmed","user_direct","ollie_confirmed","admin_confirmed"],"title":"Source","default":"ollie_confirmed"},"provenance":{"additionalProperties":true,"type":"object","title":"Provenance"}},"type":"object","required":["idempotency_key","scope","intent_type","label"],"title":"ManufacturingIntentConfirmRequest","description":"Confirm an Ollie/user proposal into the durable intent ledger."},"ManufacturingIntentListResponse":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"events":{"items":{"$ref":"#/components/schemas/ManufacturingIntentRead"},"type":"array","title":"Events"},"active_count":{"type":"integer","title":"Active Count"},"retracted_count":{"type":"integer","title":"Retracted Count"},"superseded_count":{"type":"integer","title":"Superseded Count"}},"type":"object","required":["project_id","events","active_count","retracted_count","superseded_count"],"title":"ManufacturingIntentListResponse"},"ManufacturingIntentRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"scope":{"type":"string","enum":["project","part","feature","drawing"],"title":"Scope"},"intent_type":{"type":"string","title":"Intent Type"},"label":{"type":"string","title":"Label"},"value":{"additionalProperties":true,"type":"object","title":"Value"},"state":{"type":"string","enum":["active","retracted","superseded"],"title":"State"},"source":{"type":"string","enum":["user_confirmed","user_direct","ollie_confirmed","admin_confirmed"],"title":"Source"},"source_certainty":{"type":"string","const":"user_asserted","title":"Source Certainty"},"provenance":{"additionalProperties":true,"type":"object","title":"Provenance"},"idempotency_key":{"type":"string","title":"Idempotency Key"},"supersedes_event_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Supersedes Event Id"},"retracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Retracted At"},"retracted_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Retracted By User Id"},"retraction_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Retraction Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","part_id","cad_file_version_id","feature_id","scope","intent_type","label","value","state","source","source_certainty","provenance","idempotency_key","supersedes_event_id","retracted_at","retracted_by_user_id","retraction_reason","created_at","updated_at"],"title":"ManufacturingIntentRead"},"ManufacturingIntentRetractRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason"}},"type":"object","title":"ManufacturingIntentRetractRequest"},"ManufacturingIntentSupersedeRequest":{"properties":{"idempotency_key":{"type":"string","maxLength":255,"minLength":8,"title":"Idempotency Key"},"scope":{"type":"string","enum":["project","part","feature","drawing"],"title":"Scope"},"intent_type":{"type":"string","maxLength":64,"minLength":1,"title":"Intent Type"},"label":{"type":"string","maxLength":500,"minLength":1,"title":"Label"},"value":{"additionalProperties":true,"type":"object","title":"Value"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"feature_id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Feature Id"},"source":{"type":"string","enum":["user_confirmed","user_direct","ollie_confirmed","admin_confirmed"],"title":"Source","default":"ollie_confirmed"},"provenance":{"additionalProperties":true,"type":"object","title":"Provenance"}},"type":"object","required":["idempotency_key","scope","intent_type","label"],"title":"ManufacturingIntentSupersedeRequest","description":"Replace an active event with a new value while retaining audit chain."},"ManufacturingPackageApproval":{"properties":{"approved":{"type":"boolean","title":"Approved"},"rejection_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rejection Reason"}},"type":"object","required":["approved"],"title":"ManufacturingPackageApproval","description":"Request body for approve/reject."},"ManufacturingPackageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"type":"string","format":"uuid","title":"Cad File Version Id"},"agent_action_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent Action Id"},"status":{"type":"string","title":"Status"},"version":{"type":"integer","title":"Version"},"operation_sequence":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Operation Sequence"},"setup_sheets":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Setup Sheets"},"critical_features":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Critical Features"},"inspection_criteria":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Inspection Criteria"},"supplier_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Notes"},"material_specification":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Material Specification"},"surface_finish_specification":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Surface Finish Specification"},"estimated_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Lead Time Days"},"estimated_cost_low":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Estimated Cost Low"},"estimated_cost_high":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Estimated Cost High"},"approved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approved By"},"approved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Approved At"},"rejection_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rejection Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","part_id","cad_file_version_id","status","version","created_at","updated_at"],"title":"ManufacturingPackageResponse","description":"Full detail response."},"MarkDeclinedInput":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason"}},"type":"object","title":"MarkDeclinedInput","description":"POST body for ``/admin/vendor-threads/{id}/decline``.\n\n``reason`` is optional — when provided, it's recorded in\n``ThreadState.last_intent``. Empty / omitted leaves ``last_intent``\nuntouched."},"MarkSupplierInvoicePaidInput":{"properties":{"we_paid_amount_cents":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":0.0},{"type":"null"}],"title":"We Paid Amount Cents"},"we_paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"We Paid At"},"supplier_invoice_number":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Supplier Invoice Number"}},"type":"object","title":"MarkSupplierInvoicePaidInput","description":"Body for the mark-supplier-invoice-paid action.\n\nAll fields optional — the endpoint stamps ``we_paid_at = now()`` when not\nsupplied. ``we_paid_amount_cents`` records what we actually paid (defaults\nto the won quote total when omitted is handled in the service)."},"MatingSurfaceEntry":{"properties":{"feature_id":{"type":"string","title":"Feature Id"},"mate_type":{"type":"string","maxLength":64,"title":"Mate Type"},"counterpart":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Counterpart"},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Notes"},"source_certainty":{"type":"string","enum":["user_asserted","user_hypothetical","agent_inferred"],"title":"Source Certainty"}},"type":"object","required":["feature_id","mate_type","source_certainty"],"title":"MatingSurfaceEntry"},"MessageFeedbackPatch":{"properties":{"feedback":{"anyOf":[{"type":"string","enum":["up","down"]},{"type":"null"}],"title":"Feedback"},"feedback_text":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Feedback Text"}},"type":"object","title":"MessageFeedbackPatch","description":"PATCH body for setting per-message thumbs up/down.\n\n``feedback=None`` clears an existing vote. ``feedback_text`` is reserved\nfor Phase 6; Phase 2 ships the binary vote only, but the field is\naccepted for forward compatibility."},"NotificationListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/NotificationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"NotificationListResponse"},"NotificationPreferenceResponse":{"properties":{"notification_type":{"$ref":"#/components/schemas/NotificationType"},"email_enabled":{"type":"boolean","title":"Email Enabled"},"in_app_enabled":{"type":"boolean","title":"In App Enabled"}},"type":"object","required":["notification_type","email_enabled","in_app_enabled"],"title":"NotificationPreferenceResponse"},"NotificationPreferenceUpdate":{"properties":{"notification_type":{"$ref":"#/components/schemas/NotificationType"},"email_enabled":{"type":"boolean","title":"Email Enabled"},"in_app_enabled":{"type":"boolean","title":"In App Enabled"}},"type":"object","required":["notification_type","email_enabled","in_app_enabled"],"title":"NotificationPreferenceUpdate"},"NotificationPreferencesUpdateRequest":{"properties":{"preferences":{"items":{"$ref":"#/components/schemas/NotificationPreferenceUpdate"},"type":"array","title":"Preferences"}},"type":"object","required":["preferences"],"title":"NotificationPreferencesUpdateRequest"},"NotificationResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"$ref":"#/components/schemas/NotificationType"},"title":{"type":"string","title":"Title"},"body":{"type":"string","title":"Body"},"is_read":{"type":"boolean","title":"Is Read"},"read_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Read At"},"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type"},"resource_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Resource Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","type","title","body","is_read","read_at","resource_type","resource_id","created_at"],"title":"NotificationResponse"},"NotificationType":{"type":"string","enum":["welcome","quote_ready","quote_rejected","payment_confirmed","shipment_update","delivery_confirmed","project_status_changed","project_submitted_by_admin","po_approved","po_revoked","po_uploaded_by_admin","quote_approved_by_admin","waitlist_confirmation","waitlist_invite_sent","new_comment","new_project_submitted","payment_received","order_confirmed","po_submitted","new_user_registered","new_waitlist_signup","new_project_comment","order_request_submitted","order_request_edited","agent_escalation","rfq_drafts_ready","supplier_reply_parsed","supplier_quote_received","agent_escalation_rfq","rfq_clarification_drafted","rfq_response_sla","quote_revision_overdue","quote_reactivation_requested"],"title":"NotificationType"},"OllieInsightCandidate":{"properties":{"id":{"type":"string","title":"Id"},"scope":{"type":"string","enum":["project","part","feature"],"title":"Scope"},"severity":{"type":"string","enum":["blocker","review","suggestion","info"],"title":"Severity"},"category":{"type":"string","enum":["quote_readiness","dfm","drawing","feature_uncertainty","pricing","lead_time","intent"],"title":"Category"},"title":{"type":"string","title":"Title"},"prompt":{"type":"string","title":"Prompt"},"rationale":{"type":"string","title":"Rationale"},"confidence":{"type":"string","enum":["high","medium","low"],"title":"Confidence"},"requires_confirmation":{"type":"boolean","title":"Requires Confirmation"},"part_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part Id"},"part_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part Name"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"downstream_impacts":{"items":{"type":"string"},"type":"array","title":"Downstream Impacts"},"evidence":{"items":{"$ref":"#/components/schemas/OllieInsightEvidence"},"type":"array","title":"Evidence"}},"type":"object","required":["id","scope","severity","category","title","prompt","rationale","confidence","requires_confirmation","downstream_impacts","evidence"],"title":"OllieInsightCandidate","description":"Deterministic, evidence-backed prompt Ollie may surface to users."},"OllieInsightEvidence":{"properties":{"source":{"type":"string","title":"Source"},"kind":{"type":"string","title":"Kind"}},"additionalProperties":true,"type":"object","required":["source","kind"],"title":"OllieInsightEvidence","description":"Compact source reference supporting one Ollie insight candidate."},"OllieInsightsResponse":{"properties":{"scope":{"type":"string","enum":["project","part","feature"],"title":"Scope"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"count":{"type":"integer","title":"Count"},"candidates":{"items":{"$ref":"#/components/schemas/OllieInsightCandidate"},"type":"array","title":"Candidates"}},"type":"object","required":["scope","project_id","count","candidates"],"title":"OllieInsightsResponse","description":"Read model for scoped Ollie insight candidates."},"OllieTranscriptResponse":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"project_name":{"type":"string","title":"Project Name"},"messages":{"items":{"$ref":"#/components/schemas/TranscriptMessageRead"},"type":"array","title":"Messages"},"part_intents":{"items":{"$ref":"#/components/schemas/TranscriptPartIntentRead"},"type":"array","title":"Part Intents"},"notes":{"items":{"$ref":"#/components/schemas/TranscriptNoteRead"},"type":"array","title":"Notes"}},"type":"object","required":["project_id","project_name","messages","part_intents","notes"],"title":"OllieTranscriptResponse"},"OllieTurnClientContext":{"properties":{"selected_candidate_id":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Selected Candidate Id"},"selected_candidate_scope":{"anyOf":[{"type":"string","enum":["project","part","feature"]},{"type":"null"}],"title":"Selected Candidate Scope"},"selected_candidate_category":{"anyOf":[{"type":"string","enum":["quote_readiness","dfm","drawing","feature_uncertainty","pricing","lead_time","intent"]},{"type":"null"}],"title":"Selected Candidate Category"},"active_part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Active Part Id"},"active_feature_id":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Active Feature Id"},"surface":{"type":"string","enum":["project_overview","part_viewer","admin","unknown"],"title":"Surface","default":"unknown"}},"type":"object","title":"OllieTurnClientContext","description":"Trace-safe client context for one Ollie turn.\n\nThis is observability and grounding metadata, not prompt content. Keep it\nto ids, scope/category labels, and surface names so Ollie turns can be\nevaluated without storing raw CAD geometry or drawing text."},"OllieTurnRequest":{"properties":{"message":{"type":"string","maxLength":10000,"minLength":0,"title":"Message"},"active_part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Active Part Id"},"active_feature_id":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Active Feature Id"},"client_context":{"anyOf":[{"$ref":"#/components/schemas/OllieTurnClientContext"},{"type":"null"}]}},"type":"object","required":["message"],"title":"OllieTurnRequest","description":"POST body for starting one Ollie turn.\n\nEmpty ``message`` (\"\") is allowed — the agent handles it as an empty turn\nper the golden-set fixture (gq-016). A hard 10k-char cap protects the\nAnthropic call and the DB column."},"OutboundShipmentCreate":{"properties":{"carrier":{"$ref":"#/components/schemas/CarrierCode","default":"ups"},"carrier_service_code":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Carrier Service Code"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes"},"origin_override":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]}},"type":"object","title":"OutboundShipmentCreate"},"OutboundShipmentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier"},"carrier_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Code"},"carrier_service_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Service Code"},"carrier_shipment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Shipment Id"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"status":{"$ref":"#/components/schemas/ShipmentStatus"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label_status":{"$ref":"#/components/schemas/LabelStatus"},"tracking_sync_status":{"$ref":"#/components/schemas/CarrierSyncStatus"},"tracking_last_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Tracking Last Synced At"},"tracking_sync_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Sync Error"},"origin_snapshot":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]},"destination_snapshot":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]},"events":{"items":{"$ref":"#/components/schemas/ShipmentEventResponse"},"type":"array","title":"Events"},"packages":{"items":{"$ref":"#/components/schemas/ShipmentPackageResponse"},"type":"array","title":"Packages"},"pickups":{"items":{"$ref":"#/components/schemas/ShipmentPickupResponse"},"type":"array","title":"Pickups"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","status","label_status","tracking_sync_status","created_at","updated_at"],"title":"OutboundShipmentResponse"},"OutboundShipmentUpdate":{"properties":{"carrier":{"anyOf":[{"$ref":"#/components/schemas/CarrierCode"},{"type":"null"}]},"carrier_service_code":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Carrier Service Code"},"tracking_number":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"},"status":{"anyOf":[{"$ref":"#/components/schemas/ShipmentStatus"},{"type":"null"}]},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes"},"origin_override":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]},"destination_override":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]}},"type":"object","title":"OutboundShipmentUpdate"},"POAddressValidation":{"properties":{"status":{"$ref":"#/components/schemas/POValidationStatus"},"field":{"type":"string","title":"Field"},"extracted_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extracted Text"},"current_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Text"},"suggested_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Override"},"message":{"type":"string","title":"Message"}},"type":"object","required":["status","field","message"],"title":"POAddressValidation","description":"Comparison between extracted PO address text and current order address."},"POAmountValidation":{"properties":{"status":{"$ref":"#/components/schemas/POValidationStatus"},"extracted_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extracted Total Cents"},"expected_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Total Cents"},"expected_pre_tax_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Pre Tax Cents"},"delta_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delta Cents"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"message":{"type":"string","title":"Message"}},"type":"object","required":["status","message"],"title":"POAmountValidation","description":"Comparison between the extracted PO total and the sell-side order total."},"POExtractionValidationSummary":{"properties":{"extraction_id":{"type":"string","format":"uuid","title":"Extraction Id"},"amount":{"$ref":"#/components/schemas/POAmountValidation"},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/POAddressValidation"},{"type":"null"}]},"billing_address":{"anyOf":[{"$ref":"#/components/schemas/POAddressValidation"},{"type":"null"}]},"extracted_po_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extracted Po Number"},"extracted_order_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Extracted Order Date"},"extracted_payment_terms_net_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extracted Payment Terms Net Days"},"extracted_requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extracted Requester Name"},"extracted_requester_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extracted Requester Email"}},"type":"object","required":["extraction_id","amount"],"title":"POExtractionValidationSummary","description":"Admin-only PO extraction validation summary."},"POUploadResponse":{"properties":{"r2_key":{"type":"string","title":"R2 Key"},"document_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Document Id"},"extraction_status":{"type":"string","title":"Extraction Status","default":"uploaded"},"latest_extraction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Extraction Id"}},"type":"object","required":["r2_key"],"title":"POUploadResponse","description":"Response from the PO-document upload proxy endpoint.\n\nCarries the R2 key the streamed file was written to. The client\npasses it back as ``po_document_r2_key`` on the subsequent\n``POST /payments/purchase-order`` call."},"POValidationStatus":{"type":"string","enum":["match","mismatch","matches_pre_tax_only","unknown"],"title":"POValidationStatus","description":"Canonical PO extraction validation statuses for admin review."},"PackingSlipCreate":{"properties":{"total_weight":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Weight"},"total_weight_unit":{"anyOf":[{"type":"string","enum":["kg","lbs"]},{"type":"null"}],"title":"Total Weight Unit"},"package_count":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Package Count"},"ship_date_override":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Ship Date Override"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"PackingSlipCreate","description":"Body for ``POST /admin/projects/{id}/packing-slip``.\n\nAll fields are optional. The endpoint is idempotent — calling it a\nsecond time updates the override values on the existing row and\nre-renders the PDF (preserving ``packing_slip_number``).\n\nCarrier + tracking are intentionally NOT included here — they live\non the ``Shipment`` row and are surfaced via the existing \"Create /\nEdit Shipment\" admin flow. The packing slip PDF reads them at render\ntime when a Shipment exists."},"PackingSlipGenerateResponse":{"properties":{"packing_slip_id":{"type":"string","format":"uuid","title":"Packing Slip Id"},"packing_slip_number":{"type":"string","title":"Packing Slip Number"},"status":{"type":"string","title":"Status"}},"type":"object","required":["packing_slip_id","packing_slip_number","status"],"title":"PackingSlipGenerateResponse","description":"202 Accepted response from ``POST .../packing-slip``.\n\nThe actual PDF render runs asynchronously in the Temporal worker.\nFrontend re-fetches the parent detail query to surface the new\n``packing_slip_pdf_url``."},"PackingSlipResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"shipment_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipment Id"},"packing_slip_number":{"type":"string","title":"Packing Slip Number"},"status":{"type":"string","title":"Status"},"packing_slip_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Packing Slip Pdf Url"},"total_weight":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Weight"},"total_weight_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Total Weight Unit"},"package_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Package Count"},"package_snapshot":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Package Snapshot"},"ship_date_override":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Ship Date Override"},"generated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generated At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","packing_slip_number","status","created_at","updated_at"],"title":"PackingSlipResponse","description":"Packing slip summary returned in admin payment detail + standalone fetches.\n\n``packing_slip_pdf_url`` is populated by the router via the storage\nchokepoint (5-minute presigned token, ``disposition=attachment``)\nwhen ``packing_slip_pdf_r2_key`` is present. Frontend uses it\ndirectly with ``window.open``."},"PaginatedResponse_AdminBusinessProfileListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminBusinessProfileListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminBusinessProfileListItem]"},"PaginatedResponse_AdminCadFileListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminCadFileListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminCadFileListItem]"},"PaginatedResponse_AdminPaymentListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminPaymentListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminPaymentListItem]"},"PaginatedResponse_AdminProjectListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminProjectListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminProjectListItem]"},"PaginatedResponse_AdminShipmentListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminShipmentListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminShipmentListItem]"},"PaginatedResponse_AdminUserListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminUserListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[AdminUserListItem]"},"PaginatedResponse_ExternalCustomerListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ExternalCustomerListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[ExternalCustomerListItem]"},"PaginatedResponse_FollowupTaskListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FollowupTaskListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[FollowupTaskListItem]"},"PaginatedResponse_ProjectResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProjectResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[ProjectResponse]"},"PaginatedResponse_SupplierContactListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SupplierContactListItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[SupplierContactListItem]"},"PaginatedResponse_WaitlistEntryResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WaitlistEntryResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"offset":{"type":"integer","title":"Offset"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["items","total","offset","limit","has_more"],"title":"PaginatedResponse[WaitlistEntryResponse]"},"PartAnnotationBundle":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"version_id":{"type":"string","format":"uuid","title":"Version Id"},"version_number":{"type":"integer","title":"Version Number"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"annotated_features":{"items":{"$ref":"#/components/schemas/FeatureAnnotationSummary"},"type":"array","title":"Annotated Features"},"unannotated_feature_count":{"type":"integer","title":"Unannotated Feature Count"},"part_level_notes":{"items":{"$ref":"#/components/schemas/FeatureNote"},"type":"array","title":"Part Level Notes"},"design_intent":{"anyOf":[{"$ref":"#/components/schemas/DesignIntentSummary"},{"type":"null"}]},"welds":{"items":{"$ref":"#/components/schemas/WeldSummary"},"type":"array","title":"Welds"},"total_welds":{"type":"integer","title":"Total Welds","default":0},"surface_finishes":{"items":{"$ref":"#/components/schemas/SurfaceFinishSummary"},"type":"array","title":"Surface Finishes"},"total_surface_finishes":{"type":"integer","title":"Total Surface Finishes","default":0},"edge_tolerances":{"items":{"$ref":"#/components/schemas/EdgeToleranceSummary"},"type":"array","title":"Edge Tolerances"},"total_edge_tolerances":{"type":"integer","title":"Total Edge Tolerances","default":0},"total_notes":{"type":"integer","title":"Total Notes"},"total_tolerances":{"type":"integer","title":"Total Tolerances"},"total_reclassifications":{"type":"integer","title":"Total Reclassifications"},"total_callouts":{"type":"integer","title":"Total Callouts"}},"type":"object","required":["part_id","version_id","version_number","annotated_features","unannotated_feature_count","part_level_notes","total_notes","total_tolerances","total_reclassifications","total_callouts"],"title":"PartAnnotationBundle"},"PartBulkUpdate":{"properties":{"part_ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Part Ids"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"}},"type":"object","required":["part_ids"],"title":"PartBulkUpdate","description":"Request body for bulk-updating specs on multiple parts at once."},"PartCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","minimum":1.0,"title":"Required Quantity","default":1},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Finishing Name"},"custom_coating_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Custom Coating Name"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Coating Spec"}},"type":"object","required":["name"],"title":"PartCreate","description":"Request body for creating a new part within a project.\n\nThe ``project_id`` is typically provided via the URL path rather than\nthe request body, so it is not included here.  The router is\nresponsible for binding the part to the correct project."},"PartDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","title":"Required Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Finishing Name"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"versions":{"items":{"$ref":"#/components/schemas/app__schemas__part__CadVersionSummary"},"type":"array","title":"Versions","default":[]},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Spec"},"custom_coating_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Coating Name"},"coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Value"},"coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Label"},"finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Value"},"finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Label"},"material_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Value"},"material_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Label"},"machining_process_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Value"},"machining_process_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Label"},"effective_coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Value"},"effective_coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Color"},"effective_coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Label"},"effective_finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Value"},"effective_finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Label"},"general_tolerance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"General Tolerance"},"edge_break_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Edge Break Default"},"drawing_file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing File Name"},"drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing R2 Key"},"drawing_file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Drawing File Size"},"drawing_analysis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drawing Analysis"},"spec_proposal":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Spec Proposal"},"redacted_drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redacted Drawing R2 Key"},"finish":{"anyOf":[{"$ref":"#/components/schemas/FinishResponse"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","required_quantity","project_id","created_at","updated_at"],"title":"PartDetailResponse","description":"Part with its CAD file versions -- used in detail endpoints.\n\n``versions`` is eagerly loaded and ordered by ``version_number``\nascending, matching the SQLAlchemy relationship definition on the\n``Part`` model."},"PartReconciliationResponse":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"conflicts":{"items":{"$ref":"#/components/schemas/DrawingModelConflictResponse"},"type":"array","title":"Conflicts"},"summary":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Summary"}},"type":"object","required":["part_id","conflicts"],"title":"PartReconciliationResponse"},"PartRedactionReportResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Redaction lifecycle: pending | processing | redacted | failed"},"report":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Report","description":"Summary from the redaction run: verification status, zone count, per-reason zone counts, failed zones, error."},"has_redacted_pdf":{"type":"boolean","title":"Has Redacted Pdf","description":"Whether a supplier-safe redacted PDF exists in R2"}},"type":"object","required":["status","has_redacted_pdf"],"title":"PartRedactionReportResponse","description":"Part-level redaction status + 'what was redacted' summary.\n\nInformational (non-blocking): lets an admin sanity-check the best-effort\nsupplier-safe PDF before sending the draft RFQ. Mirrors the fields already\nexposed on project documents."},"PartReviewSummary":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"part_name":{"type":"string","title":"Part Name"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"reviewable_count":{"type":"integer","title":"Reviewable Count"},"total_features":{"type":"integer","title":"Total Features"},"top_severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Top Severity"},"is_completed":{"type":"boolean","title":"Is Completed"},"is_processed":{"type":"boolean","title":"Is Processed"}},"type":"object","required":["part_id","part_name","cad_file_version_id","reviewable_count","total_features","top_severity","is_completed","is_processed"],"title":"PartReviewSummary","description":"Per-part row in the project review summary.\n\nDrives the Ollie sidebar CTA — one row per part with all the signals\nthe UI needs to rank, label, and style the entry:\n\n* ``reviewable_count`` — DFM findings + pending Ollie questions to act on\n* ``total_features`` — total detected features (drives \"N features\"\n  label for parts with no issues flagged)\n* ``top_severity`` — highest-priority label for the accent dot\n* ``is_completed`` — true when the user has acked/answered everything;\n  row renders greyed but still clickable for revisits\n* ``is_processed`` — true when CAD pipeline finished so the analyze\n  page is reachable. Pre-processing parts stay greyed + non-clickable."},"PartSimilarityResult":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"part_name":{"type":"string","title":"Part Name"},"anchors":{"items":{"$ref":"#/components/schemas/SimilarPartAnchor"},"type":"array","title":"Anchors"},"median_admin_unit_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Median Admin Unit Price"},"n_anchors":{"type":"integer","title":"N Anchors"}},"type":"object","required":["part_id","part_name","anchors","median_admin_unit_price","n_anchors"],"title":"PartSimilarityResult","description":"Top-k anchors for a single part in the quote under review."},"PartSummaryInProject":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","title":"Required Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Finishing Name"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Spec"},"custom_coating_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Coating Name"},"general_tolerance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"General Tolerance"},"edge_break_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Edge Break Default"},"coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Value"},"coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Label"},"finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Value"},"finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Label"},"material_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Value"},"material_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Label"},"machining_process_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Value"},"machining_process_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Label"},"effective_coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Value"},"effective_coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Color"},"effective_coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Label"},"effective_finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Value"},"effective_finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Label"},"drawing_file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing File Name"},"drawing_file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Drawing File Size"},"drawing_analysis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drawing Analysis"},"spec_proposal":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Spec Proposal"},"versions":{"items":{"$ref":"#/components/schemas/PartVersionStatus"},"type":"array","title":"Versions","default":[]},"latest_dfm_results":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Latest Dfm Results"},"finish":{"anyOf":[{"$ref":"#/components/schemas/FinishResponse"},{"type":"null"}]}},"type":"object","required":["id","name","required_quantity"],"title":"PartSummaryInProject","description":"Minimal part representation nested inside a project detail response.\n\nIncludes the manufacturing specification FK references so the frontend\ncan resolve dropdown labels in a single round-trip.  ``versions`` carries\nlightweight status info so tabs can show processing/ready/failed dots\nwithout extra API calls.\n\nCoating + tolerance fields are included so the parts row table can\nrender the same surface-finish/coating split as the analyze sidebar,\nwithout a per-row round-trip. The router populates the server-resolved\n``*_value`` / ``*_label`` / ``effective_*`` fields after model_validate\nvia :meth:`PartService.resolve_part_dropdown_labels`."},"PartSummaryResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"type":"integer","title":"Required Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Finishing Name"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Spec"},"custom_coating_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Coating Name"},"coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Value"},"coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coating Label"},"finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Value"},"finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finishing Label"},"material_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Value"},"material_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Label"},"machining_process_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Value"},"machining_process_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machining Process Label"},"effective_coating_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Value"},"effective_coating_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Color"},"effective_coating_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Coating Label"},"effective_finishing_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Value"},"effective_finishing_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Finishing Label"},"general_tolerance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"General Tolerance"},"edge_break_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Edge Break Default"},"drawing_file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing File Name"},"drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Drawing R2 Key"},"drawing_file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Drawing File Size"},"drawing_analysis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drawing Analysis"},"spec_proposal":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Spec Proposal"},"redacted_drawing_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redacted Drawing R2 Key"},"finish":{"anyOf":[{"$ref":"#/components/schemas/FinishResponse"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","required_quantity","project_id","created_at","updated_at"],"title":"PartSummaryResponse","description":"Part without version detail -- used in list endpoints."},"PartUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"required_quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Required Quantity"},"machining_process_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Machining Process Id"},"material_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"},"custom_material_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Material Name"},"custom_finishing_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Custom Finishing Name"},"coating_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Coating Id"},"coating_color":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Coating Color"},"coating_spec":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Coating Spec"},"custom_coating_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Custom Coating Name"},"general_tolerance":{"anyOf":[{"type":"string","enum":["ISO_2768_c","ISO_2768_m","ISO_2768_f","ISO_2768_v"]},{"type":"null"}],"title":"General Tolerance"},"edge_break_default":{"anyOf":[{"type":"string","enum":["break_0.1mm","break_0.25mm","break_0.5mm","break_1.0mm"]},{"type":"null"}],"title":"Edge Break Default"}},"type":"object","title":"PartUpdate","description":"Request body for partially updating an existing part.\n\nAll fields are optional; only the fields that are provided will be\napplied.  To clear a nullable field, send an explicit ``null``."},"PartVersionStatus":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"is_latest":{"type":"boolean","title":"Is Latest"},"status":{"type":"string","title":"Status"},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step"},"latest_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Run Id"},"analysis_milestone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Milestone"},"analysis_authority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Authority"},"analysis_seq":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Seq"},"preliminary_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceResponse"},{"type":"null"}]},"file_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Format"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"unit_price_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price Mid"},"has_ai_synthesis":{"type":"boolean","title":"Has Ai Synthesis","default":false},"has_dfm_results":{"type":"boolean","title":"Has Dfm Results","default":false},"analysis_status":{"$ref":"#/components/schemas/AnalysisStatus","default":"not_started"},"analysis_error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Error Message"},"analysis_failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Failed Step"},"analysis_last_transition_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Analysis Last Transition At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","is_latest","status","updated_at"],"title":"PartVersionStatus","description":"Version status for overview table and tab indicators.\n\nDeliberately scalar-only: this rides the polled project-detail\nresponse (every 5-15s while parts process), so the multi-MB\n``ai_dfm_synthesis`` / ``process_dfm_results`` dicts are replaced by\npresence booleans. The latest version's full DFM results live at the\npart level (``PartSummaryInProject.latest_dfm_results``); full\nsynthesis stays on the version-detail endpoint."},"PaymentIntentCreate":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"tax_calculation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Calculation Id"},"tax_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tax Amount"},"total_with_tax":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total With Tax"}},"type":"object","required":["project_id"],"title":"PaymentIntentCreate","description":"Request body for creating a Stripe PaymentIntent.\n\nIf ``tax_calculation_id`` is provided (from a prior ``calculate-tax``\ncall), the PaymentIntent amount will include tax."},"PaymentIntentResponse":{"properties":{"payment_id":{"type":"string","format":"uuid","title":"Payment Id"},"client_secret":{"type":"string","title":"Client Secret"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"deposit_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Deposit Amount"},"currency":{"type":"string","title":"Currency"},"status":{"type":"string","title":"Status"}},"type":"object","required":["payment_id","client_secret","amount","currency","status"],"title":"PaymentIntentResponse","description":"Response from create-intent — contains the client_secret for Stripe Elements."},"PaymentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"method":{"type":"string","title":"Method"},"status":{"type":"string","title":"Status"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"deposit_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Deposit Amount"},"currency":{"type":"string","title":"Currency"},"po_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Po Number"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address"},"tax_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tax Amount"},"total_with_tax":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total With Tax"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"submitted_by_admin_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Submitted By Admin Id"},"submitted_by_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitted By Label"},"po_document_extraction":{"anyOf":[{"$ref":"#/components/schemas/CommercialDocumentExtractionSummary"},{"type":"null"}]}},"type":"object","required":["id","project_id","quote_id","method","status","amount","currency","created_at","updated_at"],"title":"PaymentResponse","description":"Payment summary returned in list/detail views."},"PdfDownloadResponse":{"properties":{"url":{"type":"string","title":"Url"},"filename":{"type":"string","title":"Filename"}},"type":"object","required":["url","filename"],"title":"PdfDownloadResponse","description":"Presigned URL response for PDF download."},"PerformanceRequirementEntry":{"properties":{"metric":{"type":"string","maxLength":128,"title":"Metric"},"target":{"type":"string","maxLength":128,"title":"Target"},"source_certainty":{"type":"string","enum":["user_asserted","user_hypothetical","agent_inferred"],"title":"Source Certainty"}},"type":"object","required":["metric","target","source_certainty"],"title":"PerformanceRequirementEntry"},"PermissionGroupResponse":{"properties":{"resource":{"type":"string","title":"Resource"},"permissions":{"items":{"$ref":"#/components/schemas/PermissionResponse"},"type":"array","title":"Permissions","default":[]}},"type":"object","required":["resource"],"title":"PermissionGroupResponse","description":"Permissions grouped by resource."},"PermissionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"resource":{"type":"string","title":"Resource"},"action":{"type":"string","title":"Action"}},"type":"object","required":["id","resource","action"],"title":"PermissionResponse","description":"A single permission."},"PickupStatus":{"type":"string","enum":["not_scheduled","scheduled","cancelled","failed"],"title":"PickupStatus"},"PlaceOrderRequestBody":{"properties":{"quantity_by_part":{"additionalProperties":{"type":"integer"},"propertyNames":{"format":"uuid"},"type":"object","title":"Quantity By Part","description":"Optional per-part quantity overrides. Missing parts fall back to ``Part.required_quantity``."},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id","description":"Shipping address for the order. Falls back to the project's current shipping_address_id if omitted."},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date","description":"Customer's desired delivery date."},"po_number":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Po Number","description":"Optional PO number, pre-filled from BusinessProfile if blank."},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes","description":"Additional notes for the admin reviewer."}},"type":"object","title":"PlaceOrderRequestBody","description":"User accepts an instant auto-estimate via 'Place Order Request'.\n\nThe backend computes per-part cost + lead time using the deterministic\nDFM services, freezes the calculation as a snapshot on the new Quote,\nand creates it in ``submitted`` status with ``intent=auto_estimate``."},"PreferencesContext":{"properties":{"suppressed_all":{"type":"boolean","title":"Suppressed All"},"suppressed_categories":{"items":{"type":"string"},"type":"array","title":"Suppressed Categories"}},"type":"object","required":["suppressed_all","suppressed_categories"],"title":"PreferencesContext"},"PreliminaryPriceRange":{"properties":{"low":{"type":"number","minimum":0.0,"title":"Low"},"high":{"type":"number","minimum":0.0,"title":"High"}},"additionalProperties":false,"type":"object","required":["low","high"],"title":"PreliminaryPriceRange","description":"Inclusive USD price interval calibrated for holdout coverage."},"PreliminaryPriceResponse":{"properties":{"status":{"type":"string","enum":["ready","abstained"],"title":"Status"},"authority":{"type":"string","const":"preliminary","title":"Authority","default":"preliminary"},"non_payable":{"type":"boolean","const":true,"title":"Non Payable","default":true},"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"unit_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceRange"},{"type":"null"}]},"total_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceRange"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Quantity"},"cohort":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Cohort"},"assumptions":{"items":{"type":"string"},"type":"array","title":"Assumptions"},"missing_inputs":{"items":{"type":"string"},"type":"array","title":"Missing Inputs"},"abstention_reason":{"anyOf":[{"type":"string","enum":["missing_specs","unsupported_process_material","multi_body_or_assembly","context_unavailable","identity_unavailable","stock_out_of_envelope","implausible_fill","machine_or_setup_ambiguous","pending_drawing","custom_spec","low_primitive_confidence","calibration_unavailable","cohort_disabled","inputs_changing"]},{"type":"null"}],"title":"Abstention Reason"},"model_version":{"type":"string","minLength":1,"title":"Model Version"},"pricing_config_generation":{"type":"string","minLength":1,"title":"Pricing Config Generation"},"calibration_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Version"},"calibration_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Hash"},"pricing_input_hash":{"type":"string","maxLength":64,"minLength":64,"pattern":"^[0-9a-f]{64}$","title":"Pricing Input Hash"},"generated_at":{"type":"string","format":"date-time","title":"Generated At"}},"type":"object","required":["status","model_version","pricing_config_generation","pricing_input_hash","generated_at"],"title":"PreliminaryPriceResponse","description":"Compact public projection of a run-only Lane A pricing result.\n\nUnknown fields are deliberately ignored so internal raw-midpoint and\ncomponent-audit telemetry can never leak through REST or SSE serialization."},"PricingCalibrationResponse":{"properties":{"process":{"type":"string","title":"Process"},"complexity_bucket":{"type":"string","title":"Complexity Bucket"},"qty_bucket":{"type":"string","title":"Qty Bucket"},"median_uplift":{"type":"number","title":"Median Uplift"},"q1_uplift":{"type":"number","title":"Q1 Uplift"},"q3_uplift":{"type":"number","title":"Q3 Uplift"},"sample_size":{"type":"integer","title":"Sample Size"},"confidence":{"type":"string","title":"Confidence"},"flagged_for_review_count":{"type":"integer","title":"Flagged For Review Count"},"track_a_pricing_config_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Track A Pricing Config Version"},"last_recomputed_at":{"type":"string","format":"date-time","title":"Last Recomputed At"}},"type":"object","required":["process","complexity_bucket","qty_bucket","median_uplift","q1_uplift","q3_uplift","sample_size","confidence","flagged_for_review_count","track_a_pricing_config_version","last_recomputed_at"],"title":"PricingCalibrationResponse","description":"One bucket's calibration stats for the admin Pricing Settings UI.\n\nUsed by GET /admin/pricing-calibration (Phase 3 endpoint).\n`flagged_for_review_count` is the array length; admin opens a detail\nview to see the full list of flagged outliers."},"PricingConfigHistoryItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version":{"type":"integer","title":"Version"},"label":{"type":"string","title":"Label"},"is_active":{"type":"boolean","title":"Is Active"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","version","label","is_active","created_at"],"title":"PricingConfigHistoryItem","description":"Lightweight version info for the pricing config history list."},"PricingConfigResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version":{"type":"integer","title":"Version"},"label":{"type":"string","title":"Label"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"is_active":{"type":"boolean","title":"Is Active"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","version","label","config","is_active","created_at","updated_at"],"title":"PricingConfigResponse","description":"Full pricing config response including the JSON config document."},"PricingConfigUpdate":{"properties":{"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["config"],"title":"PricingConfigUpdate","description":"Update body for creating a new pricing config version.\n\nThe ``config`` field must contain the full config document -- it is\nnot merged with the previous version. Server-side validation is\nperformed by ``PricingConfigService``."},"PricingFeedbackCreate":{"properties":{"quote_line_item_id":{"type":"string","format":"uuid","title":"Quote Line Item Id"},"track_a_unit_price":{"type":"number","title":"Track A Unit Price"},"track_b_predicted_unit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Track B Predicted Unit"},"actual_unit_price":{"type":"number","title":"Actual Unit Price"},"reason_category":{"type":"string","enum":["nre_fixture","batch_amortization","market_position","urgency_premium","customer_specific","complexity_judgment","material_supply","other"],"title":"Reason Category"},"reason_text":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason Text"}},"type":"object","required":["quote_line_item_id","track_a_unit_price","actual_unit_price","reason_category"],"title":"PricingFeedbackCreate","description":"POST /admin/quotes/{quote_id}/line-items/{item_id}/pricing-feedback.\n\nPhase 1 only ships the schema; Phase 3 wires it into a router."},"ProcessingStatusResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"latest_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Run Id"},"analysis_milestone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Milestone"},"analysis_authority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Authority"},"analysis_seq":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Seq"},"preliminary_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceResponse"},{"type":"null"}]}},"type":"object","required":["id","status"],"title":"ProcessingStatusResponse","description":"Lightweight processing status for polling during CAD file processing.\n\nReturns only the essential fields needed to track pipeline progress,\nkeeping the payload small for frequent polling."},"ProjectActivityEventResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"actor_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor User Id"},"source":{"type":"string","title":"Source"},"event_type":{"type":"string","title":"Event Type"},"entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"},"entity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Entity Id"},"entity_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Label"},"summary":{"type":"string","title":"Summary"},"details":{"additionalProperties":true,"type":"object","title":"Details"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","source","event_type","summary","created_at","updated_at"],"title":"ProjectActivityEventResponse","description":"A deterministic project change marker shown in Ollie surfaces."},"ProjectCommentCreate":{"properties":{"message":{"type":"string","maxLength":5000,"minLength":1,"title":"Message"},"is_internal":{"type":"boolean","title":"Is Internal","description":"Admin-only internal note","default":false}},"type":"object","required":["message"],"title":"ProjectCommentCreate","description":"Create a new comment on a project."},"ProjectCommentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"author_id":{"type":"string","title":"Author Id"},"author_type":{"type":"string","title":"Author Type"},"author_name":{"type":"string","title":"Author Name"},"message":{"type":"string","title":"Message"},"is_internal":{"type":"boolean","title":"Is Internal"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","author_id","author_type","author_name","message","is_internal","created_at","updated_at"],"title":"ProjectCommentResponse","description":"A single comment on a project."},"ProjectCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"priority":{"type":"string","title":"Priority","description":"low, medium, or high","default":"medium"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date","description":"Target delivery date (optional)"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["name"],"title":"ProjectCreate","description":"Create a new project.\n\n``name`` is required.  ``description`` is optional (nullable).\n``priority`` defaults to ``\"medium\"`` and ``target_delivery_date``\nis optional. ``status`` is always set server-side to ``\"draft\"``\non creation."},"ProjectDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"status":{"type":"string","title":"Status"},"priority":{"type":"string","title":"Priority"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"parts":{"items":{"$ref":"#/components/schemas/PartSummaryInProject"},"type":"array","title":"Parts","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"submitted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted At"},"order_placed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At"},"expected_delivery_date_min":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Min"},"expected_delivery_date_max":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Max"}},"type":"object","required":["id","name","status","priority","user_id","created_at","updated_at"],"title":"ProjectDetailResponse","description":"Full project representation with nested parts.\n\nUsed by GET /projects/{id} to return the project along with its\nassociated parts in a single response."},"ProjectDocumentRedactionStatus":{"type":"string","enum":["pending","processing","redacted","failed"],"title":"ProjectDocumentRedactionStatus","description":"Supplier-safe redaction lifecycle for project-level PDFs."},"ProjectDocumentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"file_name":{"type":"string","title":"File Name"},"file_size":{"type":"integer","title":"File Size"},"content_type":{"type":"string","title":"Content Type"},"status":{"$ref":"#/components/schemas/ProjectDocumentStatus"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"uploaded_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Uploaded By User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Download Url"}},"type":"object","required":["id","project_id","file_name","file_size","content_type","status","created_at","updated_at"],"title":"ProjectDocumentResponse","description":"User-facing project PDF metadata.\n\nRedaction fields are intentionally omitted. Users only need to know\nwhether their original PDF is uploaded and available."},"ProjectDocumentStatus":{"type":"string","enum":["uploading","uploaded","validated","failed"],"title":"ProjectDocumentStatus","description":"Lifecycle for project-level supporting PDF documents."},"ProjectIntentAnswerRequest":{"properties":{"value":{"type":"string","title":"Value"},"label":{"type":"string","title":"Label"}},"type":"object","required":["value","label"],"title":"ProjectIntentAnswerRequest","description":"Answer for the single pushed project-level question."},"ProjectIntentStatus":{"properties":{"answered":{"type":"boolean","title":"Answered"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"}},"type":"object","required":["answered"],"title":"ProjectIntentStatus"},"ProjectIntentSummary":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"pending_count":{"type":"integer","title":"Pending Count"},"in_progress_count":{"type":"integer","title":"In Progress Count"},"completed_count":{"type":"integer","title":"Completed Count"},"skipped_count":{"type":"integer","title":"Skipped Count"},"total_parts":{"type":"integer","title":"Total Parts"},"pending_part_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Pending Part Ids","default":[]}},"type":"object","required":["project_id","pending_count","in_progress_count","completed_count","skipped_count","total_parts"],"title":"ProjectIntentSummary","description":"Aggregate across a project's parts — drives the combined nudge badge."},"ProjectPricingPreviewResponse":{"properties":{"total_amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$","title":"Total Amount","description":"Estimated project subtotal in USD before tax/shipping."},"lead_time_days":{"type":"integer","minimum":1.0,"title":"Lead Time Days","description":"Numeric business-day promise used for date arithmetic."},"lead_time_display":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Lead Time Display","description":"Display range such as '7-10' when the calendar promise engine is active."},"lead_time_source":{"type":"string","title":"Lead Time Source","description":"Internal source label for the selected lead-time promise."},"manual_review_required":{"type":"boolean","title":"Manual Review Required","description":"True when instant lead-time promise should route to manual review.","default":false},"manual_review_reasons":{"items":{"type":"string"},"type":"array","title":"Manual Review Reasons","description":"Human-readable reasons that prevented a confident instant promise."},"pricing_config_version":{"type":"string","title":"Pricing Config Version"}},"type":"object","required":["total_amount","lead_time_days","lead_time_source","pricing_config_version"],"title":"ProjectPricingPreviewResponse","description":"Read-only project estimate preview for draft Order Summary UI.\n\nMirrors the same pricing calculation used when freezing an auto-estimate\nquote, without creating a Quote or emitting pricing telemetry."},"ProjectResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"status":{"type":"string","title":"Status"},"priority":{"type":"string","title":"Priority"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"part_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Part Count"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"submitted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted At"},"order_placed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Placed At"},"expected_delivery_date_min":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Min"},"expected_delivery_date_max":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Delivery Date Max"}},"type":"object","required":["id","name","status","priority","user_id","created_at","updated_at"],"title":"ProjectResponse","description":"Project summary returned in list endpoints.\n\nMaps 1-to-1 with the ``Project`` SQLAlchemy model, excluding\nrelationships to keep the payload lightweight."},"ProjectReviewSummary":{"properties":{"parts":{"items":{"$ref":"#/components/schemas/PartReviewSummary"},"type":"array","title":"Parts"}},"type":"object","required":["parts"],"title":"ProjectReviewSummary","description":"Project-level review summary — one row per part with pending items."},"ProjectStatsResponse":{"properties":{"total":{"type":"integer","title":"Total"},"by_status":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Status"}},"type":"object","required":["total","by_status"],"title":"ProjectStatsResponse","description":"Project count statistics for the user dashboard.\n\nReturns the total number of projects and a breakdown by status,\nenabling the dashboard to render stat cards from a single API call."},"ProjectStatus":{"type":"string","enum":["draft","submitted","in_review","quoted","quote_rejected","approved","awaiting_confirmation","payment_pending","payment_received","order_confirmed","in_production","shipped","delivered","completed","cancelled"],"title":"ProjectStatus"},"ProjectSubmitResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"submitted_at":{"type":"string","format":"date-time","title":"Submitted At"}},"type":"object","required":["id","status","submitted_at"],"title":"ProjectSubmitResponse","description":"Confirmation response after submitting a project for review.\n\n``submitted_at`` is populated from the project's ``updated_at``\ntimestamp which reflects when the status transition occurred."},"ProjectSupplierQuoteCreate":{"properties":{"total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount Cents"},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"USD"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"line_items":{"items":{"$ref":"#/components/schemas/LineItem"},"type":"array","title":"Line Items"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"document_kind":{"type":"string","enum":["quote","invoice"],"title":"Document Kind","default":"quote"}},"type":"object","required":["supplier_contact_id"],"title":"ProjectSupplierQuoteCreate","description":"Create a supplier quote/invoice for any active supplier on a project."},"ProjectUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"}},"type":"object","title":"ProjectUpdate","description":"Partial update for an existing project.\n\nAll fields are optional — only supplied fields are applied.\n``shipping_address_id`` can be updated regardless of project status;\nall other fields require the project to be in DRAFT status."},"PurchaseOrderCreate":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"po_number":{"type":"string","maxLength":100,"minLength":1,"title":"Po Number"},"po_document_r2_key":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Po Document R2 Key"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"tax_calculation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Calculation Id"},"tax_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tax Amount"},"total_with_tax":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total With Tax"}},"type":"object","required":["project_id","po_number"],"title":"PurchaseOrderCreate","description":"Request to submit a purchase order.\n\nIf ``tax_calculation_id`` is provided (from a prior ``calculate-tax``\ncall), the tax amounts are stored on the Payment record for later\nuse when the admin marks the PO as received."},"QuoteAdminSendResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"total_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Amount"},"tax_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Amount"},"tax_auto_calculated":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Auto Calculated"},"line_items":{"items":{"$ref":"#/components/schemas/QuoteLineItemResponse"},"type":"array","title":"Line Items","default":[]}},"type":"object","required":["id","status"],"title":"QuoteAdminSendResponse","description":"Response after sending a quote to the customer."},"QuoteAdminUpdate":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"New quote status (must be a valid QuoteStatus value)"},"total_amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Total Amount","description":"Total quote amount in USD"},"lead_time_days":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Lead Time Days","description":"Estimated business days until delivery (numeric, used for arithmetic)"},"lead_time_display":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Lead Time Display","description":"Display override for lead time (e.g. '4-5', '7-10'). Overrides the numeric lead_time_days on the PDF and user-facing quote cards. When unset, the numeric value is rendered instead."},"additional_line_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Input"},"type":"array"},{"type":"null"}],"title":"Additional Line Items","description":"Admin-entered misc line items rendered ABOVE the tax line (e.g. rush fee, tooling). INCLUDED in the Stripe Tax base."},"additional_line_items_post_tax":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Input"},"type":"array"},{"type":"null"}],"title":"Additional Line Items Post Tax","description":"Admin-entered misc line items rendered BELOW the tax line (e.g. shipping, handling, flat discount). NOT taxed — adds to the grand total without affecting the Stripe Tax base."},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until","description":"Quote expiration timestamp (timezone-aware)"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes","description":"Notes visible to the customer"},"is_human_reviewed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Human Reviewed","description":"Flag indicating an admin has reviewed this quote"},"tax_amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Tax Amount","description":"Tax amount in USD (overrides auto-calculated value)"},"require_deposit":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Require Deposit","description":"Whether a deposit is required before production"},"deposit_percentage":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Deposit Percentage","description":"Deposit percentage (0-100)"},"customer_name_override":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Customer Name Override","description":"Override for the 'Prepared For' name on the quote PDF. Used when an admin creates a quote on behalf of an end customer. Pass an empty string to clear the override."},"customer_email_override":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Customer Email Override","description":"Override for the 'Prepared For' email on the quote PDF. Pass an empty string to clear the override."},"customer_billing_address_override":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Customer Billing Address Override","description":"Free-form billing address override for the 'Bill To' block on the quote and invoice PDFs. Multi-line strings (newline-separated) are rendered as-is. Pass an empty string to clear the override and fall back to the order's shipping address / BusinessProfile billing address."},"customer_shipping_address_override":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Customer Shipping Address Override","description":"Free-form shipping address override for the 'Ship To' block on the quote and invoice PDFs. Multi-line strings (newline-separated) are rendered as-is. Pass an empty string to clear the override and fall back to the project's resolved shipping address."},"customer_shipping_name_override":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Customer Shipping Name Override","description":"Shipping CONTACT name override for the 'Ship To' block on the quote, invoice, and packing slip PDFs (the receiving dock vs AP-department distinction). Pass an empty string to clear and fall back to customer_name_override, then the project owner's full name."}},"type":"object","title":"QuoteAdminUpdate","description":"Admin sets pricing, lead time, status, and review flag on a quote.\n\nUsed by the admin panel to transition a quote through its lifecycle.\n``total_amount`` is typically the sum of line item totals but can be\noverridden (e.g. to apply a project-level discount)."},"QuoteApprovalRequest":{"properties":{"delivery_option_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Delivery Option Id","description":"Selected delivery option. Optional for legacy quotes; when omitted the backend uses the enabled default option."}},"type":"object","title":"QuoteApprovalRequest","description":"Quote approval payload with optional delivery option selection."},"QuoteApprovalResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"approved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Approved At"}},"type":"object","required":["id","status"],"title":"QuoteApprovalResponse","description":"Confirmation returned after a user approves, rejects, or requests changes on a quote.\n\n``approved_at`` is populated from the quote's ``updated_at``\ntimestamp when approving; ``None`` for reject and request-changes."},"QuoteAuditResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"action":{"type":"string","title":"Action"},"actor_id":{"type":"string","title":"Actor Id"},"actor_type":{"type":"string","title":"Actor Type"},"old_values":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Old Values"},"new_values":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"New Values"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","quote_id","action","actor_id","actor_type","created_at"],"title":"QuoteAuditResponse","description":"A single audit trail entry for a quote.\n\nRecords who did what, and the before/after values for the changed\nfields.  Used by the admin panel to display the quote history\ntimeline."},"QuoteChangesRequest":{"properties":{"message":{"type":"string","maxLength":5000,"minLength":1,"title":"Message","description":"Description of the changes requested by the customer"}},"type":"object","required":["message"],"title":"QuoteChangesRequest","description":"Customer requests changes to a quote."},"QuoteDeliveryOptionGenerateRequest":{"properties":{"force":{"type":"boolean","title":"Force","description":"When true, regenerate existing option rows from Standard pricing.","default":false}},"type":"object","title":"QuoteDeliveryOptionGenerateRequest","description":"Generate customer-selectable delivery options from Standard pricing."},"QuoteDeliveryOptionLineItemCreate":{"properties":{"description":{"type":"string","maxLength":2000,"minLength":1,"title":"Description"},"quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Quantity","description":"Optional display quantity for additional option charges. When omitted, unit_price is treated as a flat line amount."},"unit_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"}],"title":"Unit Price","default":"0.00"},"is_taxable":{"type":"boolean","title":"Is Taxable","description":"Whether this additional item is included in the Stripe Tax base.","default":true},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["description"],"title":"QuoteDeliveryOptionLineItemCreate","description":"Create an option-specific additional line item."},"QuoteDeliveryOptionLineItemResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"delivery_option_id":{"type":"string","format":"uuid","title":"Delivery Option Id"},"part_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Part Id"},"part_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"quantity":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Quantity"},"unit_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Unit Price"},"total_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Price"},"is_additional":{"type":"boolean","title":"Is Additional","default":false},"is_taxable":{"type":"boolean","title":"Is Taxable","default":true},"sort_order":{"type":"integer","title":"Sort Order","default":0},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","delivery_option_id","created_at","updated_at"],"title":"QuoteDeliveryOptionLineItemResponse","description":"Line item for a selectable quote delivery option."},"QuoteDeliveryOptionLineItemUpdate":{"properties":{"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Quantity"},"unit_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Unit Price"},"is_taxable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Taxable"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"QuoteDeliveryOptionLineItemUpdate","description":"Admin update payload for an option-specific line item."},"QuoteDeliveryOptionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"sort_order":{"type":"integer","title":"Sort Order"},"is_enabled":{"type":"boolean","title":"Is Enabled"},"is_default":{"type":"boolean","title":"Is Default"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"lead_time_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lead Time Display"},"pricing_multiplier":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Pricing Multiplier"},"lead_time_multiplier":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Lead Time Multiplier"},"taxable_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Taxable Amount"},"tax_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Amount"},"tax_auto_calculated":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Auto Calculated"},"tax_rate":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Rate"},"stripe_tax_calculation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Tax Calculation Id"},"post_tax_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Post Tax Amount"},"grand_total_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Grand Total Amount"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"line_items":{"items":{"$ref":"#/components/schemas/QuoteDeliveryOptionLineItemResponse"},"type":"array","title":"Line Items","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","quote_id","key","label","sort_order","is_enabled","is_default","created_at","updated_at"],"title":"QuoteDeliveryOptionResponse","description":"Selectable quote option with its own lead time and pricing."},"QuoteDeliveryOptionSelectionRequest":{"properties":{"delivery_option_id":{"type":"string","format":"uuid","title":"Delivery Option Id","description":"Enabled delivery option to make the accepted option for checkout/PO."}},"type":"object","required":["delivery_option_id"],"title":"QuoteDeliveryOptionSelectionRequest","description":"Payload for changing the accepted delivery option before payment/PO."},"QuoteDeliveryOptionUpdate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Label"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"is_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Enabled"},"is_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Default"},"lead_time_days":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Lead Time Days"},"lead_time_display":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Lead Time Display"},"pricing_multiplier":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,3}0*$"},{"type":"null"}],"title":"Pricing Multiplier"},"lead_time_multiplier":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,3}0*$"},{"type":"null"}],"title":"Lead Time Multiplier"},"tax_amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Tax Amount"},"admin_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Notes"}},"type":"object","title":"QuoteDeliveryOptionUpdate","description":"Admin update payload for a quote delivery option."},"QuoteDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"intent":{"type":"string","title":"Intent","default":"manual_quote"},"total_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Amount"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"lead_time_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lead Time Display"},"additional_line_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Output"},"type":"array"},{"type":"null"}],"title":"Additional Line Items"},"additional_line_items_post_tax":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Output"},"type":"array"},{"type":"null"}],"title":"Additional Line Items Post Tax"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"ai_estimate":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Ai Estimate"},"ai_estimate_generated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ai Estimate Generated At"},"is_human_reviewed":{"type":"boolean","title":"Is Human Reviewed"},"require_deposit":{"type":"boolean","title":"Require Deposit","default":false},"deposit_percentage":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Deposit Percentage"},"customer_name_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Name Override"},"customer_email_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email Override"},"customer_billing_address_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Billing Address Override"},"customer_shipping_address_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Shipping Address Override"},"customer_shipping_name_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Shipping Name Override"},"reviewed_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reviewed By"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"tax_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Amount"},"tax_auto_calculated":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Auto Calculated"},"tax_rate":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Rate"},"quote_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quote Pdf Url"},"cost_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cost Snapshot"},"pricing_config_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pricing Config Version"},"snapshot_version":{"type":"integer","title":"Snapshot Version","default":0},"selected_delivery_option_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Selected Delivery Option Id"},"selected_delivery_option":{"anyOf":[{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"},{"type":"null"}]},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"line_items":{"items":{"$ref":"#/components/schemas/QuoteLineItemResponse"},"type":"array","title":"Line Items","default":[]},"delivery_options":{"items":{"$ref":"#/components/schemas/QuoteDeliveryOptionResponse"},"type":"array","title":"Delivery Options","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","status","is_human_reviewed","project_id","created_at","updated_at"],"title":"QuoteDetailResponse","description":"Full quote representation with nested line items.\n\nUsed by GET /quotes/{id} to return the quote along with all of its\nline items in a single response.  Includes AI estimation metadata,\nreview tracking fields, and tax calculation results."},"QuoteLineItemCreate":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description","description":"Line item description (e.g. material, process details)"},"quantity":{"type":"integer","minimum":1.0,"title":"Quantity"},"unit_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Unit Price","description":"Per-unit price in USD"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes","description":"Internal notes for this line item"}},"type":"object","required":["part_id","quantity"],"title":"QuoteLineItemCreate","description":"Admin creates a line item on an existing quote.\n\n``part_id`` must reference a part belonging to the same project as\nthe quote.  ``quantity`` typically mirrors the part's\n``required_quantity`` but can be overridden."},"QuoteLineItemResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"part_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"quantity":{"type":"integer","title":"Quantity"},"unit_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Unit Price"},"total_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Price"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","part_id","quantity","created_at","updated_at"],"title":"QuoteLineItemResponse","description":"A single line item within a quote.\n\n``total_price`` is computed server-side as ``quantity * unit_price``\nwhen both values are present."},"QuoteLineItemUpdate":{"properties":{"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"quantity":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Quantity"},"unit_price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"},{"type":"null"}],"title":"Unit Price"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"QuoteLineItemUpdate","description":"Admin updates a line item on an existing quote.\n\nAll fields are optional -- only supplied fields are applied."},"QuoteLostReason":{"type":"string","enum":["price_too_high","lead_time_too_long","went_elsewhere","project_cancelled","spec_changed","no_response","other"],"title":"QuoteLostReason","description":"Structured why-we-lost-it taxonomy for quotes (retention MVP).\n\nCaptured forward-only from three sources (see ``LostReasonSource``);\nlegacy free-text reasons in QuoteAudit JSON are NOT backfilled. Feeds\nthe Customers CRM timeline and, via ``Quote.pricing_bucket_key``, the\nfuture pricing-calibration join (PRO-230)."},"QuoteRejectRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason","description":"Optional reason for rejecting the quote"},"lost_reason":{"anyOf":[{"$ref":"#/components/schemas/QuoteLostReason"},{"type":"null"}],"description":"Structured loss reason chip (price_too_high, lead_time_too_long, ...)"}},"type":"object","title":"QuoteRejectRequest","description":"Customer rejects a quote, optionally providing a reason.\n\n``lost_reason`` is the structured loss-intelligence chip (retention MVP):\none of the ``QuoteLostReason`` values. The free-text ``reason`` remains\nas the optional note that accompanies it."},"QuoteRequestCreate":{"properties":{"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes","description":"Additional notes or requirements for the quote request"},"target_delivery_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Target Delivery Date","description":"Customer's desired delivery date for the project"}},"type":"object","title":"QuoteRequestCreate","description":"User request for a quote on a project.\n\nSubmitted by the project owner after configuring parts and specs.\nThe quote is created in ``draft`` status and an admin must review it."},"QuoteResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"intent":{"type":"string","title":"Intent","default":"manual_quote"},"total_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Amount"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"lead_time_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lead Time Display"},"additional_line_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Output"},"type":"array"},{"type":"null"}],"title":"Additional Line Items"},"additional_line_items_post_tax":{"anyOf":[{"items":{"$ref":"#/components/schemas/AdditionalLineItem-Output"},"type":"array"},{"type":"null"}],"title":"Additional Line Items Post Tax"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"is_human_reviewed":{"type":"boolean","title":"Is Human Reviewed"},"require_deposit":{"type":"boolean","title":"Require Deposit","default":false},"deposit_percentage":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Deposit Percentage"},"customer_name_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Name Override"},"customer_email_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email Override"},"customer_billing_address_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Billing Address Override"},"customer_shipping_address_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Shipping Address Override"},"customer_shipping_name_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Shipping Name Override"},"selected_delivery_option_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Selected Delivery Option Id"},"snapshot_version":{"type":"integer","title":"Snapshot Version","default":0},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","status","is_human_reviewed","project_id","created_at","updated_at"],"title":"QuoteResponse","description":"Quote summary returned in list endpoints.\n\nOmits line items and audit trail to keep the payload lightweight.\nThe ``status`` field is serialised as its string value (e.g.\n``\"draft\"``, ``\"quoted\"``)."},"QuoteReviewRequest":{"properties":{"reviewed":{"type":"boolean","title":"Reviewed","default":true}},"type":"object","title":"QuoteReviewRequest","description":"Optional body for the review endpoint.\n\nDefaults to ``reviewed=True`` (mark as reviewed).  Pass\n``reviewed=False`` to clear the review and allow further edits."},"QuoteReviewResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"is_human_reviewed":{"type":"boolean","title":"Is Human Reviewed"},"reviewed_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reviewed By"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"}},"type":"object","required":["id","status","is_human_reviewed"],"title":"QuoteReviewResponse","description":"Response after updating review status on a quote."},"ReactivateSubmit":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"ReactivateSubmit"},"RecentActivityItem":{"properties":{"type":{"type":"string","title":"Type"},"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"user_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Name"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}},"type":"object","required":["type","id","title","status","created_at"],"title":"RecentActivityItem","description":"A single recent activity entry for the dashboard feed."},"Reclassification":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"new_type":{"type":"string","title":"New Type"},"is_confirmation":{"type":"boolean","title":"Is Confirmation","default":false},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","new_type","created_at"],"title":"Reclassification"},"RecommendationFeedbackCreate":{"properties":{"feedback_type":{"type":"string","enum":["recommendation_helpful","recommendation_flagged"],"title":"Feedback Type"},"recommendation_index":{"type":"integer","minimum":0.0,"title":"Recommendation Index","description":"Recommendation index in synthesis"},"feature_refs":{"items":{"type":"string"},"type":"array","title":"Feature Refs"},"finding_refs":{"items":{"type":"string"},"type":"array","title":"Finding Refs"}},"type":"object","required":["feedback_type","recommendation_index"],"title":"RecommendationFeedbackCreate","description":"Request body for POST /parts/{part_id}/recommendation-feedback."},"RecommendationFeedbackResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"outcome_type":{"type":"string","title":"Outcome Type"},"source":{"type":"string","title":"Source"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","part_id","outcome_type","source","data","created_at"],"title":"RecommendationFeedbackResponse","description":"Response for recommendation feedback submission."},"RecomputeReport":{"properties":{"total_buckets":{"type":"integer","title":"Total Buckets"},"buckets_with_high_confidence":{"type":"integer","title":"Buckets With High Confidence"},"buckets_with_medium_confidence":{"type":"integer","title":"Buckets With Medium Confidence"},"buckets_with_low_confidence":{"type":"integer","title":"Buckets With Low Confidence"},"buckets_with_no_confidence":{"type":"integer","title":"Buckets With No Confidence"},"sample_size_histogram":{"additionalProperties":{"type":"integer"},"type":"object","title":"Sample Size Histogram"},"flagged_outliers_total":{"type":"integer","title":"Flagged Outliers Total"},"skipped_count":{"type":"integer","title":"Skipped Count","description":"Line items skipped (no geometry, deleted parts, etc.)","default":0},"duration_seconds":{"type":"number","title":"Duration Seconds"}},"type":"object","required":["total_buckets","buckets_with_high_confidence","buckets_with_medium_confidence","buckets_with_low_confidence","buckets_with_no_confidence","sample_size_histogram","flagged_outliers_total","duration_seconds"],"title":"RecomputeReport","description":"Returned from recompute_all_buckets / manual recompute admin endpoint."},"RegisterWithInviteRequest":{"properties":{"invite_token":{"type":"string","minLength":1,"title":"Invite Token"},"password":{"type":"string","minLength":8,"title":"Password"},"first_name":{"type":"string","minLength":1,"title":"First Name"},"last_name":{"type":"string","minLength":1,"title":"Last Name"}},"type":"object","required":["invite_token","password","first_name","last_name"],"title":"RegisterWithInviteRequest","description":"Request body for POST /auth/register-with-invite.\n\nThe email is derived from the validated invite token — callers\ndo not supply it.  Password must be at least 8 characters."},"RegisterWithInviteResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"email":{"type":"string","title":"Email"},"dev_mode":{"type":"boolean","title":"Dev Mode","default":false}},"type":"object","required":["success","email"],"title":"RegisterWithInviteResponse","description":"Response body for POST /auth/register-with-invite."},"RetriggerAnalysisRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"RetriggerAnalysisRequest","description":"Body for ``POST /parts/{part_id}/retrigger-analysis``.\n\n``reason`` is captured in structured logs for stuck-state\nobservability (e.g., ``\"user_clicked_retry\"``,\n``\"admin_override_post_review\"``). Optional — defaults to a generic\nstring when the caller doesn't have richer context."},"RetriggerAnalysisResponse":{"properties":{"status":{"type":"string","const":"computing","title":"Status"},"part_id":{"type":"string","format":"uuid","title":"Part Id"}},"type":"object","required":["status","part_id"],"title":"RetriggerAnalysisResponse","description":"Response for the retrigger endpoint.\n\nKeeps the legacy ``status=computing`` wire value after a successful\nretrigger. The frontend invalidates its analysis queries and reads\nthe authoritative ``analysis_status`` from the part/version payload."},"RetryAnalysisResponse":{"properties":{"status":{"type":"string","title":"Status","description":"'started' on success"},"workflow_id":{"type":"string","title":"Workflow Id","description":"Temporal workflow ID of the new run"}},"type":"object","required":["status","workflow_id"],"title":"RetryAnalysisResponse","description":"Response after kicking off a drawing analysis retry."},"RfqPackagePartPreview":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"decision":{"type":"string","enum":["user_pdf","needs_shop_drawing"],"title":"Decision"},"has_original_pdf":{"type":"boolean","title":"Has Original Pdf"},"has_redacted_pdf":{"type":"boolean","title":"Has Redacted Pdf"},"shop_drawing_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shop Drawing Status"},"shop_drawing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shop Drawing Id"}},"type":"object","required":["id","name","decision","has_original_pdf","has_redacted_pdf"],"title":"RfqPackagePartPreview","description":"One row in the RFQ package preview — the dialog renders this directly."},"RfqPackagePreview":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"parts":{"items":{"$ref":"#/components/schemas/RfqPackagePartPreview"},"type":"array","title":"Parts"}},"type":"object","required":["project_id","parts"],"title":"RfqPackagePreview","description":"Project-scoped preview returned by ``GET /rfq-package/preview``."},"RoleDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"permissions":{"items":{"$ref":"#/components/schemas/PermissionResponse"},"type":"array","title":"Permissions","default":[]},"admins":{"items":{"$ref":"#/components/schemas/AdminSummary"},"type":"array","title":"Admins","default":[]}},"type":"object","required":["id","name"],"title":"RoleDetailResponse","description":"Full role detail with permissions and assigned admins."},"RolePermissionUpdate":{"properties":{"permission_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Permission Ids","description":"Complete list of permission IDs for this role"}},"type":"object","required":["permission_ids"],"title":"RolePermissionUpdate","description":"Request to update a role's permissions."},"RoleResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"permission_count":{"type":"integer","title":"Permission Count","default":0},"admin_count":{"type":"integer","title":"Admin Count","default":0}},"type":"object","required":["id","name"],"title":"RoleResponse","description":"Role summary for list views."},"RuleInfo":{"properties":{"slug":{"type":"string","title":"Slug"},"audience":{"type":"string","title":"Audience"},"category":{"type":"string","title":"Category"},"priority":{"type":"integer","title":"Priority"},"mode":{"$ref":"#/components/schemas/FollowupRuleMode"},"description":{"type":"string","title":"Description"}},"type":"object","required":["slug","audience","category","priority","mode","description"],"title":"RuleInfo"},"RuleModesUpdate":{"properties":{"rule_modes":{"additionalProperties":{"$ref":"#/components/schemas/FollowupRuleMode"},"type":"object","title":"Rule Modes"}},"type":"object","required":["rule_modes"],"title":"RuleModesUpdate"},"ScoreBreakdown":{"properties":{"errors":{"type":"integer","title":"Errors","default":0},"warnings":{"type":"integer","title":"Warnings","default":0},"infos":{"type":"integer","title":"Infos","default":0},"weighted_score":{"type":"integer","title":"Weighted Score","default":0},"blockers":{"type":"integer","title":"Blockers","default":0},"review_items":{"type":"integer","title":"Review Items","default":0},"cost_notes":{"type":"integer","title":"Cost Notes","default":0}},"type":"object","title":"ScoreBreakdown","description":"DFM score computation breakdown."},"SelectManufacturerInput":{"properties":{"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"supplier_quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Supplier Quote Id"},"their_price_cents":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":0.0},{"type":"null"}],"title":"Their Price Cents"},"their_lead_time_days":{"anyOf":[{"type":"integer","maximum":1000.0,"minimum":0.0},{"type":"null"}],"title":"Their Lead Time Days"},"their_lead_time_display":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Their Lead Time Display"},"order_confirmed_at":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Order Confirmed At"}},"type":"object","required":["supplier_contact_id"],"title":"SelectManufacturerInput","description":"Body for ``POST /admin/projects/{id}/supplier-order`` (direct pick).\n\nSelect ANY active supplier as the manufacturer — with or without a quote.\n``supplier_contact_id`` is required; everything else is optional:\n\n* ``supplier_quote_id`` — when the pick is backed by a won quote (the RFQ\n  path also routes through here). When set and the quote is accepted,\n  ``their_price_cents`` / ``their_lead_time_days`` default from the quote\n  unless explicitly overridden in this body.\n* ``their_price_cents`` / ``their_lead_time_days`` / ``their_lead_time_display``\n  — the manual price + lead time captured when there's no quote.\n* ``order_confirmed_at`` — the calendar DATE the supplier confirmed the\n  order (default today, applied server-side when omitted). This is the clock\n  the buy-side ETA (lead time → estimated ship) counts from, so back-dating\n  a selection yields the correct ETA. Stored as a UTC-noon ``DateTime``\n  (D6); only honoured when the order is CREATED — editing an existing\n  order's confirmation date goes through ``PATCH /admin/supplier-orders/{id}``."},"SendResultResponse":{"properties":{"outcome":{"type":"string","title":"Outcome"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"}},"type":"object","required":["outcome"],"title":"SendResultResponse"},"ShipmentCreate":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"carrier":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Carrier"},"tracking_number":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Initial status (defaults to 'pending' if omitted)"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["project_id"],"title":"ShipmentCreate","description":"Admin creates a shipment for a project."},"ShipmentDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"status":{"type":"string","title":"Status"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"events":{"items":{"$ref":"#/components/schemas/ShipmentEventResponse"},"type":"array","title":"Events","default":[]},"packages":{"items":{"$ref":"#/components/schemas/ShipmentPackageTrackingResponse"},"type":"array","title":"Packages","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","status","created_at","updated_at"],"title":"ShipmentDetailResponse","description":"Full shipment with nested events and project name."},"ShipmentEventCreate":{"properties":{"status":{"type":"string","title":"Status","description":"Status at this event"},"description":{"type":"string","maxLength":1000,"minLength":1,"title":"Description"},"location":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Location"},"occurred_at":{"type":"string","format":"date-time","title":"Occurred At"}},"type":"object","required":["status","description","occurred_at"],"title":"ShipmentEventCreate","description":"Admin adds a tracking event to a shipment."},"ShipmentEventResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"shipment_id":{"type":"string","format":"uuid","title":"Shipment Id"},"status":{"type":"string","title":"Status"},"description":{"type":"string","title":"Description"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"occurred_at":{"type":"string","format":"date-time","title":"Occurred At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","shipment_id","status","description","occurred_at","created_at"],"title":"ShipmentEventResponse","description":"A single tracking event within a shipment."},"ShipmentPackageListUpdate":{"properties":{"packages":{"items":{"$ref":"#/components/schemas/ShipmentPackageUpsert"},"type":"array","title":"Packages"}},"type":"object","title":"ShipmentPackageListUpdate"},"ShipmentPackageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"shipment_id":{"type":"string","format":"uuid","title":"Shipment Id"},"package_index":{"type":"integer","title":"Package Index"},"weight":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Weight"},"weight_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Weight Unit"},"length":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Length"},"width":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Height"},"dimension_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dimension Unit"},"contents_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contents Summary"},"source":{"$ref":"#/components/schemas/ShipmentPackageSource"},"source_inbound_package_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Source Inbound Package Id"},"carrier_package_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier Package Id"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"label_status":{"$ref":"#/components/schemas/LabelStatus"},"label_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label Pdf Url"},"label_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label Format"},"label_created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Label Created At"},"label_voided_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Label Voided At"},"label_cost_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Label Cost Cents"},"label_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label Currency"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","shipment_id","package_index","source","label_status","created_at","updated_at"],"title":"ShipmentPackageResponse"},"ShipmentPackageSource":{"type":"string","enum":["manual","inbound_seeded"],"title":"ShipmentPackageSource"},"ShipmentPackageTrackingResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"package_index":{"type":"integer","title":"Package Index"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"weight_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Weight Unit"},"label_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label Status"}},"type":"object","required":["id","package_index"],"title":"ShipmentPackageTrackingResponse","description":"Customer-safe outbound package tracking summary."},"ShipmentPackageUpsert":{"properties":{"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id"},"package_index":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Package Index"},"weight":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Weight"},"weight_unit":{"anyOf":[{"type":"string","enum":["kg","g","lb","lbs","oz"]},{"type":"null"}],"title":"Weight Unit"},"length":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Length"},"width":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Height"},"dimension_unit":{"anyOf":[{"type":"string","enum":["in","cm","mm"]},{"type":"null"}],"title":"Dimension Unit"},"contents_summary":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Contents Summary"},"tracking_number":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"}},"type":"object","title":"ShipmentPackageUpsert"},"ShipmentPickupCreate":{"properties":{"window_start":{"type":"string","format":"date-time","title":"Window Start"},"window_end":{"type":"string","format":"date-time","title":"Window End"},"location":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Location"},"instructions":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Instructions"}},"type":"object","required":["window_start","window_end"],"title":"ShipmentPickupCreate"},"ShipmentPickupResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"shipment_id":{"type":"string","format":"uuid","title":"Shipment Id"},"carrier":{"$ref":"#/components/schemas/CarrierCode"},"pickup_confirmation_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pickup Confirmation Number"},"status":{"$ref":"#/components/schemas/PickupStatus"},"window_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Window Start"},"window_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Window End"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instructions"},"cancelled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cancelled At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","shipment_id","carrier","status","created_at","updated_at"],"title":"ShipmentPickupResponse"},"ShipmentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Carrier"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url"},"status":{"type":"string","title":"Status"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","status","created_at","updated_at"],"title":"ShipmentResponse","description":"Shipment summary (without events)."},"ShipmentStatus":{"type":"string","enum":["pending","processing","ready_to_ship","shipped","in_transit","out_for_delivery","delivered","failed_delivery","returned","cancelled"],"title":"ShipmentStatus"},"ShipmentUpdate":{"properties":{"carrier":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Carrier"},"tracking_number":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Tracking Number"},"tracking_url":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Tracking Url"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"New status (must be a valid ShipmentStatus transition)"},"estimated_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Estimated Delivery"},"actual_delivery":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Actual Delivery"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"ShipmentUpdate","description":"Admin updates shipment details. All fields optional."},"ShippingAddressCreate":{"properties":{"label":{"type":"string","maxLength":100,"minLength":1,"title":"Label"},"address_line1":{"type":"string","maxLength":255,"minLength":1,"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Address Line2"},"city":{"type":"string","maxLength":100,"minLength":1,"title":"City"},"state":{"type":"string","maxLength":100,"minLength":1,"title":"State"},"postal_code":{"type":"string","maxLength":20,"minLength":1,"title":"Postal Code"},"country":{"type":"string","maxLength":100,"title":"Country","default":"US"},"is_default":{"type":"boolean","title":"Is Default","default":false}},"type":"object","required":["label","address_line1","city","state","postal_code"],"title":"ShippingAddressCreate","description":"Request body for creating a new shipping address."},"ShippingAddressInput":{"properties":{"line1":{"type":"string","maxLength":255,"minLength":1,"title":"Line1"},"line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line2"},"city":{"type":"string","maxLength":100,"minLength":1,"title":"City"},"state":{"type":"string","maxLength":50,"minLength":2,"title":"State","description":"State name or two-letter code"},"postal_code":{"type":"string","maxLength":20,"minLength":3,"title":"Postal Code"},"country":{"type":"string","maxLength":50,"title":"Country","description":"Country name or two-letter code","default":"US"}},"type":"object","required":["line1","city","state","postal_code"],"title":"ShippingAddressInput","description":"Shipping address for tax calculation (destination-based taxation)."},"ShippingAddressResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"label":{"type":"string","title":"Label"},"address_line1":{"type":"string","title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State"},"postal_code":{"type":"string","title":"Postal Code"},"country":{"type":"string","title":"Country"},"is_default":{"type":"boolean","title":"Is Default"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","user_id","label","address_line1","city","state","postal_code","country","is_default","created_at","updated_at"],"title":"ShippingAddressResponse","description":"Full shipping address representation."},"ShippingAddressSnapshot":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"contact_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Name"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},"type":"object","title":"ShippingAddressSnapshot","description":"Normalized origin/destination address for carrier operations."},"ShippingAddressUpdate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Label"},"address_line1":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"State"},"postal_code":{"anyOf":[{"type":"string","maxLength":20,"minLength":1},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Country"},"is_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Default"}},"type":"object","title":"ShippingAddressUpdate","description":"Request body for partially updating an existing shipping address.\n\nAll fields are optional; only the fields that are provided will be\napplied."},"ShippingWorkspaceResponse":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"customer_visible":{"type":"boolean","title":"Customer Visible"},"default_origin":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]},"destination":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSnapshot"},{"type":"null"}]},"supplier_order":{"anyOf":[{"$ref":"#/components/schemas/SupplierOrderRead"},{"type":"null"}]},"inbound_shipments":{"items":{"$ref":"#/components/schemas/InboundShipmentResponse"},"type":"array","title":"Inbound Shipments"},"outbound_shipment":{"anyOf":[{"$ref":"#/components/schemas/OutboundShipmentResponse"},{"type":"null"}]},"packing_slip":{"anyOf":[{"$ref":"#/components/schemas/PackingSlipResponse"},{"type":"null"}]},"carrier_integrations_enabled":{"type":"boolean","title":"Carrier Integrations Enabled","default":false},"ups_labels_enabled":{"type":"boolean","title":"Ups Labels Enabled","default":false},"ups_pickup_enabled":{"type":"boolean","title":"Ups Pickup Enabled","default":false},"dhl_tracking_enabled":{"type":"boolean","title":"Dhl Tracking Enabled","default":false}},"type":"object","required":["project_id","customer_visible"],"title":"ShippingWorkspaceResponse"},"SimilarPartAnchor":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"project_name":{"type":"string","title":"Project Name"},"quote_id":{"type":"string","format":"uuid","title":"Quote Id"},"admin_unit_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Admin Unit Price"},"quoted_at":{"type":"string","format":"date-time","title":"Quoted At"},"fingerprint_distance":{"type":"number","title":"Fingerprint Distance"},"process_label":{"type":"string","title":"Process Label"},"material_label":{"type":"string","title":"Material Label"},"feature_summary":{"additionalProperties":{"type":"integer"},"type":"object","title":"Feature Summary"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"}},"type":"object","required":["part_id","project_id","project_name","quote_id","admin_unit_price","quoted_at","fingerprint_distance","process_label","material_label","feature_summary"],"title":"SimilarPartAnchor","description":"One historical priced part used as a pricing anchor.\n\nReturned alongside a feature-summary diff and a presigned thumbnail\nURL so the admin UI can render a card with the part's visual + price."},"SkipRequest":{"properties":{"reason":{"type":"string","maxLength":500,"title":"Reason"}},"type":"object","required":["reason"],"title":"SkipRequest"},"SnoozeRequest":{"properties":{"until":{"type":"string","format":"date-time","title":"Until"}},"type":"object","required":["until"],"title":"SnoozeRequest"},"SourcePreviewUrlResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Presigned GET URL (24h TTL)"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"mime_type":{"type":"string","title":"Mime Type","description":"Best-effort MIME inferred from R2 key extension"},"filename":{"type":"string","title":"Filename","description":"Original filename from the R2 key"},"document_kind":{"type":"string","title":"Document Kind","description":"Per-attachment kind tag — quote or invoice","default":"quote"}},"type":"object","required":["url","expires_at","mime_type","filename"],"title":"SourcePreviewUrlResponse","description":"Response for ``GET /admin/supplier-quotes/{id}/source-preview-url``.\n\nReturns a presigned R2 URL for ONE attachment on the quote (default:\nthe first), plus metadata the V2 UI needs to render the right\npreview (PDF iframe / CSV table / generic download). The agent's\n``prepare_quote_attachment`` MCP tool persists attachments in upload\norder; the admin UI can ask for a specific attachment by index via\nthe ``attachment_index`` query parameter.\n\nReturns 404 when the quote has no attachments (frontend falls back\nto the inline-body source or shows the empty state)."},"StripeConfigResponse":{"properties":{"publishable_key":{"type":"string","title":"Publishable Key"}},"type":"object","required":["publishable_key"],"title":"StripeConfigResponse","description":"Stripe publishable key for frontend Elements initialization."},"SupplierCapabilities":{"properties":{"processes":{"items":{"type":"string"},"type":"array","title":"Processes","description":"Ranked list of canonical ``dropdowns.value`` strings for category=``machining_process``. Index 0 is most preferred."}},"type":"object","title":"SupplierCapabilities","description":"Typed shape for ``supplier_contacts.capabilities`` JSONB.\n\nV1 (iteration 2): only ``processes`` is edited via UI. The list is\nORDERED — index 0 is the supplier's most preferred capability\n(\"we use this supplier mainly for CNC milling\"). Ranking feeds the\nfuture :func:`select_suppliers_for_project` weighting.\n\nOther dimensions on legacy rows (materials/finishes/coatings/\ncertifications/max_envelope_mm) are silently ignored on read\n(Pydantic v2 default ``extra='ignore'``) and overwritten on first\nUI-driven update. This is intentional — admins asked us to drop\nthem from the v1 directory."},"SupplierContactCreate":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"email":{"type":"string","format":"email","title":"Email"},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Company"},"location":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Location"},"capabilities":{"$ref":"#/components/schemas/SupplierCapabilities"},"trust_tier":{"type":"string","enum":["new","trusted","restricted"],"title":"Trust Tier","default":"new"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"admin_routing_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Routing Notes"}},"type":"object","required":["name","email"],"title":"SupplierContactCreate","description":"POST body — no readonly fields."},"SupplierContactListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"active":{"type":"boolean","title":"Active"},"trust_tier":{"type":"string","enum":["new","trusted","restricted"],"title":"Trust Tier"},"capability_summary":{"items":{"type":"string"},"type":"array","title":"Capability Summary"},"last_contacted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Contacted At"},"response_count":{"type":"integer","title":"Response Count"},"decline_count":{"type":"integer","title":"Decline Count"}},"type":"object","required":["id","name","email","company","location","active","trust_tier","capability_summary","last_contacted_at","response_count","decline_count"],"title":"SupplierContactListItem","description":"Slim row for the list page — no full capabilities payload.\n\nShips ``capability_summary`` (the top-N processes, server-side\ncomputed) instead of the full capabilities JSON. Since only the\n``processes`` dimension is edited in v1, the summary is just\n``processes[:2]``."},"SupplierContactRead":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"email":{"type":"string","format":"email","title":"Email"},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Company"},"location":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Location"},"capabilities":{"$ref":"#/components/schemas/SupplierCapabilities"},"trust_tier":{"type":"string","enum":["new","trusted","restricted"],"title":"Trust Tier","default":"new"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"admin_routing_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Routing Notes"},"id":{"type":"string","format":"uuid","title":"Id"},"active":{"type":"boolean","title":"Active"},"last_contacted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Contacted At"},"response_count":{"type":"integer","title":"Response Count"},"decline_count":{"type":"integer","title":"Decline Count"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["name","email","id","active","last_contacted_at","response_count","decline_count","created_at","updated_at"],"title":"SupplierContactRead","description":"Full detail response — used by GET/POST/PATCH/restore.\n\nNote: ``declined_project_ids`` is NOT exposed here even though the\nmodel has it — v1 UI does not display it. Re-add when an \"incident\nhistory\" feature wants it."},"SupplierContactUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email"},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Company"},"location":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Location"},"capabilities":{"anyOf":[{"$ref":"#/components/schemas/SupplierCapabilities"},{"type":"null"}]},"trust_tier":{"anyOf":[{"type":"string","enum":["new","trusted","restricted"]},{"type":"null"}],"title":"Trust Tier"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"admin_routing_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Routing Notes"}},"type":"object","title":"SupplierContactUpdate","description":"PATCH body — all fields optional, partial update.\n\nDistinct from :class:`SupplierContactBase` rather than inheriting +\noverriding because Pydantic v2 makes ``Optional[T]`` inheritance\nawkward when the parent declares the field as required. Keeping the\nshapes side-by-side reads cleaner and pyright-strict has no false\npositives on partial dumps."},"SupplierOrderRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"supplier_quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Supplier Quote Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"supplier_contact_name":{"type":"string","title":"Supplier Contact Name"},"supplier_contact_email":{"type":"string","title":"Supplier Contact Email"},"supplier_contact_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Contact Company"},"their_price_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Their Price Cents"},"their_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Their Lead Time Days"},"their_lead_time_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Their Lead Time Display"},"won_quote_total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Won Quote Total Amount Cents"},"won_quote_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Won Quote Currency"},"won_quote_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Won Quote Lead Time Days"},"order_confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Confirmed At"},"mfg_status":{"$ref":"#/components/schemas/SupplierOrderStatus"},"mfg_tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mfg Tracking Number"},"mfg_estimated_ship_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Mfg Estimated Ship Date"},"actual_shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Shipped At"},"received_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Received At"},"supplier_invoice_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Invoice Number"},"supplier_invoice_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Supplier Invoice At"},"we_paid_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"We Paid Amount Cents"},"we_paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"We Paid At"},"payment_terms_net_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Payment Terms Net Days"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","supplier_contact_id","supplier_contact_name","supplier_contact_email","mfg_status","created_at","updated_at"],"title":"SupplierOrderRead","description":"Full buy-side order detail for the admin project view."},"SupplierOrderStatus":{"type":"string","enum":["sourcing","ordered","in_production","shipped_to_us","received"],"title":"SupplierOrderStatus","description":"Buy-side manufacturing status for a :class:`SupplierOrder`.\n\nTracks the physical fulfilment of the order we placed with the WINNING\nsupplier — distinct from the customer-facing ``ProjectStatus`` (sell side)\nand ``ShipmentStatus`` (the carrier leg to the customer). This is the\ninbound leg: parts being made by the supplier and shipped TO US.\n\nSOURCING:        winning supplier chosen, order not yet formally placed.\nORDERED:         PO sent to the supplier; production queued. (Default when\n                 ``accept_won`` auto-creates the SupplierOrder.)\nIN_PRODUCTION:   supplier is machining/fabricating the parts.\nSHIPPED_TO_US:   supplier has shipped the finished parts to our dock.\nRECEIVED:        parts received + inspected at our facility."},"SupplierOrderUpdate":{"properties":{"mfg_status":{"anyOf":[{"$ref":"#/components/schemas/SupplierOrderStatus"},{"type":"null"}]},"mfg_tracking_number":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Mfg Tracking Number"},"mfg_estimated_ship_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Mfg Estimated Ship Date"},"actual_shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Shipped At"},"received_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Received At"},"order_confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Order Confirmed At"},"their_price_cents":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":0.0},{"type":"null"}],"title":"Their Price Cents"},"their_lead_time_days":{"anyOf":[{"type":"integer","maximum":1000.0,"minimum":0.0},{"type":"null"}],"title":"Their Lead Time Days"},"their_lead_time_display":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Their Lead Time Display"},"supplier_invoice_number":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Supplier Invoice Number"},"supplier_invoice_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Supplier Invoice At"},"we_paid_amount_cents":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":0.0},{"type":"null"}],"title":"We Paid Amount Cents"},"we_paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"We Paid At"},"payment_terms_net_days":{"anyOf":[{"type":"integer","maximum":365.0,"minimum":0.0},{"type":"null"}],"title":"Payment Terms Net Days"},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"SupplierOrderUpdate","description":"Partial PATCH for a SupplierOrder.\n\nEvery field is optional; only the keys present in the request body are\napplied (``exclude_unset``). ``None`` is a meaningful value (clears the\nfield) for the nullable columns."},"SupplierQuoteDocumentRead":{"properties":{"extraction_status":{"type":"string","title":"Extraction Status","default":"uploaded"},"latest_extraction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Extraction Id"},"last_extracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Extracted At"},"has_reviewable_suggestion":{"type":"boolean","title":"Has Reviewable Suggestion","default":false},"extraction_error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extraction Error Message"},"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"supplier_quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Supplier Quote Id"},"vendor_thread_state_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Vendor Thread State Id"},"source":{"type":"string","title":"Source"},"document_kind":{"type":"string","title":"Document Kind"},"r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"R2 Key"},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"mime_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mime Type"},"file_size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size Bytes"},"gmail_thread_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gmail Thread Id"},"gmail_message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gmail Message Id"},"latest_extraction":{"anyOf":[{"$ref":"#/components/schemas/CommercialDocumentExtractionSummary"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","supplier_contact_id","source","document_kind","created_at","updated_at"],"title":"SupplierQuoteDocumentRead","description":"Supplier document row plus latest extraction summary."},"SupplierQuoteManualCreate":{"properties":{"total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount Cents"},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"USD"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"line_items":{"items":{"$ref":"#/components/schemas/LineItem"},"type":"array","title":"Line Items"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"SupplierQuoteManualCreate","description":"Manual entry from admin reading a supplier reply in Gmail.\n\nDistinct from :class:`app.agents.vendors.schemas.mcp.RecordSupplierQuoteInput`\n(the agent path requires ``gmail_message_id`` + ``thread_state_id``\nfrom the MCP context). The manual path derives those from the chosen\nThreadState URL parameter, and uses a sentinel\n``\"manual-entry-{uuid4().hex[:12]}\"`` for ``gmail_message_id``\n(eng-review §1.2 — UUID not timestamp to avoid millisecond collisions).\n\nValidation: range constants imported from :mod:`app.agents.vendors.schemas.mcp`\n(eng-review §1.3 — single source of truth). Currency is free-form\n3-char string (eng-review §1.4 — same as MCP path; FE select\nconstrains user input)."},"SupplierQuoteRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"supplier_contact_name":{"type":"string","title":"Supplier Contact Name"},"supplier_contact_email":{"type":"string","title":"Supplier Contact Email"},"gmail_thread_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gmail Thread Id"},"source":{"type":"string","title":"Source","default":"email"},"total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount Cents"},"currency":{"type":"string","title":"Currency"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"line_items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Line Items"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"source_email_body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Email Body"},"attachment_r2_keys":{"items":{"type":"string"},"type":"array","title":"Attachment R2 Keys"},"attachment_kinds":{"items":{"type":"string"},"type":"array","title":"Attachment Kinds"},"supplier_documents":{"items":{"$ref":"#/components/schemas/SupplierQuoteDocumentRead"},"type":"array","title":"Supplier Documents"},"document_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Kind"},"extraction_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Extraction Confidence"},"needs_human_review":{"type":"boolean","title":"Needs Human Review"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"reviewed_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reviewed By"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","supplier_contact_id","supplier_contact_name","supplier_contact_email","total_amount_cents","currency","lead_time_days","valid_until","line_items","notes","needs_human_review","reviewed_at","reviewed_by","created_at","updated_at"],"title":"SupplierQuoteRead","description":"Full detail response for ``GET /admin/supplier-quotes/{id}``.\n\nJoins the supplier contact's name + email at the schema layer so the\nFE doesn't have to make a second round-trip.\n\nPRO-113 V2: ``attachment_r2_keys`` is now exposed (previously hidden\nin V1 since admins kept PDFs in Gmail). The V2 Quote Correction View\nconsumes this to render the source-preview panel for attachment-\nbacked inbound replies. Frontend resolves R2 keys to presigned URLs\nvia the dedicated ``/source-preview-url`` endpoint."},"SupplierQuoteUpdate":{"properties":{"total_amount_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount Cents"},"currency":{"anyOf":[{"type":"string","maxLength":3,"minLength":3},{"type":"null"}],"title":"Currency"},"lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lead Time Days"},"valid_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Valid Until"},"line_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/LineItem"},"type":"array"},{"type":"null"}],"title":"Line Items"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"SupplierQuoteUpdate","description":"PATCH body — edits the existing quote row in place (eng-review §2.2).\n\nTo record a revised quote (e.g., supplier sent a new number), admin\nPOSTs a new revision via the create endpoint — append-on-revision\npattern preserves the audit trail (eng-review §1.6).\n\nAll fields optional; only fields present in the body are touched\n(``model_dump(exclude_unset=True)``)."},"SuppressRequest":{"properties":{"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"note":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Note"}},"type":"object","title":"SuppressRequest","description":"Admin suppression from the workspace: user-level, category-scoped\n(None = all lifecycle categories)."},"SuppressionItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"source":{"type":"string","title":"Source"},"active":{"type":"boolean","title":"Active"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","category","source","active","note","created_at"],"title":"SuppressionItem"},"SurfaceFinishCreate":{"properties":{"feature_id":{"type":"string","minLength":5,"title":"Feature Id","description":"Topology face ID of form ``face_N`` — looked up in the topology sidecar JSON."},"finish_type":{"type":"string","title":"Finish Type","description":"One of SURFACE_FINISH_TYPES."},"ra_um":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Ra Um","description":"Surface roughness in micrometers (Ra). Optional."},"custom_color_hex":{"anyOf":[{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},{"type":"null"}],"title":"Custom Color Hex","description":"Optional user-chosen tint (6-char hex). Overrides the default palette. Relevant for ``anodize_colored``, ``powder_coat``, ``paint``."},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["feature_id","finish_type"],"title":"SurfaceFinishCreate","description":"Payload for ``POST /parts/{part_id}/surface-finishes``."},"SurfaceFinishRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"feature_id":{"type":"string","title":"Feature Id"},"finish_type":{"type":"string","title":"Finish Type"},"ra_um":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ra Um"},"custom_color_hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Color Hex"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"state":{"type":"string","title":"State"},"source":{"type":"string","title":"Source"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"is_process_mismatch":{"type":"boolean","title":"Is Process Mismatch","default":false}},"type":"object","required":["id","part_id","cad_file_version_id","feature_id","finish_type","ra_um","custom_color_hex","notes","label","state","source","author","created_by","created_at","updated_at"],"title":"SurfaceFinishRead","description":"Flattened finish row — built by the service from an OutcomeEvent.\n\nNot an ORM passthrough: the source row is an ``OutcomeEvent`` with\n``data = {finish_type, ra_um, ...}``. The projection flattens that\npayload + adds the computed ``is_process_mismatch`` flag and the\nresolved visual label."},"SurfaceFinishSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"face_id":{"type":"string","title":"Face Id"},"finish_type":{"type":"string","title":"Finish Type"},"ra_um":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ra Um"},"custom_color_hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Color Hex"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"},"source":{"type":"string","title":"Source"},"state":{"type":"string","title":"State"},"is_process_mismatch":{"type":"boolean","title":"Is Process Mismatch","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"}},"type":"object","required":["id","face_id","finish_type","label","source","state","created_at"],"title":"SurfaceFinishSummary","description":"One surface-finish annotation (Phase 6E). Face-anchored OutcomeEvent."},"SurfaceFinishUpdate":{"properties":{"finish_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finish Type"},"ra_um":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Ra Um"},"custom_color_hex":{"anyOf":[{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},{"type":"null"}],"title":"Custom Color Hex"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"SurfaceFinishUpdate","description":"Payload for ``PATCH /surface-finishes/{id}``. All fields optional."},"SyncUserRequest":{"properties":{"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"}},"type":"object","title":"SyncUserRequest","description":"Optional profile fields sent during POST /auth/sync.\n\nThese supplement the ``sub`` (supabase_user_id) and ``email``\nthat are always extracted from the JWT itself."},"TaxBreakdownItem":{"properties":{"jurisdiction":{"type":"string","title":"Jurisdiction"},"rate":{"type":"string","title":"Rate"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"tax_type":{"type":"string","title":"Tax Type"}},"type":"object","required":["jurisdiction","rate","amount","tax_type"],"title":"TaxBreakdownItem","description":"A single jurisdiction's tax contribution."},"TaxCalculateRequest":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"shipping_address":{"$ref":"#/components/schemas/ShippingAddressInput"}},"type":"object","required":["project_id","shipping_address"],"title":"TaxCalculateRequest","description":"Request body for calculating tax on a project quote."},"TaxCalculateResponse":{"properties":{"calculation_id":{"type":"string","title":"Calculation Id"},"subtotal":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Subtotal"},"tax_amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Tax Amount"},"tax_rate":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Tax Rate"},"total":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total"},"tax_breakdown":{"items":{"$ref":"#/components/schemas/TaxBreakdownItem"},"type":"array","title":"Tax Breakdown"}},"type":"object","required":["calculation_id","subtotal","tax_amount","total","tax_breakdown"],"title":"TaxCalculateResponse","description":"Tax calculation result returned to the frontend."},"TaxCalculationResponse":{"properties":{"calculation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calculation Id"},"subtotal":{"type":"number","title":"Subtotal"},"tax_amount":{"type":"number","title":"Tax Amount"},"total":{"type":"number","title":"Total"},"tax_breakdown":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Tax Breakdown","default":[]},"is_tax_exempt":{"type":"boolean","title":"Is Tax Exempt","default":false}},"type":"object","required":["subtotal","tax_amount","total"],"title":"TaxCalculationResponse","description":"Result of a Stripe Tax calculation for a quote.\n\n``is_tax_exempt`` is ``True`` when the user's business profile is\nmarked as tax-exempt; in that case all tax amounts are zero."},"TaxExemptCertUploadResponse":{"properties":{"r2_key":{"type":"string","title":"R2 Key"}},"type":"object","required":["r2_key"],"title":"TaxExemptCertUploadResponse","description":"Response from the tax-exempt-cert upload proxy endpoint.\n\nCarries the R2 key the streamed file was written to. The client\npasses it back as ``tax_exempt_cert_r2_key`` on a subsequent\n``PATCH /business-profile`` call to associate the certificate with\nthe profile."},"TaxExemptToggleRequest":{"properties":{"is_tax_exempt":{"type":"boolean","title":"Is Tax Exempt"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["is_tax_exempt"],"title":"TaxExemptToggleRequest","description":"Request to toggle tax exemption on a business profile."},"TestEmailRequest":{"properties":{"to_email":{"type":"string","title":"To Email"},"template_name":{"type":"string","title":"Template Name","default":"welcome"}},"type":"object","required":["to_email"],"title":"TestEmailRequest"},"TestEmailResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","message"],"title":"TestEmailResponse"},"TimelineEntry":{"properties":{"entry_type":{"type":"string","title":"Entry Type"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"title":{"type":"string","title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Quote Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"lost_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lost Reason"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["entry_type","timestamp","title"],"title":"TimelineEntry","description":"One merged CRM timeline entry. The timeline QUERIES canonical sources\n(quotes/payments/comments/outreach) at read time — nothing is copied."},"ToleranceRationaleEntry":{"properties":{"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"spec":{"type":"string","maxLength":64,"title":"Spec"},"why":{"type":"string","maxLength":500,"title":"Why"},"source_certainty":{"type":"string","enum":["user_asserted","user_hypothetical","agent_inferred"],"title":"Source Certainty"}},"type":"object","required":["spec","why","source_certainty"],"title":"ToleranceRationaleEntry"},"ToleranceSpec":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"tolerance_type":{"type":"string","title":"Tolerance Type"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","tolerance_type","data","created_at"],"title":"ToleranceSpec"},"ToolCallSummary":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"is_error":{"type":"boolean","title":"Is Error","default":false}},"type":"object","title":"ToolCallSummary","description":"Compact tool-call summary rendered inline with a message."},"TrackBPrediction":{"properties":{"predicted_unit":{"type":"number","title":"Predicted Unit","description":"Track A unit price * median uplift"},"predicted_low":{"type":"number","title":"Predicted Low","description":"Track A unit price * q1 uplift"},"predicted_high":{"type":"number","title":"Predicted High","description":"Track A unit price * q3 uplift"},"median_uplift":{"type":"number","title":"Median Uplift"},"sample_size":{"type":"integer","title":"Sample Size"},"confidence":{"type":"string","title":"Confidence"},"calibration_source":{"additionalProperties":true,"type":"object","title":"Calibration Source","description":"Bucket key (process, complexity, qty) + last_updated_at"}},"type":"object","required":["predicted_unit","predicted_low","predicted_high","median_uplift","sample_size","confidence","calibration_source"],"title":"TrackBPrediction","description":"Predicted admin unit price + confidence, attached to calculate_cost output.\n\nPhase 1 only ships the schema; Phase 2 wires it into the response chain."},"TranscriptMessageRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"role":{"type":"string","title":"Role"},"content":{"type":"string","title":"Content"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallSummary"},"type":"array","title":"Tool Calls","default":[]}},"type":"object","required":["id","role","content"],"title":"TranscriptMessageRead"},"TranscriptNoteRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"part_name":{"type":"string","title":"Part Name"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"note":{"type":"string","title":"Note"},"author":{"type":"string","title":"Author"},"excluded_from_drawing":{"type":"boolean","title":"Excluded From Drawing"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","part_id","part_name","note","author","excluded_from_drawing"],"title":"TranscriptNoteRead"},"TranscriptPartIntentRead":{"properties":{"part_id":{"type":"string","format":"uuid","title":"Part Id"},"part_name":{"type":"string","title":"Part Name"},"intent_status":{"type":"string","title":"Intent Status"},"purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purpose"},"primary_function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Function"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment"},"critical_features":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Critical Features","default":[]},"mating_surfaces":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Mating Surfaces","default":[]},"load_paths":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Load Paths","default":[]},"tolerance_rationale":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Tolerance Rationale","default":[]},"performance_requirements":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Performance Requirements","default":[]},"free_text_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Free Text Notes"}},"type":"object","required":["part_id","part_name","intent_status"],"title":"TranscriptPartIntentRead"},"UncoveredFeature":{"properties":{"feature_id":{"type":"string","title":"Feature Id"},"feature_type":{"type":"string","title":"Feature Type"},"reason":{"type":"string","title":"Reason"}},"type":"object","required":["feature_id","feature_type","reason"],"title":"UncoveredFeature","description":"A detected feature the synthesized CamSpec did not address.\n\n``reason`` is a short machine token (e.g. ``\"no_synthesis_handler\"``,\n``\"missing_dimensions\"``, ``\"outside_v1_envelope\"``) the admin UI can\nmap to human copy."},"UnmatchedReplyRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"gmail_message_id":{"type":"string","title":"Gmail Message Id"},"gmail_thread_id":{"type":"string","title":"Gmail Thread Id"},"from_email":{"type":"string","title":"From Email"},"subject":{"type":"string","title":"Subject"},"snippet":{"type":"string","title":"Snippet"},"received_at":{"type":"string","format":"date-time","title":"Received At"},"reason":{"type":"string","title":"Reason"},"reassigned_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reassigned At"},"reassigned_to_project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reassigned To Project Id"},"reassigned_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reassigned By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","gmail_message_id","gmail_thread_id","from_email","subject","snippet","received_at","reason","reassigned_at","reassigned_to_project_id","reassigned_by","created_at","updated_at"],"title":"UnmatchedReplyRead","description":"One unmatched supplier reply, as shown in the admin triage queue."},"UnmatchedReplyReassignRequest":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"}},"type":"object","required":["project_id"],"title":"UnmatchedReplyReassignRequest","description":"Reassign body — link an unmatched reply to a project.\n\nProject-only: ``unmatched_replies`` has no supplier-contact column, so\nthe admin only picks the target project. The supplier identity is\nrecoverable from ``from_email`` once the reply is linked."},"UnreadCountResponse":{"properties":{"count":{"type":"integer","title":"Count"}},"type":"object","required":["count"],"title":"UnreadCountResponse"},"UnsubscribeSubmit":{"properties":{"token":{"type":"string","title":"Token"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},"type":"object","required":["token"],"title":"UnsubscribeSubmit"},"UpdateOrderPlacedAtRequest":{"properties":{"order_placed_at":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Order Placed At"}},"type":"object","title":"UpdateOrderPlacedAtRequest","description":"Admin request to set/clear a payment's order-placed override (D1).\n\nThe edit-anytime correction affordance for the TRUE order date on\non-behalf orders. The admin sends a calendar ``order_placed_at`` →\nstored at UTC noon as ``Payment.order_placed_at_override``;\n``None`` **CLEARS** the override (the order-placed clock reverts to the\nderived created_at/paid_at). Because ``derive_order_placed_at`` is the\nsingle chokepoint, a correction here propagates to every read consumer\n(admin list/detail, the customer's view, the sell-side ETA)."},"UserDashboardResponse":{"properties":{"recent_activity":{"items":{"$ref":"#/components/schemas/RecentActivityItem"},"type":"array","title":"Recent Activity","default":[]}},"type":"object","title":"UserDashboardResponse","description":"Response for the user-facing dashboard endpoint.\n\nContains a merged recent-activity feed scoped to the current user's\nprojects and quotes."},"UserPreferencesResponse":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"ollie_enabled":{"type":"boolean","title":"Ollie Enabled"},"ollie_proactivity":{"type":"string","enum":["active","minimal","off"],"title":"Ollie Proactivity"}},"type":"object","required":["user_id","ollie_enabled","ollie_proactivity"],"title":"UserPreferencesResponse","description":"Read model for per-user Ollie settings."},"UserPreferencesUpdate":{"properties":{"ollie_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ollie Enabled"},"ollie_proactivity":{"anyOf":[{"type":"string","enum":["active","minimal","off"]},{"type":"null"}],"title":"Ollie Proactivity"}},"type":"object","title":"UserPreferencesUpdate","description":"Partial-update payload for user preferences."},"UserProfileResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"status":{"$ref":"#/components/schemas/UserStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","email","first_name","last_name","status","created_at","updated_at"],"title":"UserProfileResponse","description":"Full user profile detail.\n\nThis is richer than ``schemas.auth.UserResponse`` — it includes\n``updated_at`` and is intended for dedicated profile endpoints\nrather than the lightweight auth context."},"UserProfileUpdate":{"properties":{"first_name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Last Name"},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Phone"},"company":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Company"}},"type":"object","title":"UserProfileUpdate","description":"Partial update payload for user profile fields.\n\nAll fields are optional; only supplied fields are applied.\nValidation constraints mirror the column limits on the ``User`` model."},"UserResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","email","first_name","last_name","status","created_at"],"title":"UserResponse","description":"Public representation of a customer user."},"UserStatus":{"type":"string","enum":["active","inactive","suspended"],"title":"UserStatus"},"UserSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"}},"type":"object","required":["id","email","first_name","last_name"],"title":"UserSummary","description":"Minimal user info for denormalized list views."},"ValidateMaterialRequest":{"properties":{"machining_process_id":{"type":"string","format":"uuid","title":"Machining Process Id"},"material_id":{"type":"string","format":"uuid","title":"Material Id"},"finishing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Finishing Id"}},"type":"object","required":["machining_process_id","material_id"],"title":"ValidateMaterialRequest","description":"Request to validate a process + material + finishing combination.\n\nUsed when the user selects manufacturing specs for a part.  The\nbackend checks the ``process_mappings`` table to confirm the\ncombination is supported before persisting the selection."},"ValidateMaterialResponse":{"properties":{"is_valid":{"type":"boolean","title":"Is Valid"},"message":{"type":"string","title":"Message","default":""}},"type":"object","required":["is_valid"],"title":"ValidateMaterialResponse","description":"Whether a process/material/finishing combination is valid.\n\n``is_valid`` is ``True`` when a matching ``ProcessMapping`` row\nexists with ``is_valid=True``.  ``message`` provides a\nhuman-readable explanation when the combination is not supported."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VendorRoutingOverride":{"properties":{"override_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Override Ids"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"triggered_by":{"type":"string","title":"Triggered By"}},"type":"object","required":["created_at","triggered_by"],"title":"VendorRoutingOverride","description":"An active override row joined onto the routing preview.\n\nSourced from the most recent ``AgentAction`` with\n``action_type=\"vendors_ranker_override\"`` and matching ``project_id``.\n``output_data`` is unpacked into ``override_ids`` + ``reason`` by the\nrouter; the timestamp is the AgentAction's ``created_at`` and the\n``triggered_by`` mirrors the same column on the audit row."},"VendorRoutingOverrideRequest":{"properties":{"supplier_contact_ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":5,"minItems":1,"title":"Supplier Contact Ids"},"reason":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Reason"}},"type":"object","required":["supplier_contact_ids"],"title":"VendorRoutingOverrideRequest","description":"Body for ``POST /admin/projects/{project_id}/vendor-routing/override``.\n\n``supplier_contact_ids`` is bounded to ``1..5`` entries — matches the\nlive agent's outbound batch ceiling. ``reason`` is free-form (max\n1000 chars) so admins can record why they overrode the ranker. Future\ncalibration work will mine these rationales for patterns the ranker\nformula misses."},"VendorRoutingPreviewResponse":{"properties":{"ranker_version":{"type":"string","title":"Ranker Version","default":"v2"},"top_n_applied":{"type":"integer","title":"Top N Applied","default":0},"suppliers":{"items":{"$ref":"#/components/schemas/VendorRoutingSupplierRow"},"type":"array","title":"Suppliers"},"active_override":{"anyOf":[{"$ref":"#/components/schemas/VendorRoutingOverride"},{"type":"null"}]}},"type":"object","title":"VendorRoutingPreviewResponse","description":"Response for ``GET /admin/projects/{project_id}/vendor-routing``.\n\n``ranker_version`` is a stable identifier for the response shape — kept\non the schema so existing admin clients don't break. ``top_n_applied``\nechoes the cap actually applied (matches the constant from\n``services.pricing_config_loader.DEFAULT_VENDORS_RANKER_TOP_N``)."},"VendorRoutingSupplierRow":{"properties":{"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"name":{"type":"string","title":"Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"score":{"type":"number","title":"Score"},"reasons":{"items":{"type":"string"},"type":"array","title":"Reasons"},"score_breakdown":{"additionalProperties":{"type":"number"},"type":"object","title":"Score Breakdown"},"admin_routing_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Routing Notes"},"trust_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trust Tier"}},"type":"object","required":["supplier_contact_id","name","score"],"title":"VendorRoutingSupplierRow","description":"One ranked candidate in the admin vendor-routing preview.\n\nMirrors :class:`app.agents.vendors.schemas.mcp.SelectSuppliersForProjectOutputRow`\nbut adds the supplier's display ``name`` and ``company`` so the admin can\nrecognise who they're routing to. **No ``email`` field** — the routing\npreview is intentionally a degraded surface (admins go to the supplier\ndetail page to see emails, and that access is audited there).\n\n``score_breakdown`` and ``trust_tier`` and ``reasons`` are surfaced for\ndiagnostic UX — admins inspect why a supplier ranked where it did before\ndeciding to override."},"VendorThreadStateListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"supplier_contact_id":{"type":"string","format":"uuid","title":"Supplier Contact Id"},"supplier_contact_name":{"type":"string","title":"Supplier Contact Name"},"supplier_contact_email":{"type":"string","title":"Supplier Contact Email"},"supplier_contact_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Contact Company"},"status":{"type":"string","title":"Status"},"last_intent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Intent"},"last_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Message At"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"latest_quote_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Quote Id"},"latest_quote_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Quote Total Cents"},"latest_quote_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Quote Currency"},"latest_quote_lead_time_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Quote Lead Time Days"},"latest_invoice_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Invoice Id"},"latest_invoice_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Invoice Total Cents"},"latest_invoice_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Invoice Currency"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"latest_quote_attachment_kinds":{"items":{"type":"string"},"type":"array","title":"Latest Quote Attachment Kinds"},"latest_quote_attachment_count":{"type":"integer","title":"Latest Quote Attachment Count","default":0},"latest_invoice_attachment_kinds":{"items":{"type":"string"},"type":"array","title":"Latest Invoice Attachment Kinds"},"latest_invoice_attachment_count":{"type":"integer","title":"Latest Invoice Attachment Count","default":0},"needs_human_review":{"type":"boolean","title":"Needs Human Review"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","supplier_contact_id","supplier_contact_name","supplier_contact_email","supplier_contact_company","status","last_intent","last_message_at","sent_at","latest_quote_id","latest_quote_total_cents","latest_quote_currency","latest_quote_lead_time_days","needs_human_review","created_at"],"title":"VendorThreadStateListItem","description":"One row in the project ``Supplier quotes`` tab.\n\nJoins :class:`VendorThreadState` + its :class:`SupplierContact` +\noptional latest :class:`SupplierQuote` summary in a single response.\nService uses ``selectinload`` + manual join to keep the round-trip\ncount to <= 2 (eng-review §4.1).\n\n``needs_human_review`` is ``False`` when no quote exists yet —\nThreadStates without a recorded quote can't have a HitL pending\nreview."},"ViewerCalloutAnswerRequest":{"properties":{"answer_text":{"type":"string","maxLength":500,"title":"Answer Text"}},"type":"object","required":["answer_text"],"title":"ViewerCalloutAnswerRequest","description":"User answers an intent_question callout from the 3D pin popover."},"ViewerCalloutPatch":{"properties":{"state":{"type":"string","enum":["acknowledged","dismissed"],"title":"State"}},"type":"object","required":["state"],"title":"ViewerCalloutPatch","description":"State transition request — acknowledge or dismiss a callout."},"ViewerCalloutRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"cad_file_version_id":{"type":"string","format":"uuid","title":"Cad File Version Id"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"callout_type":{"type":"string","title":"Callout Type"},"severity":{"type":"string","title":"Severity"},"title":{"type":"string","title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"},"actions":{"anyOf":[{"items":{"$ref":"#/components/schemas/CalloutAction"},"type":"array"},{"type":"null"}],"title":"Actions"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By"},"related_message_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Related Message Id"},"state":{"type":"string","title":"State"},"acknowledged_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Acknowledged At"},"dismissed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dismissed At"},"source_finding_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Finding Id"},"stakes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Stakes"},"intent_field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Intent Field"},"answer_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Text"},"answer_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","cad_file_version_id","feature_id","callout_type","severity","title","body","created_by","related_message_id","state","acknowledged_at","dismissed_at","source_finding_id","intent_field","answer_text","answer_status","created_at","updated_at"],"title":"ViewerCalloutRead","description":"Full viewer callout response."},"WaitlistEntryResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry"},"project_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Description"},"estimated_order_size":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated Order Size"},"referral_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referral Source"},"referral_source_other":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referral Source Other"},"status":{"type":"string","title":"Status"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"invite_sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Invite Sent At"},"invite_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Invite Expires At"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"reviewed_by_admin_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reviewed By Admin Id"},"converted_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Converted User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","email","first_name","last_name","status","created_at"],"title":"WaitlistEntryResponse","description":"Admin view of a waitlist entry."},"WaitlistJoinRequest":{"properties":{"email":{"type":"string","maxLength":255,"pattern":"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$","title":"Email"},"first_name":{"type":"string","maxLength":255,"minLength":1,"title":"First Name"},"last_name":{"type":"string","maxLength":255,"minLength":1,"title":"Last Name"},"company":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Company"},"industry":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Industry"},"project_description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Project Description"},"estimated_order_size":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Estimated Order Size"},"referral_source":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Referral Source"},"referral_source_other":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Referral Source Other"},"honeypot":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Honeypot"}},"type":"object","required":["email","first_name","last_name"],"title":"WaitlistJoinRequest","description":"Public waitlist signup form submission."},"WaitlistJoinResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"WaitlistJoinResponse","description":"Response after successful waitlist signup."},"WaitlistStatsResponse":{"properties":{"total":{"type":"integer","title":"Total"},"pending":{"type":"integer","title":"Pending"},"approved":{"type":"integer","title":"Approved"},"denied":{"type":"integer","title":"Denied"},"converted":{"type":"integer","title":"Converted"}},"type":"object","required":["total","pending","approved","denied","converted"],"title":"WaitlistStatsResponse","description":"Aggregate waitlist statistics for the admin dashboard."},"WaitlistUpdateRequest":{"properties":{"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","title":"WaitlistUpdateRequest","description":"Admin update to a waitlist entry (notes, deny).\n\nOnly ``\"denied\"`` is accepted via PATCH; approval has its own\ndedicated endpoint that also triggers the invite email."},"WelcomeDeckResponse":{"properties":{"welcome_deck_dismissed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Welcome Deck Dismissed At"}},"type":"object","required":["welcome_deck_dismissed_at"],"title":"WelcomeDeckResponse","description":"Welcome card deck dismissal state for the authenticated user."},"WeldCreate":{"properties":{"edge_id":{"type":"string","minLength":3,"title":"Edge Id","description":"Topology edge ID (e.g. 'edge_7') — looked up in the topology sidecar JSON."},"weld_type":{"type":"string","title":"Weld Type","description":"One of WELD_TYPES (fillet, bevel, v_groove, plug, spot)."},"size_mm":{"type":"number","exclusiveMinimum":0.0,"title":"Size Mm","description":"Weld size / fillet leg length in mm."},"length_mm":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Length Mm","description":"Seam length; None = full edge."},"process":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Process","description":"One of WELD_PROCESSES (TIG, MIG, spot, laser, arc) or null."},"side":{"type":"string","title":"Side","description":"ISO 2553 reference-line side (arrow, other, both).","default":"arrow"},"all_around":{"type":"boolean","title":"All Around","description":"Weld wraps the full perimeter (○ symbol).","default":false},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["edge_id","weld_type","size_mm"],"title":"WeldCreate","description":"Payload for ``POST /parts/{part_id}/welds``."},"WeldRead":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"part_id":{"type":"string","format":"uuid","title":"Part Id"},"cad_file_version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cad File Version Id"},"edge_id":{"type":"string","title":"Edge Id"},"weld_type":{"type":"string","title":"Weld Type"},"size_mm":{"type":"number","title":"Size Mm"},"length_mm":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Length Mm"},"process":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Process"},"side":{"type":"string","title":"Side"},"all_around":{"type":"boolean","title":"All Around"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"state":{"type":"string","title":"State"},"source":{"type":"string","title":"Source"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"is_process_mismatch":{"type":"boolean","title":"Is Process Mismatch","default":false}},"type":"object","required":["id","part_id","cad_file_version_id","edge_id","weld_type","size_mm","length_mm","process","side","all_around","notes","label","state","source","created_by","created_at","updated_at"],"title":"WeldRead","description":"Flattened weld row — built by the service from an OutcomeEvent.\n\nNot an ORM passthrough: the source row is an ``OutcomeEvent`` with\n``data = {weld_type, size_mm, ...}``; this projection flattens that\npayload into first-class fields and adds the computed\n``is_process_mismatch`` flag."},"WeldSummary":{"properties":{"weld_id":{"type":"string","format":"uuid","title":"Weld Id"},"edge_id":{"type":"string","title":"Edge Id"},"weld_type":{"type":"string","title":"Weld Type"},"size_mm":{"type":"number","title":"Size Mm"},"length_mm":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Length Mm"},"process":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Process"},"side":{"type":"string","title":"Side","default":"arrow"},"all_around":{"type":"boolean","title":"All Around","default":false},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"label":{"type":"string","title":"Label"},"state":{"type":"string","title":"State"},"source":{"type":"string","title":"Source"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["weld_id","edge_id","weld_type","size_mm","label","state","source","created_at"],"title":"WeldSummary"},"WeldUpdate":{"properties":{"weld_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Weld Type"},"size_mm":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Size Mm"},"length_mm":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Length Mm"},"process":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Process"},"side":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Side"},"all_around":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"All Around"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"WeldUpdate","description":"Payload for ``PATCH /welds/{weld_id}``. All fields optional."},"app__schemas__admin__BusinessProfileResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"company_name":{"type":"string","title":"Company Name"},"tax_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Id"},"billing_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Email"},"billing_address":{"type":"string","title":"Billing Address"},"shipping_address":{"type":"string","title":"Shipping Address"},"payment_terms":{"type":"string","title":"Payment Terms"},"credit_limit":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Credit Limit"},"is_approved_for_po":{"type":"boolean","title":"Is Approved For Po"},"po_approval_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Po Approval Date"},"approved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approved By"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","company_name","billing_address","shipping_address","payment_terms","is_approved_for_po"],"title":"BusinessProfileResponse","description":"Business profile info for admin user detail."},"app__schemas__admin__CadVersionSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version_number":{"type":"integer","title":"Version Number"},"is_latest":{"type":"boolean","title":"Is Latest"},"file_name":{"type":"string","title":"File Name"},"original_file_name":{"type":"string","title":"Original File Name"},"file_format":{"type":"string","title":"File Format"},"file_size":{"type":"integer","title":"File Size"},"status":{"type":"string","title":"Status"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"dfm_issues":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Dfm Issues"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"width":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Height"},"depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth"},"dimension_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dimension Unit"},"volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Volume"},"surface_area":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Surface Area"}},"type":"object","required":["id","version_number","is_latest","file_name","original_file_name","file_format","file_size","status","created_at"],"title":"CadVersionSummary","description":"Minimal CAD version info for admin part detail."},"app__schemas__business_profile__BusinessProfileResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"company_name":{"type":"string","title":"Company Name"},"tax_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Id"},"billing_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Email"},"billing_address":{"type":"string","title":"Billing Address"},"shipping_address":{"type":"string","title":"Shipping Address"},"payment_terms":{"type":"string","title":"Payment Terms"},"credit_limit":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Credit Limit"},"is_tax_exempt":{"type":"boolean","title":"Is Tax Exempt","default":false},"tax_exempt_cert_r2_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Exempt Cert R2 Key"},"is_approved_for_po":{"type":"boolean","title":"Is Approved For Po"},"po_approval_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Po Approval Date"},"approved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approved By"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","user_id","company_name","billing_address","shipping_address","payment_terms","is_approved_for_po","created_at","updated_at"],"title":"BusinessProfileResponse","description":"User-facing business profile response."},"app__schemas__part__CadVersionSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version_number":{"type":"integer","title":"Version Number"},"is_latest":{"type":"boolean","title":"Is Latest"},"file_name":{"type":"string","title":"File Name"},"original_file_name":{"type":"string","title":"Original File Name"},"file_format":{"type":"string","title":"File Format"},"file_size":{"type":"integer","title":"File Size"},"status":{"type":"string","title":"Status"},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step"},"failure_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Reason"},"latest_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Latest Run Id"},"analysis_milestone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Milestone"},"analysis_authority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Authority"},"analysis_seq":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Seq"},"preliminary_price":{"anyOf":[{"$ref":"#/components/schemas/PreliminaryPriceResponse"},{"type":"null"}]},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"dfm_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dfm Score"},"unit_price_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Price Mid"},"has_ai_synthesis":{"type":"boolean","title":"Has Ai Synthesis","default":false},"analysis_status":{"$ref":"#/components/schemas/AnalysisStatus","default":"not_started"},"analysis_error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Error Message"},"analysis_failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Failed Step"},"analysis_last_transition_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Analysis Last Transition At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","version_number","is_latest","file_name","original_file_name","file_format","file_size","status","created_at","updated_at"],"title":"CadVersionSummary","description":"Minimal CAD version info embedded in a part detail response.\n\nExposes processing status and basic file metadata.  Geometry\nanalysis results are intentionally omitted here -- they belong\nto a dedicated CAD version detail schema.\nThe thumbnail_url is the sole exception, included so the\npart card can display a thumbnail without a separate API call."}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"token"}}}}}}