# Pilot Plant category, equipment, and item contract

Pilot Plant uses separate Category, Equipment, and Item models. Inventory Part is a separate domain. Item has no spare-part assignment relation. PartAssignment still links inventory parts to equipment.

Canonical endpoints (prefix /api/v1):
- GET/POST /pilot-plant/categories
- PATCH /pilot-plant/categories/:id
- GET/POST /pilot-plant/categories/:id/equipment
- GET/PATCH /pilot-plant/equipment/:id
- GET/POST /pilot-plant/equipment/:id/items
- GET/PATCH /pilot-plant/items/:id
- GET/POST/DELETE /pilot-plant/{categories|equipment|items}/:id/photo
- GET/POST /pilot-plant/items/:id/damage-reports
- GET /pilot-plant/summary

The former /plant-units and /assets endpoints are replaced. Equipment IDs cannot be used on item endpoints, or vice versa (404). Category filters use categoryId. Shared DTO names use Category and PilotEntity; entity levels are EQUIPMENT and ITEM. Report/work-order target identifiers use pilotEntityId. Swagger annotations document every operation.

## Migration

Run from the workspace root:

    pnpm --filter express-api-starter-ts prisma:migrate:deploy
    pnpm --filter express-api-starter-ts prisma:generate

Migration 20261013000300_detach_item_inventory removes PartAssignment.itemId and Item.parts. Before removal, existing item assignments are saved as AuditLog snapshots with action DETACH_ITEM_INVENTORY, including itemId, equipmentId, partId, and requiredQuantity. Item-only assignment rows are removed. Any assignment already linked to equipment keeps its equipment link. No item or inventory part is deleted, and no assignment is silently transferred to the parent equipment.

The API and frontend must be updated together. Name and photo editing uses one form and one Save button; the API still uses separate versioned requests. If the name succeeds and photo fails, the form retains the saved version and pending photo for retry.
