Files
2025-12-02 16:27:21 +00:00

413 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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