feat: implement SavePump/SaveAlarms, fix config round-trip bugs, redesign PDF reports
Config system fixes: - Implement SavePump() — full XML serialization with insert/update by pump ID - Add CanBusParameter.ToPumpXml() for legacy P1-P6 pump param format - Fix LastRotationDirection never loaded in LoadSettings() - Add SaveAlarms() to ConfigurationService and IConfigurationService - Remove dead fields AppSettings.Clients and AppSettings.PumpIds PDF report redesign: - Professional layout with charts, verdict badges, and tolerance bands - Add ReportChartRenderer (SVG) and ReportTheme styling constants - Embed default_logo.png as fallback report logo Documentation: - Add gap analysis docs (config validation, ford unlock, missing features) - Update CLAUDE.md architecture, known gaps, and debt tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
117
docs/gap-missing-features.md
Normal file
117
docs/gap-missing-features.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Gap: Missing Features
|
||||
|
||||
## 1. Localization System (HIGH)
|
||||
|
||||
### Problem
|
||||
The old app supported runtime Spanish/English switching via `R.LoadLanguage()` which swapped WPF `ResourceDictionary` files (`StringResources.xaml` for Spanish, `StringResourcesEN.xaml` for English). The new app has `AppSettings.Language` ("ESP"/"ENG") persisted but NOT used — all UI strings are hardcoded in English.
|
||||
|
||||
### Implementation approach
|
||||
1. Create `Resources/StringResources.xaml` (Spanish) and `Resources/StringResources.en.xaml` (English) with keyed `sys:String` entries
|
||||
2. Reference strings in XAML via `{DynamicResource key}` (not `StaticResource` — dynamic allows runtime swap)
|
||||
3. Add `LanguageService` or extension method that merges the correct dictionary into `Application.Current.Resources`
|
||||
4. Wire language toggle to `AppSettings.Language` change
|
||||
5. Default resource dictionary should be Spanish (the primary user base)
|
||||
|
||||
### Scope
|
||||
All user-facing text: labels, button text, dialog messages, status messages, report text, error messages. Roughly 200-300 strings.
|
||||
|
||||
## 2. User Credential Encryption (HIGH)
|
||||
|
||||
### Problem
|
||||
Users stored as plaintext `user:password` pairs in `config.xml`. Default is `admin:admin`. Old system used AES-256 (Rijndael CBC, PBKDF2 1000 iterations) via `Encrypter.cs`.
|
||||
|
||||
### Recommended approach
|
||||
Don't re-implement the old Rijndael scheme (it used obsolete primitives and weak iteration count). Instead:
|
||||
1. **Hash passwords** with `Rfc2898DeriveBytes` using HMAC-SHA256, 600,000 iterations, random 16-byte salt
|
||||
2. Store as `user:salt:hash` in config.xml
|
||||
3. `ValidateUser()` computes hash of input password with stored salt and compares
|
||||
4. Migration: on first load of old-format `user:password` entries, hash them and rewrite
|
||||
|
||||
This is more secure than the old encrypted-but-reversible approach. Passwords become irreversible.
|
||||
|
||||
### Files to modify
|
||||
- `Models/BenchConfiguration.cs` — change `Users` property format
|
||||
- `Services/Impl/ConfigurationService.cs` — `ValidateUser()`, `GetUsers()`, `UpdateUsers()`, `SaveSettings()`
|
||||
|
||||
## 3. KlineIDs Auto-Mapping (MEDIUM)
|
||||
|
||||
### Problem
|
||||
Old system remembered K-Line ID → pump ID associations via `Settings.Default.KlineIDs` (comma-separated `klineID:pumpID` string). When a pump was connected and identified via K-Line, the system could auto-select it next time. New system has no equivalent.
|
||||
|
||||
### Implementation
|
||||
1. Add `Dictionary<string, string> KlineIdMap` to `AppSettings`
|
||||
2. Persist as `<KlineIDs>kline1:pump1,kline2:pump2</KlineIDs>` in config.xml
|
||||
3. In `KwpService` or `PumpIdentificationViewModel`: after successful K-Line read, save the mapping
|
||||
4. On pump connection: look up K-Line ID in map, auto-select pump if found
|
||||
|
||||
## 4. Test Phase Timer/Countdown Display (MEDIUM)
|
||||
|
||||
### Problem
|
||||
During test execution, conditioning and measurement phases have timed durations (e.g., 10 sec conditioning, 30 sec measurement). The old system showed a visual countdown. The new system fires `VerboseMessage` events with text like "Conditioning: 8s remaining" but there's no dedicated countdown UI.
|
||||
|
||||
### Implementation
|
||||
- Add countdown properties to `TestDisplayViewModel`: `RemainingSeconds`, `PhaseProgress` (0-1), `PhaseName`
|
||||
- Fire `PhaseTimerTick` event from `BenchService` with remaining seconds
|
||||
- Display as a circular progress indicator or large countdown text in `TestDisplayView`
|
||||
|
||||
## 5. QOver Zero-Flow Safety Check (HIGH — Safety)
|
||||
|
||||
### Problem
|
||||
The old system had a safety check: if `QOver == 0` while RPM > 300 and oil pump is on, trigger emergency stop (leak/blockage detection). This is completely absent from the new codebase.
|
||||
|
||||
### Implementation
|
||||
Add to `BenchService` or the ViewModel's bench monitoring loop:
|
||||
```csharp
|
||||
if (qOverValue == 0 && benchRpm > 300 && IsRelayOn(RelayNames.OilPump))
|
||||
{
|
||||
EmergencyStop();
|
||||
_log.Error(LogId, "QOver zero-flow safety triggered: oil flow blocked while motor running");
|
||||
}
|
||||
```
|
||||
Debounce for 2-3 seconds to avoid false positives during startup transients.
|
||||
|
||||
## 6. Alarm Bit Recording During Tests (HIGH)
|
||||
|
||||
### Problem
|
||||
`PhaseDefinition` has `ErrorBits` list and `RecordErrorBit(int bit)` method, but no code in `BenchService` ever calls it. The old system tracked which alarm bits fired during each test phase for inclusion in the report.
|
||||
|
||||
### Implementation
|
||||
In `BenchService.MeasurePhaseAsync()`, subscribe to alarm parameter changes. When an alarm bit transitions to active during a measurement phase, call `phase.RecordErrorBit(bit)`. The error bits are already rendered in the PDF report (PdfService checks `phase.ErrorBits`).
|
||||
|
||||
## 7. Per-Sample Real-Time UI Callback (MEDIUM)
|
||||
|
||||
### Problem
|
||||
Old system fired `ITestParameterListener.OnValueUpdate` for every measurement sample, enabling live chart updates during test execution. New system silently collects samples with no per-sample event.
|
||||
|
||||
### Implementation
|
||||
Add an event to `IBenchService`:
|
||||
```csharp
|
||||
event Action<string, double, double>? MeasurementSampled; // paramName, value, timestamp
|
||||
```
|
||||
Fire in `MeasurePhaseAsync` after each sample. ViewModel subscribes to update live charts.
|
||||
|
||||
## 8. Pump Parameter Zeroing Between Phases (MEDIUM)
|
||||
|
||||
### Problem
|
||||
Old system called `StopPump()` between phases, which zeroed ME/FBKW/PreIn values. New system calls `SetRpm(0)` but does NOT zero pump injection parameters. This means the pump may continue injecting fuel between phases at the previous phase's setpoint.
|
||||
|
||||
### Implementation
|
||||
Add a `StopPumpParameters()` method to `BenchService` that sets ME, FBKW, and PreIn to 0 and sends the CAN frame. Call it at the end of each phase (currently line 776 in BenchService.cs — after `SetRpm(0)`).
|
||||
|
||||
## 9. PDF Report Observations Section (LOW)
|
||||
|
||||
### Problem
|
||||
Old report had an "Observaciones" free-text section at the bottom. New `IPdfService.GenerateReport()` has no observations parameter and no observations rendering.
|
||||
|
||||
### Implementation
|
||||
1. Add `string? observations` parameter to `IPdfService.GenerateReport()`
|
||||
2. Add a text section at the bottom of the PDF body in `PdfService`
|
||||
3. Add an observations text box to `ReportDialog`/`ReportViewModel`
|
||||
|
||||
## 10. PDF Auto-Open After Generation (LOW)
|
||||
|
||||
### Problem
|
||||
Old code called `Process.Start(filePath)` to open the generated PDF. New code returns the path but doesn't open it.
|
||||
|
||||
### Implementation
|
||||
After `GenerateReport()` returns the path, call `Process.Start(new ProcessStartInfo(path) { UseShellExecute = true })` in the ViewModel.
|
||||
Reference in New Issue
Block a user