# Consumer migration and maintenance handoff

Pilot Plant now loads categories, equipment, components, summaries and reports through /api/v1. Form targets use server IDs and versioned edits. Name changes and photo uploads are separate confirmed mutations. Failed requests retain form input and show Indonesian errors; stale metadata can be refreshed before retry. No IndexedDB data is imported, rewritten, or deleted by the new page. The old storage helper is retained but is no longer mounted by Pilot Plant.

ADMIN/SUPERVISOR manage master data/photos and review. TECHNICIAN can submit reports, and VIEWER reads only. The API enforces every permission independently of UI visibility. Successful report/review/photo/name mutations invalidate mounted hierarchy, summary, queue and Work Order reads. Request cleanup ignores stale responses after navigation.

Persisted corrective work has its own routes:
- /maintenance/pilot-plant: released PILOT_PLANT/CORRECTIVE Work Orders with server pagination.
- /maintenance/pilot-plant/:id: persisted detail, linked from an accepted report.

The existing /maintenance page remains explicitly labelled as local demo data and links to the server view. Persisted records never enter editable demo arrays. No status, assignment, cancellation, reopening, parts, or stock-consumption mutation is exposed in the server view.

Accepted reports remain active in NOTED counts. Future Maintenance execution must synchronize IN_PROGRESS to IN_REPAIR and resolved COMPLETED to RESOLVED; CANCELLED must retain the one lifetime WO link and leave the report ACCEPTED/unresolved. Reopening must reuse that WO. Accept is not a hidden reopen operation.

## Verification commands

- pnpm typecheck
- pnpm build
- pnpm test
- pnpm --filter express-api-starter-ts test:pilot-plant
- pnpm --filter express-api-starter-ts test:docs

The real database runner creates and removes only random isolated databases. Regular tests intentionally skip MySQL and browser cases without that guarded environment.

For the browser flow, build the isolated same-origin frontend from the monorepo root:
`node apps/app/test/build-pilot-browser.mjs`

Then run:
`pnpm --filter express-api-starter-ts test:pilot-browser`

The browser runner uses a temporary Chrome profile, test-only cookies/users and a loopback server backed by an isolated database. PILOT_CHROME can name an installed Chrome-compatible executable. It checks a technician report, supervisor/admin review, persisted read-only WO and retention of a sentinel IndexedDB record. Its frontend build is separate from production dist and does not edit .env.

Current session limitation: Chrome starts but cannot initialize its renderer under the available Windows permissions (GPU access failures and Page.enable timeout). This browser acceptance has not passed; frontend interaction verification and integrated task 6.1 remain open. Run in a session where the local browser can start normally before release.

## Release gate

The application database has not been migrated by this implementation. Configure and verify a persistent MEDIA_ROOT, run read-only migration preflight, take paired database/media backups, rehearse restoration, and deliver a compatible frontend/backend release together. See prisma/media-storage.md for storage, cleanup and rollback. Preserve schema/history on rollback; do not run older writers unaware of ACCEPTED or the unique report/WO link.
