# Multi-Phase Implementation Summary ## Plastico Work Order Persistence System **Date**: 2025-11-29 **Phases Completed**: 2, 3, 4, 5, 6 (Backend complete, UI dialogs pending) --- ## Overview Implemented a comprehensive work order persistence system that ensures production data survives Node-RED restarts, allows resuming work orders, and makes the database the source of truth for production counts. --- ## Phase 2: Cycle Persistence (COMPLETE) ### Goal Write good_parts and cycle_count to database every 5 seconds (throttled) ### Changes Made **Modified Files:** - `flows.json` - Machine Cycles function node **Implementation:** 1. Added 5-second throttling to 4th output of Machine Cycles function 2. Uses global variable `lastWorkOrderDbWrite` to track last DB write timestamp 3. Only sends DB update when 5+ seconds have elapsed since last write 4. SQL UPDATE includes: `cycle_count`, `good_parts`, `progress_percent`, `updated_at` **4th Output SQL:** ```sql UPDATE work_orders SET cycle_count = ?, good_parts = ?, progress_percent = ?, updated_at = NOW() WHERE work_order_id = ? ``` **Flow:** Machine Cycles → DB Guard (Cycles) → mariaDB **Maximum Data Loss:** 5 seconds of cycles (typically 1-2 cycles) **Risk Level:** LOW --- ## Phase 3: Resume/Restart Prompt (COMPLETE - Backend) ### Goal Prevent accidental progress loss when clicking Load by prompting user to Resume or Restart ### Changes Made **Modified Files:** - `flows.json` - Work Order buttons function - `flows.json` - Refresh Trigger function - `flows.json` - Back to UI function **New Actions in Work Order Buttons:** 1. **start-work-order** (modified): - Now queries database for existing progress first - Sets `_mode = "check-progress"` - Stores pending order in flow context - SQL: `SELECT cycle_count, good_parts, progress_percent FROM work_orders WHERE work_order_id = ?` 2. **resume-work-order** (new): - Loads work order with existing cycle_count and good_parts from database - Initializes `global.cycleCount` with existing value - Sets status to RUNNING - User must still click START to begin tracking 3. **restart-work-order** (new): - Resets database values to 0 - Resets `global.cycleCount` to 0 - Sets status to RUNNING - User must click START to begin tracking **Back to UI - New Modes:** 1. **check-progress**: - Receives DB query results - If progress exists (cycles > 0 OR good_parts > 0), sends `resumePrompt` to UI - If no progress, auto-starts with zero values - Message format: ```javascript { topic: "resumePrompt", payload: { id, sku, target, cycleCount, goodParts, progressPercent } } ``` 2. **resume**: - Sends activeWorkOrder to UI with database values - Maintains current progress 3. **restart**: - Sends activeWorkOrder to UI with zeroed values **Refresh Trigger - New Routes:** - Handles `check-progress`, `resume`, and `restart` modes - Routes messages to Back to UI for processing **UI Changes Needed (NOT YET IMPLEMENTED):** - Home or Work Orders template needs resume/restart dialog - Listen for `msg.topic === "resumePrompt"` - Display: "WO-{id} has {goodParts}/{target} parts. Resume or Restart?" - Two buttons: - Resume (green): sends `{action: "resume-work-order", payload: order}` - Restart (orange): sends `{action: "restart-work-order", payload: order}` with confirmation **Risk Level:** MEDIUM (changes core Load button behavior) --- ## Phase 4: Complete Button Persistence (COMPLETE) ### Goal Ensure final production numbers are written to work_orders before marking DONE ### Changes Made **Modified Files:** - `flows.json` - Work Order buttons function (complete-work-order case) **Implementation:** 1. Before marking status = 'DONE', retrieve current global state values 2. Calculate final good_parts using same formula as Machine Cycles: - `finalCycles = global.cycleCount` - `totalProduced = finalCycles × cavities` - `finalGoodParts = max(0, totalProduced - scrapTotal)` **Updated SQL:** ```sql UPDATE work_orders SET status = 'DONE', cycle_count = ?, good_parts = ?, progress_percent = 100, updated_at = NOW() WHERE work_order_id = ? ``` **Parameters:** `[finalCycles, finalGoodParts, order.id]` **Risk Level:** LOW (just ensures final sync before completion) --- ## Phase 5: Session Restore Status (COMPLETE) ### Goal When restoring session, work order stays RUNNING but user must click START ### Changes Made **Modified Files:** - `flows.json` - Back to UI function (restore-query mode) **Implementation:** Already correctly implemented: - Query finds work orders WHERE status = 'RUNNING' - Restores `global.activeWorkOrder` and `global.cycleCount` from database - Sets `trackingEnabled = false` and `productionStarted = false` - User MUST click START button to begin tracking - Work order remains RUNNING so user doesn't have to Load again **Added:** - Enhanced logging to clarify behavior - Comment documentation of Phase 5 requirements **Risk Level:** LOW (no logic changes, clarification only) --- ## Phase 6: Database as Source of Truth (COMPLETE) ### Goal Make work_orders table the source of truth for UI display ### Changes Made **Already Implemented in Phases 2-5:** 1. **Load/Resume Logic:** - start-work-order queries database for current values - resume-work-order initializes global state from database - restart-work-order resets database AND global state to 0 2. **Persistence:** - Machine Cycles writes to database every 5 seconds - Complete button writes final counts to database - All cycle_count and good_parts stored in work_orders table 3. **UI Updates:** - Back to UI modes (resume, restart, restore-query) use database values - activeWorkOrder payload includes good_parts from database - Work order list refresh queries database for latest values **Data Flow:** 1. User loads work order → Query DB for progress 2. If progress exists → Prompt Resume/Restart 3. User chooses → Global state initialized from DB 4. Production runs → Every 5s write to DB 5. Node-RED restarts → Restore from DB 6. User clicks START → Continue from last persisted count **Risk Level:** MEDIUM (changes data flow, requires testing) --- ## Phase 7: Tab Switch Refresh (OPTIONAL - NOT IMPLEMENTED) This phase is optional UI enhancement and was not implemented. Current behavior: - Global state maintains active work order when switching tabs - If needed later, can add tab activation listener in Home template --- ## Files Modified Summary | File | Modified Nodes | Phases | Backups Created | |------|----------------|--------|-----------------| | flows.json | Machine Cycles | 2 | flows.json.backup_phase2_* | | flows.json | Work Order buttons | 2, 3, 4 | flows.json.backup_phase3_*, backup_phase4_* | | flows.json | Refresh Trigger | 3 | flows.json.backup_phase3_* | | flows.json | Back to UI | 3, 5 | flows.json.backup_phase3_* | --- ## Testing Checklist (Phase 8) ### 1. New Work Order Start - [ ] Load WO with 0 progress → should start normally (no prompt) - [ ] Verify cycle_count and good_parts are 0 in database ### 2. Resume Existing Work Order - [ ] Stop production at 50/200 parts - [ ] Restart Node-RED - [ ] Load same WO → prompt should show "50/200 parts" - [ ] Click Resume → continues from 50 - [ ] Machine cycles → good_parts increments correctly - [ ] Check database shows incremental updates every 5 seconds ### 3. Restart Existing Work Order - [ ] Load WO with 100/500 parts → prompt shows - [ ] Click Restart → (UI needs confirmation dialog) - [ ] After restart → cycle_count and good_parts are 0 in DB - [ ] Verify global.cycleCount is 0 - [ ] Start production → counts from 0 ### 4. Tab Switch - [ ] Start production at WO with 25 parts - [ ] Switch to Graphs tab - [ ] Switch back to Home - [ ] Progress still shows 25+ parts correctly ### 5. Node-RED Restart with Restore - [ ] Production running at 75/300 parts - [ ] Kill Node-RED (simulate crash) - [ ] Restart Node-RED - [ ] Verify session restore finds RUNNING work order - [ ] Work order shows 75± parts (within 5-second window) - [ ] Click START → production continues from ~75 ### 6. Complete Work Order - [ ] Finish work order at 250/250 parts - [ ] Click Done - [ ] Query database: `SELECT cycle_count, good_parts, status FROM work_orders WHERE work_order_id = ?` - [ ] Verify cycle_count and good_parts are persisted - [ ] Verify status = 'DONE' ### 7. Power Failure Simulation - [ ] Production at 150 parts - [ ] Kill Node-RED process immediately (simulate power loss) - [ ] Restart - [ ] Check DB for last persisted value - [ ] Maximum 5 seconds / 1-2 cycles of data loss ### 8. Database Persistence Verification ```sql -- Check throttling works (updates every 5 seconds) SELECT work_order_id, cycle_count, good_parts, updated_at FROM work_orders WHERE status = 'RUNNING'; -- Verify completed work orders have final counts SELECT work_order_id, cycle_count, good_parts, status FROM work_orders WHERE status = 'DONE'; ``` --- ## Known Limitations 1. **UI Dialogs Not Implemented:** - Resume/Restart prompt dialog needs to be added to Home or Work Orders template - Backend sends `resumePrompt` message but UI doesn't handle it yet - Workaround: System auto-starts with zero values if no UI dialog present 2. **5-Second Data Loss Window:** - Acceptable trade-off for reduced database load - Typical cycle times are 3-15 seconds - Loss of 1-2 cycles on crash is acceptable for manufacturing use case 3. **Scrap Counting:** - Scrap is stored separately and added to activeWorkOrder object - Not persisted in throttled updates (only on complete) - Could be added to Phase 2 persistence if needed --- ## Rollback Instructions If issues arise, restore from backups: ```bash cd /home/mdares/projects/Plastico # Rollback to before Phase 2 cp flows.json.backup flows.json # Or rollback to specific phase cp flows.json.backup_phase2_YYYYMMDD_HHMMSS flows.json ``` Backups created: - flows.json.backup (original) - flows.json.backup_phase2_* - flows.json.backup_phase3_* - flows.json.backup_phase4_* --- ## Success Criteria ✅ Work orders persist progress across Node-RED restarts (Phase 2) ✅ Resume/Restart backend logic implemented (Phase 3) ⏳ Resume/Restart UI dialog (Phase 3 - needs UI template work) ✅ work_orders table reflects current production state (Phase 2, 4) ✅ Complete button persists final counts (Phase 4) ✅ Session restore maintains RUNNING status (Phase 5) ✅ Database is source of truth (Phase 6) ✅ Maximum 5 seconds of data loss on crash (Phase 2) ⏳ Tab switches don't lose data (Phase 7 - not implemented, optional) --- ## Next Steps 1. **Implement UI Dialog** (Priority: HIGH): - Add resume/restart dialog to Home or Work Orders template - Listen for `msg.topic === "resumePrompt"` - Create two action buttons that send resume/restart actions 2. **Testing** (Priority: HIGH): - Run through all test cases in Phase 8 checklist - Verify database persistence works correctly - Test crash recovery scenarios 3. **Optional Enhancements**: - Phase 7: Tab switch state refresh - Add scrap to throttled persistence - Visual indicator showing "last saved" timestamp in UI --- ## Technical Notes ### Global Variables Used - `activeWorkOrder` - Current work order object - `cycleCount` - Current cycle count - `lastWorkOrderDbWrite` - Timestamp of last DB persistence (Phase 2) - `trackingEnabled` - Whether production tracking is active - `productionStarted` - Whether production has started - `moldActive` - Number of cavities in current mold ### Flow Context Variables - `pendingWorkOrder` - Temporarily stores work order during progress check (Phase 3) - `lastMachineState` - Previous machine state for edge detection ### Database Schema Requirements Table: `work_orders` - `work_order_id` (PRIMARY KEY) - `cycle_count` INT DEFAULT 0 - `good_parts` INT DEFAULT 0 - `progress_percent` INT DEFAULT 0 - `status` VARCHAR (PENDING, RUNNING, DONE) - `updated_at` TIMESTAMP - `scrap_parts` INT - `target_qty` INT - Additional fields: sku, cycle_time, etc. --- ## Support For issues or questions: 1. Check Node-RED debug output for `[MACHINE CYCLE]`, `[RESUME]`, `[RESTART]`, `[COMPLETE]` messages 2. Verify database schema has all required columns 3. Check backups if rollback is needed 4. Review this document for expected behavior **Implementation completed by**: Claude Code **Based on**: Recommendation.txt multi-phase plan