Skip to content

feat(docker): add ZFS collector to omnibus image#82

Merged
Starosdev merged 1 commit intodevelopfrom
feature/SCR-75-zfs-collector-omnibus
Jan 17, 2026
Merged

feat(docker): add ZFS collector to omnibus image#82
Starosdev merged 1 commit intodevelopfrom
feature/SCR-75-zfs-collector-omnibus

Conversation

@Starosdev
Copy link
Owner

  • Add zfsutils-linux package (requires contrib repo)
  • Copy scrutiny-collector-zfs binary to /opt/scrutiny/bin/
  • Add ZFS cron configuration (opt-in via COLLECTOR_ZFS_CRON_SCHEDULE)
  • Add collector-zfs-once service for optional startup collection

Closes #75

Summary

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • CI/CD or infrastructure change

Related Issues

Changes Made

Testing

  • I have tested this locally
  • I have added/updated tests that prove my fix/feature works
  • All existing tests pass

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my code
  • I have commented my code where necessary (particularly complex areas)
  • I have updated the documentation if needed
  • My changes generate no new warnings
  • No console.log, debug statements, or commented-out code

Screenshots (if applicable)

Additional Notes

- Add zfsutils-linux package (requires contrib repo)
- Copy scrutiny-collector-zfs binary to /opt/scrutiny/bin/
- Add ZFS cron configuration (opt-in via COLLECTOR_ZFS_CRON_SCHEDULE)
- Add collector-zfs-once service for optional startup collection

Closes #75
@Starosdev Starosdev merged commit 9ed219d into develop Jan 17, 2026
13 checks passed
Starosdev added a commit that referenced this pull request Jan 19, 2026
* feat(dashboard): add more sorting options (#80)

Add ascending/descending sort options for dashboard devices:
- Status (Failed First / Passed First)
- Title (A-Z / Z-A)
- Age (Oldest First / Newest First)
- Capacity (Largest First / Smallest First)
- Temperature (Hottest First / Coolest First)

Includes backward compatibility for legacy sort values.

Closes #72

* Fix/scr 71 tooltip cutoff (#81)

* feat(docker): add ZFS collector to omnibus image (#82)

* fix(frontend): prevent tooltip cutoff on sparkline charts

Add CSS to temporarily disable overflow clipping on the SMART table
wrapper when hovering over charts, allowing ApexCharts tooltips to
display fully without being clipped at cell boundaries.

Uses CSS :has() selector to detect when a tooltip is active and
removes overflow restriction on the parent container.

Fixes #71

* fix(frontend): use ApexCharts native events for tooltip overflow fix

Replace CSS :has() selector approach with ApexCharts native mouseMove
and mouseLeave events to toggle overflow on the table wrapper. This
ensures reliable tooltip display by disabling overflow clipping when
the user interacts with sparkline charts.

Fixes #71

* fix(frontend): add debounce to sparkline hover to prevent flickering

When toggling overflow on the table wrapper, the DOM reflow can trigger
mouseLeave events, causing the tooltip to flicker. Adding a 150ms
debounce on mouseLeave prevents the class from being removed immediately,
allowing the tooltip to remain visible.

Part of fix for issue #71.

* fix(frontend): use fixed tooltip position for sparkline charts

Instead of toggling overflow on hover (which causes scroll position
reset), use ApexCharts' built-in tooltip.fixed option to render
tooltips at a fixed position relative to the chart.

This avoids the horizontal scroll jump issue that occurred when
overflow changed from auto to visible, since overflow:visible
removes scroll capability entirely.

Fixes issue #71.

* fix(frontend): disable tooltips on sparkline charts

ApexCharts tooltips cannot escape overflow:auto containers because
they render inside the chart element. After trying multiple approaches
(overflow toggling, fixed positioning, custom tooltips), the simplest
solution is to disable tooltips entirely on sparklines.

Users can still see the visual trend and click the row to expand
details if needed.

Fixes issue #71.

* feat(frontend): add attribute history dialog for sparkline charts

Since tooltips are disabled on sparklines due to overflow clipping issues,
add a click handler that opens a dialog showing:
- A larger bar chart with working tooltips
- A table of historical values with dates and status indicators

Users can click on any sparkline in the History column to view the full
historical data in a modal dialog.

Related to issue #71.
Starosdev pushed a commit that referenced this pull request Jan 19, 2026
## [1.10.0](v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](#80)) ([88ef36e](88ef36e)), closes [#72](#72)
* **docker:** add ZFS collector to omnibus image ([#82](#82)) ([9ed219d](9ed219d))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](a1a67cf)), closes [#71](#71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](46e4938))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](d5ce8be))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](c9fc565))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](e987360)), closes [#71](#71)
* **frontend:** disable tooltips on sparkline charts ([853d580](853d580)), closes [#71](#71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](1377179)), closes [#71](#71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](0a16d4e)), closes [#71](#71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](a81e08a)), closes [#71](#71)
Starosdev added a commit that referenced this pull request Jan 24, 2026
)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](#80)) ([88ef36e](88ef36e)), closes [#72](#72)
* **docker:** add ZFS collector to omnibus image ([#82](#82)) ([9ed219d](9ed219d))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](a1a67cf)), closes [#71](#71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](46e4938))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](d5ce8be))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](c9fc565))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](e987360)), closes [#71](#71)
* **frontend:** disable tooltips on sparkline charts ([853d580](853d580)), closes [#71](#71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](1377179)), closes [#71](#71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](0a16d4e)), closes [#71](#71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](a81e08a)), closes [#71](#71)

* chore(release): 1.10.1

## [1.10.1](v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](c8b22fd))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](#74)) ([10698c3](10698c3))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](#96)) ([4713199](4713199))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](#98)) ([126307f](126307f)), closes [#84](#84) [#84](#84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](#99)) ([d615d78](d615d78)), closes [#95](#95) [#96](#96) [#95](#95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](#100)) ([e37a924](e37a924)), closes [#91](#91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](#101)) ([ebef580](ebef580)), closes [#95](#95) [#96](#96) [#95](#95) [#93](#93) [#93](#93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](#103)) ([edce49b](edce49b))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](#104)) ([15e2a62](15e2a62)), closes [#69](#69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](#105)) ([72d1773](72d1773)), closes [#67](#67) [#67](#67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](#116)) ([ed386d2](ed386d2)), closes [#78](#78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](#118)) ([e113d1f](e113d1f))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](#120)) ([fa9b54d](fa9b54d)), closes [#97](#97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](#122) ([#127](#127)) ([b0907f8](b0907f8))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](#124)) ([fac6c3e](fac6c3e))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](bb36d66))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](#129)) ([9930980](9930980)), closes [#67](#67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](#130)) ([2ec3eb1](2ec3eb1)), closes [#107](#107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* fix(notify): handle Zulip 60-character topic limit and add force_topic support

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* feat(backend): add container CPU quota awareness with automaxprocs

Go does not respect Linux container CPU quotas by default, setting
GOMAXPROCS to host CPU count regardless of cgroup limits. This causes
CPU throttling and degraded performance in resource-constrained containers.

Add go.uber.org/automaxprocs v1.6.0 to automatically configure GOMAXPROCS
based on the container's CPU quota. The package initializes via init()
so only blank imports are needed in each entry point.

Closes #112

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>
Starosdev added a commit that referenced this pull request Jan 24, 2026
* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](#80)) ([88ef36e](88ef36e)), closes [#72](#72)
* **docker:** add ZFS collector to omnibus image ([#82](#82)) ([9ed219d](9ed219d))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](a1a67cf)), closes [#71](#71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](46e4938))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](d5ce8be))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](c9fc565))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](e987360)), closes [#71](#71)
* **frontend:** disable tooltips on sparkline charts ([853d580](853d580)), closes [#71](#71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](1377179)), closes [#71](#71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](0a16d4e)), closes [#71](#71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](a81e08a)), closes [#71](#71)

* chore(release): 1.10.1

## [1.10.1](v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](c8b22fd))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](#74)) ([10698c3](10698c3))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](#96)) ([4713199](4713199))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](#98)) ([126307f](126307f)), closes [#84](#84) [#84](#84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](#99)) ([d615d78](d615d78)), closes [#95](#95) [#96](#96) [#95](#95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](#100)) ([e37a924](e37a924)), closes [#91](#91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](#101)) ([ebef580](ebef580)), closes [#95](#95) [#96](#96) [#95](#95) [#93](#93) [#93](#93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](#103)) ([edce49b](edce49b))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](#104)) ([15e2a62](15e2a62)), closes [#69](#69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](#105)) ([72d1773](72d1773)), closes [#67](#67) [#67](#67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](#116)) ([ed386d2](ed386d2)), closes [#78](#78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](#118)) ([e113d1f](e113d1f))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](#120)) ([fa9b54d](fa9b54d)), closes [#97](#97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](#122) ([#127](#127)) ([b0907f8](b0907f8))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](#124)) ([fac6c3e](fac6c3e))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](bb36d66))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](#129)) ([9930980](9930980)), closes [#67](#67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](#130)) ([2ec3eb1](2ec3eb1)), closes [#107](#107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* ci(docker): add concurrency and path filtering to docker-build workflow

- Add concurrency group to cancel in-progress builds when new commits arrive
- Add path filtering to skip builds for non-code changes (docs, README)
- Reduces wasted CI time when batching multiple merges to develop/master

* fix(notify): handle Zulip 60-character topic limit and add force_topic support (#132)

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* chore(release): 1.15.6

## [1.15.6](v1.15.5...v1.15.6) (2026-01-24)

### Bug Fixes

* **notify:** handle Zulip 60-character topic limit and add force_topic support ([#132](#132)) ([a6b45cd](a6b45cd)), closes [#110](#110)

* fix(docker): use exec in service scripts to reduce process overhead (#131)

Use exec to replace shell processes with main service processes,
eliminating unnecessary bash processes in the container process tree.

Changes:
- Change CMD to ENTRYPOINT in omnibus Dockerfile
- Add exec to cron, influxdb, and scrutiny service run scripts

This reduces memory usage and improves signal handling for graceful
container shutdowns.

Closes #111

* chore(release): 1.15.7

## [1.15.7](v1.15.6...v1.15.7) (2026-01-24)

### Bug Fixes

* **docker:** use exec in service scripts to reduce process overhead ([#131](#131)) ([43eba12](43eba12)), closes [#111](#111)

* feat(notify): add missed collector ping notifications

Add background monitoring to detect when collectors fail to send data
within the expected time window and send notifications via configured
channels.

Changes:
- Add MissedPingMonitor background scheduler that checks for stale devices
- Add GetDevicesLastSeenTimes() to query last submission times from InfluxDB
- Add MissedPingPayload and NewMissedPing() for notification handling
- Add database migration for new settings (notify_on_missed_ping,
  missed_ping_timeout_minutes, missed_ping_check_interval_mins)
- Add settings fields to Metrics struct
- Add 5 new tests for missed ping payload generation

Configuration via Settings API:
  curl -X POST http://localhost:8080/api/settings \
    -H "Content-Type: application/json" \
    -d '{"metrics": {"notify_on_missed_ping": true}}'

Closes #126

* fix(notify): improve missed ping monitor robustness and add tests

- Add graceful shutdown with signal handling (SIGINT/SIGTERM)
- Optimize repository usage with persistent connection
- Fix potential memory leak in notifiedDevices map
- Add context cancellation for in-flight operations
- Add 15 unit tests for monitor behavior
- Refactor checkMissedPings for lower cognitive complexity

* feat(ui): add missed ping notification settings to dashboard

- Add toggle to enable/disable missed collector ping notifications
- Add configurable timeout (minutes before alerting)
- Add configurable check interval (how often to check)
- Show timeout/interval fields only when feature is enabled

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>
Starosdev added a commit that referenced this pull request Jan 24, 2026
* feat(backend): add container CPU quota awareness with automaxprocs (#133)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* fix(notify): handle Zulip 60-character topic limit and add force_topic support

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* feat(backend): add container CPU quota awareness with automaxprocs

Go does not respect Linux container CPU quotas by default, setting
GOMAXPROCS to host CPU count regardless of cgroup limits. This causes
CPU throttling and degraded performance in resource-constrained containers.

Add go.uber.org/automaxprocs v1.6.0 to automatically configure GOMAXPROCS
based on the container's CPU quota. The package initializes via init()
so only blank imports are needed in each entry point.

Closes #112

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* feat(notify): add missed collector ping notifications (#140)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* ci(docker): add concurrency and path filtering to docker-build workflow

- Add concurrency group to cancel in-progress builds when new commits arrive
- Add path filtering to skip builds for non-code changes (docs, README)
- Reduces wasted CI time when batching multiple merges to develop/master

* fix(notify): handle Zulip 60-character topic limit and add force_topic support (#132)

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* chore(release): 1.15.6

## [1.15.6](https://github.com/Starosdev/scrutiny/compare/v1.15.5...v1.15.6) (2026-01-24)

### Bug Fixes

* **notify:** handle Zulip 60-character topic limit and add force_topic support ([#132](https://github.com/Starosdev/scrutiny/issues/132)) ([a6b45cd](https://github.com/Starosdev/scrutiny/commit/a6b45cd7d6309e74e2fdf934fc3b9d8165c52b95)), closes [#110](https://github.com/Starosdev/scrutiny/issues/110)

* fix(docker): use exec in service scripts to reduce process overhead (#131)

Use exec to replace shell processes with main service processes,
eliminating unnecessary bash processes in the container process tree.

Changes:
- Change CMD to ENTRYPOINT in omnibus Dockerfile
- Add exec to cron, influxdb, and scrutiny service run scripts

This reduces memory usage and improves signal handling for graceful
container shutdowns.

Closes #111

* chore(release): 1.15.7

## [1.15.7](https://github.com/Starosdev/scrutiny/compare/v1.15.6...v1.15.7) (2026-01-24)

### Bug Fixes

* **docker:** use exec in service scripts to reduce process overhead ([#131](https://github.com/Starosdev/scrutiny/issues/131)) ([43eba12](https://github.com/Starosdev/scrutiny/commit/43eba12b7e574dede4fd2599a14b856369a8e713)), closes [#111](https://github.com/Starosdev/scrutiny/issues/111)

* feat(notify): add missed collector ping notifications

Add background monitoring to detect when collectors fail to send data
within the expected time window and send notifications via configured
channels.

Changes:
- Add MissedPingMonitor background scheduler that checks for stale devices
- Add GetDevicesLastSeenTimes() to query last submission times from InfluxDB
- Add MissedPingPayload and NewMissedPing() for notification handling
- Add database migration for new settings (notify_on_missed_ping,
  missed_ping_timeout_minutes, missed_ping_check_interval_mins)
- Add settings fields to Metrics struct
- Add 5 new tests for missed ping payload generation

Configuration via Settings API:
  curl -X POST http://localhost:8080/api/settings \
    -H "Content-Type: application/json" \
    -d '{"metrics": {"notify_on_missed_ping": true}}'

Closes #126

* fix(notify): improve missed ping monitor robustness and add tests

- Add graceful shutdown with signal handling (SIGINT/SIGTERM)
- Optimize repository usage with persistent connection
- Fix potential memory leak in notifiedDevices map
- Add context cancellation for in-flight operations
- Add 15 unit tests for monitor behavior
- Refactor checkMissedPings for lower cognitive complexity

* feat(ui): add missed ping notification settings to dashboard

- Add toggle to enable/disable missed collector ping notifications
- Add configurable timeout (minutes before alerting)
- Add configurable check interval (how often to check)
- Show timeout/interval fields only when feature is enabled

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* fix(api): return attribute override ID after save for UI deletion (#142)

The SaveAttributeOverride function was passing the override struct by
value, so the ID populated by GORM after creation wasn't returned to
the frontend. Additionally, gorm.Model serialized ID as uppercase "ID"
but the frontend expected lowercase "id".

Changes:
- Replace gorm.Model with explicit fields and proper json tags
- Change SaveAttributeOverride to use pointer parameter
- Update interface, handler, and mock to match

Fixes #141

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>
Starosdev added a commit that referenced this pull request Jan 25, 2026
* feat(backend): add container CPU quota awareness with automaxprocs (#133)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* fix(notify): handle Zulip 60-character topic limit and add force_topic support

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* feat(backend): add container CPU quota awareness with automaxprocs

Go does not respect Linux container CPU quotas by default, setting
GOMAXPROCS to host CPU count regardless of cgroup limits. This causes
CPU throttling and degraded performance in resource-constrained containers.

Add go.uber.org/automaxprocs v1.6.0 to automatically configure GOMAXPROCS
based on the container's CPU quota. The package initializes via init()
so only blank imports are needed in each entry point.

Closes #112

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* feat(notify): add missed collector ping notifications (#140)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* ci(docker): add concurrency and path filtering to docker-build workflow

- Add concurrency group to cancel in-progress builds when new commits arrive
- Add path filtering to skip builds for non-code changes (docs, README)
- Reduces wasted CI time when batching multiple merges to develop/master

* fix(notify): handle Zulip 60-character topic limit and add force_topic support (#132)

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* chore(release): 1.15.6

## [1.15.6](https://github.com/Starosdev/scrutiny/compare/v1.15.5...v1.15.6) (2026-01-24)

### Bug Fixes

* **notify:** handle Zulip 60-character topic limit and add force_topic support ([#132](https://github.com/Starosdev/scrutiny/issues/132)) ([a6b45cd](https://github.com/Starosdev/scrutiny/commit/a6b45cd7d6309e74e2fdf934fc3b9d8165c52b95)), closes [#110](https://github.com/Starosdev/scrutiny/issues/110)

* fix(docker): use exec in service scripts to reduce process overhead (#131)

Use exec to replace shell processes with main service processes,
eliminating unnecessary bash processes in the container process tree.

Changes:
- Change CMD to ENTRYPOINT in omnibus Dockerfile
- Add exec to cron, influxdb, and scrutiny service run scripts

This reduces memory usage and improves signal handling for graceful
container shutdowns.

Closes #111

* chore(release): 1.15.7

## [1.15.7](https://github.com/Starosdev/scrutiny/compare/v1.15.6...v1.15.7) (2026-01-24)

### Bug Fixes

* **docker:** use exec in service scripts to reduce process overhead ([#131](https://github.com/Starosdev/scrutiny/issues/131)) ([43eba12](https://github.com/Starosdev/scrutiny/commit/43eba12b7e574dede4fd2599a14b856369a8e713)), closes [#111](https://github.com/Starosdev/scrutiny/issues/111)

* feat(notify): add missed collector ping notifications

Add background monitoring to detect when collectors fail to send data
within the expected time window and send notifications via configured
channels.

Changes:
- Add MissedPingMonitor background scheduler that checks for stale devices
- Add GetDevicesLastSeenTimes() to query last submission times from InfluxDB
- Add MissedPingPayload and NewMissedPing() for notification handling
- Add database migration for new settings (notify_on_missed_ping,
  missed_ping_timeout_minutes, missed_ping_check_interval_mins)
- Add settings fields to Metrics struct
- Add 5 new tests for missed ping payload generation

Configuration via Settings API:
  curl -X POST http://localhost:8080/api/settings \
    -H "Content-Type: application/json" \
    -d '{"metrics": {"notify_on_missed_ping": true}}'

Closes #126

* fix(notify): improve missed ping monitor robustness and add tests

- Add graceful shutdown with signal handling (SIGINT/SIGTERM)
- Optimize repository usage with persistent connection
- Fix potential memory leak in notifiedDevices map
- Add context cancellation for in-flight operations
- Add 15 unit tests for monitor behavior
- Refactor checkMissedPings for lower cognitive complexity

* feat(ui): add missed ping notification settings to dashboard

- Add toggle to enable/disable missed collector ping notifications
- Add configurable timeout (minutes before alerting)
- Add configurable check interval (how often to check)
- Show timeout/interval fields only when feature is enabled

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* fix(api): return attribute override ID after save for UI deletion (#142)

The SaveAttributeOverride function was passing the override struct by
value, so the ID populated by GORM after creation wasn't returned to
the frontend. Additionally, gorm.Model serialized ID as uppercase "ID"
but the frontend expected lowercase "id".

Changes:
- Replace gorm.Model with explicit fields and proper json tags
- Change SaveAttributeOverride to use pointer parameter
- Update interface, handler, and mock to match

Fixes #141

* feat(frontend): improve temperature graph UX (#40) (#145)

- Add dropdown icon to time selector button for visual affordance
- Enable Y-axis with temperature labels and unit display
- Enable X-axis with datetime labels (disabled sparkline mode)
- Add drive filter/selector to show/hide specific drives on graph
- Add grid lines for better readability

* refactor: migrate from moment.js to dayjs for date handling (#147)

- Removed moment.js dependencies from package.json and package-lock.json.
- Introduced dayjs as a lightweight alternative for date manipulation.
- Updated date handling in date-range component and related modules to use dayjs.
- Adjusted date formatting and parsing methods to align with dayjs API.
- Enhanced date range functionality with dayjs plugins for improved performance and features.

* chore(release): 1.15.8

## [1.15.8](https://github.com/Starosdev/scrutiny/compare/v1.15.7...v1.15.8) (2026-01-25)

### Refactoring

* migrate from moment.js to dayjs for date handling ([#147](https://github.com/Starosdev/scrutiny/issues/147)) ([ab6584d](https://github.com/Starosdev/scrutiny/commit/ab6584db48f761f332074672d2c11cfeaff36ed6))

* ci(release): add manual dispatch support for release workflow

Allows triggering releases manually when merge commits don't contain
conventional commit messages. Options: auto, patch, minor, major.

When a non-auto option is selected, creates an empty commit with the
appropriate conventional commit message to trigger semantic-release.

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>
Starosdev added a commit that referenced this pull request Jan 25, 2026
* feat(backend): add container CPU quota awareness with automaxprocs (#133)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* fix(notify): handle Zulip 60-character topic limit and add force_topic support

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* feat(backend): add container CPU quota awareness with automaxprocs

Go does not respect Linux container CPU quotas by default, setting
GOMAXPROCS to host CPU count regardless of cgroup limits. This causes
CPU throttling and degraded performance in resource-constrained containers.

Add go.uber.org/automaxprocs v1.6.0 to automatically configure GOMAXPROCS
based on the container's CPU quota. The package initializes via init()
so only blank imports are needed in each entry point.

Closes #112

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* feat(notify): add missed collector ping notifications (#140)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* ci(docker): add concurrency and path filtering to docker-build workflow

- Add concurrency group to cancel in-progress builds when new commits arrive
- Add path filtering to skip builds for non-code changes (docs, README)
- Reduces wasted CI time when batching multiple merges to develop/master

* fix(notify): handle Zulip 60-character topic limit and add force_topic support (#132)

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* chore(release): 1.15.6

## [1.15.6](https://github.com/Starosdev/scrutiny/compare/v1.15.5...v1.15.6) (2026-01-24)

### Bug Fixes

* **notify:** handle Zulip 60-character topic limit and add force_topic support ([#132](https://github.com/Starosdev/scrutiny/issues/132)) ([a6b45cd](https://github.com/Starosdev/scrutiny/commit/a6b45cd7d6309e74e2fdf934fc3b9d8165c52b95)), closes [#110](https://github.com/Starosdev/scrutiny/issues/110)

* fix(docker): use exec in service scripts to reduce process overhead (#131)

Use exec to replace shell processes with main service processes,
eliminating unnecessary bash processes in the container process tree.

Changes:
- Change CMD to ENTRYPOINT in omnibus Dockerfile
- Add exec to cron, influxdb, and scrutiny service run scripts

This reduces memory usage and improves signal handling for graceful
container shutdowns.

Closes #111

* chore(release): 1.15.7

## [1.15.7](https://github.com/Starosdev/scrutiny/compare/v1.15.6...v1.15.7) (2026-01-24)

### Bug Fixes

* **docker:** use exec in service scripts to reduce process overhead ([#131](https://github.com/Starosdev/scrutiny/issues/131)) ([43eba12](https://github.com/Starosdev/scrutiny/commit/43eba12b7e574dede4fd2599a14b856369a8e713)), closes [#111](https://github.com/Starosdev/scrutiny/issues/111)

* feat(notify): add missed collector ping notifications

Add background monitoring to detect when collectors fail to send data
within the expected time window and send notifications via configured
channels.

Changes:
- Add MissedPingMonitor background scheduler that checks for stale devices
- Add GetDevicesLastSeenTimes() to query last submission times from InfluxDB
- Add MissedPingPayload and NewMissedPing() for notification handling
- Add database migration for new settings (notify_on_missed_ping,
  missed_ping_timeout_minutes, missed_ping_check_interval_mins)
- Add settings fields to Metrics struct
- Add 5 new tests for missed ping payload generation

Configuration via Settings API:
  curl -X POST http://localhost:8080/api/settings \
    -H "Content-Type: application/json" \
    -d '{"metrics": {"notify_on_missed_ping": true}}'

Closes #126

* fix(notify): improve missed ping monitor robustness and add tests

- Add graceful shutdown with signal handling (SIGINT/SIGTERM)
- Optimize repository usage with persistent connection
- Fix potential memory leak in notifiedDevices map
- Add context cancellation for in-flight operations
- Add 15 unit tests for monitor behavior
- Refactor checkMissedPings for lower cognitive complexity

* feat(ui): add missed ping notification settings to dashboard

- Add toggle to enable/disable missed collector ping notifications
- Add configurable timeout (minutes before alerting)
- Add configurable check interval (how often to check)
- Show timeout/interval fields only when feature is enabled

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* fix(api): return attribute override ID after save for UI deletion (#142)

The SaveAttributeOverride function was passing the override struct by
value, so the ID populated by GORM after creation wasn't returned to
the frontend. Additionally, gorm.Model serialized ID as uppercase "ID"
but the frontend expected lowercase "id".

Changes:
- Replace gorm.Model with explicit fields and proper json tags
- Change SaveAttributeOverride to use pointer parameter
- Update interface, handler, and mock to match

Fixes #141

* feat(frontend): improve temperature graph UX (#40) (#145)

- Add dropdown icon to time selector button for visual affordance
- Enable Y-axis with temperature labels and unit display
- Enable X-axis with datetime labels (disabled sparkline mode)
- Add drive filter/selector to show/hide specific drives on graph
- Add grid lines for better readability

* refactor: migrate from moment.js to dayjs for date handling (#147)

- Removed moment.js dependencies from package.json and package-lock.json.
- Introduced dayjs as a lightweight alternative for date manipulation.
- Updated date handling in date-range component and related modules to use dayjs.
- Adjusted date formatting and parsing methods to align with dayjs API.
- Enhanced date range functionality with dayjs plugins for improved performance and features.

* chore(release): 1.15.8

## [1.15.8](https://github.com/Starosdev/scrutiny/compare/v1.15.7...v1.15.8) (2026-01-25)

### Refactoring

* migrate from moment.js to dayjs for date handling ([#147](https://github.com/Starosdev/scrutiny/issues/147)) ([ab6584d](https://github.com/Starosdev/scrutiny/commit/ab6584db48f761f332074672d2c11cfeaff36ed6))

* ci(release): add manual dispatch support for release workflow

Allows triggering releases manually when merge commits don't contain
conventional commit messages. Options: auto, patch, minor, major.

When a non-auto option is selected, creates an empty commit with the
appropriate conventional commit message to trigger semantic-release.

* fix(security): prevent Flux query injection via parameterized queries (#149)

* fix(security): prevent Flux query injection via parameterized queries (#135)

Replace unsafe fmt.Sprintf Flux query construction with parameterized
queries and input validation to prevent injection attacks.

Changes:
- Add validation package with WWN and GUID format validation
- Add handler-level validation returning 400 Bad Request for invalid input
- Convert GetPreviousSmartSubmission to use QueryWithParams
- Convert GetSmartAttributeHistory to use QueryWithParams
- Convert GetZFSPoolMetricsHistory to use QueryWithParams
- Add defense-in-depth validation in DeleteDevice and DeleteZFSPool
  repository methods (DeleteAPI doesn't support parameterization)

Closes #135

* fix(validation): support UUID format for NVMe device WWNs

NVMe devices use UUID format (e.g., a4c8e8ed-11a0-4c97-9bba-306440f1b944)
instead of the 0x hex format used by ATA/SCSI devices. Update WWN validation
to accept both formats while still preventing injection attacks.

* refactor(backend): replace fmt.Printf with structured logging (#136) (#150)

- Remove duplicate fmt.Printf in notify.go (already logged via logrus)
- Replace debug fmt.Println with sr.logger.Debugln in repository_device.go
- Replace fmt.Printf error logging with sr.logger.Errorf in repository files
- Clean up debug print statements (=== lines) in scrutiny_repository.go
- Use bootstrapLogger instead of fmt.Printf in scrutiny.go startup

All fmt.Printf/Println calls now use appropriate logrus logging methods
for consistent, structured logging output.

* docs: add environment variable documentation for web server (#137) (#151)

- Add comprehensive environment variable documentation to example.scrutiny.yaml
- Add "Web Server Environment Variable Overrides" section to README.md
- Update collector env var table in README.md with default values
- Document all SCRUTINY_* environment variables with their config key mappings

* feat(config): make InfluxDB retention periods configurable (#138) (#152)

- Add config options for retention periods: web.influxdb.retention.daily,
  web.influxdb.retention.weekly, web.influxdb.retention.monthly
- Update EnsureBuckets to use config values instead of hardcoded constants
- Rename constants to DEFAULT_* prefix for backwards compatibility in migrations
- Document retention settings in example.scrutiny.yaml

Users can now customize how long metrics data is retained without
recompiling. Default values remain unchanged for backwards compatibility.

* feat(api): improve health check depth with structured response (#139) (#153)

* feat(api): improve health check depth with structured response (#139)

- Add HealthCheckResult and HealthCheckStatus types for detailed health info
- Execute actual SQLite query (not just ping) to verify database responsiveness
- Measure and report latency for each health check component
- Return structured JSON response with individual check status and latency
- Add frontend files check to the health check result
- Maintain backwards compatibility by returning error when unhealthy

Example response:
{
  "success": true,
  "status": "healthy",
  "checks": {
    "influxdb": {"status": "ok", "latency_ms": 15},
    "sqlite": {"status": "ok", "latency_ms": 2},
    "frontend": {"status": "ok", "latency_ms": 0}
  }
}

* fix(test): update health check tests for new structured response format

The health check endpoint now returns a structured response with status
and checks fields. Updated test assertions to validate the JSON response
structure instead of exact string matching.

- TestHealthRoute: check success, status, and checks fields
- TestHealthRoute_MissingFrontend: verify unhealthy status and error message

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>
Starosdev added a commit that referenced this pull request Jan 26, 2026
…devices (#158)

* Release: Merge develop to master (#144)

* feat(backend): add container CPU quota awareness with automaxprocs (#133)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* fix(notify): handle Zulip 60-character topic limit and add force_topic support

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* feat(backend): add container CPU quota awareness with automaxprocs

Go does not respect Linux container CPU quotas by default, setting
GOMAXPROCS to host CPU count regardless of cgroup limits. This causes
CPU throttling and degraded performance in resource-constrained containers.

Add go.uber.org/automaxprocs v1.6.0 to automatically configure GOMAXPROCS
based on the container's CPU quota. The package initializes via init()
so only blank imports are needed in each entry point.

Closes #112

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* feat(notify): add missed collector ping notifications (#140)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and wearout health conditionally based on available data.
- Added unit tests for new methods to ensure correct functionality and integration.

* add missing imports to reduce non-errors in testing

* chore(release): 1.12.0

## [1.12.0](https://github.com/Starosdev/scrutiny/compare/v1.11.0...v1.12.0) (2026-01-22)

### Features

* **detail:** add SSD health metrics to detail component ([#96](https://github.com/Starosdev/scrutiny/issues/96)) ([4713199](https://github.com/Starosdev/scrutiny/commit/4713199cdae5ac0d4c35d9443ad811b735412ade))

* docs(notify): add Telegram topic/thread ID documentation

Document the correct format for sending notifications to Telegram
topics/threads using the chat_id:thread_id syntax supported by
Shoutrrr v0.8.0.

Fixes #31

* Fix ata gp logmapping Closes: #92 (#94)

* devstat 1_40 and 1_48 were incorrectly placed in page 1, but the correct mappings already exist in page 3.
According to the ATA GP Log 0x04 specification:
Page 3, offset 0x030 (48 decimal) = "Number of Mechanical Start Failures"
Page 3, offset 0x038 (56 decimal) = "Number of Reallocation Candidate Logical Sectors"
So:
devstat_3_48 is correct, devstat_3_56 is correct
The issue was that they were also incorrectly mapped in page 1, which is now fixed.

* refactor: update AtaDeviceStatsMetadata for uncorrectable errors

Removed duplicate entry for "Number of Reported Uncorrectable Errors" from page 1 and updated the entry on page 4 - now correctly mapped to "Number of Reported Uncorrectable Errors"

* fix: correct ATA device statistics metadata mappings

Updated the mappings for ATA device statistics in the metadata. Adjusted page numbers and offsets for various statistics, ensuring accurate representation according to the ATA GP Log 0x04 specification. This includes renumbering entries from page 0 to page 1 and adding new statistics for pages 2, 3, and 4.

* PowerOnResets should not report a failure

* fix(smart): prevent false failures from corrupted ATA device statistics (#98)

* fix(smart): prevent false failures from corrupted ATA device statistics (#84)

Add sanity checks for impossibly high device statistics values (e.g., 420 billion
mechanical failures) that were causing false failure alerts. Changes include:

- Add AttributeStatusInvalidValue constant for corrupted data detection
- Add MaxReasonableFailureCount (1M) threshold for value validation
- Mark values exceeding threshold as invalid instead of failed
- Add device status propagation to ProcessAtaDeviceStatistics
- Fix notify.go to handle string-based devstat attribute IDs
- Add config-based ignore lists for devstat attributes
- Add comprehensive unit tests for all new functionality

Closes #84

* fix(tests): use correct attribute IDs with Ideal:low metadata

The invalid value detection tests were using devstat_1_40 which has
Ideal:"" (empty), but the sanity check only applies to attributes with
Ideal:ObservedThresholdIdealLow. Updated tests to use:
- devstat_7_8 (Percentage Used) for critical attribute tests
- devstat_5_88 (Time in Over-temperature) for non-critical test

* chore(release): 1.12.1

## [1.12.1](https://github.com/Starosdev/scrutiny/compare/v1.12.0...v1.12.1) (2026-01-22)

### Bug Fixes

* **smart:** prevent false failures from corrupted ATA device statistics ([#98](https://github.com/Starosdev/scrutiny/issues/98)) ([126307f](https://github.com/Starosdev/scrutiny/commit/126307f3301960ef989bf0da1b2bb60cd3f547cd)), closes [#84](https://github.com/Starosdev/scrutiny/issues/84) [#84](https://github.com/Starosdev/scrutiny/issues/84)

* feat(dashboard): add SSD health metrics to dashboard cards (#99)

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* chore(release): 1.13.0

## [1.13.0](https://github.com/Starosdev/scrutiny/compare/v1.12.1...v1.13.0) (2026-01-22)

### Features

* **dashboard:** add SSD health metrics to dashboard cards ([#99](https://github.com/Starosdev/scrutiny/issues/99)) ([d615d78](https://github.com/Starosdev/scrutiny/commit/d615d78bc626630b9accdec39c9e8b6eefcc71ce)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95)

* fix(zfs): ensure pool data updates are persisted to database (#100)

The ZFS pool registration was using GORM's OnConflict clause with
AssignmentColumns, which was not reliably updating existing records
in SQLite. This caused the collector to send fresh data but the
database to retain stale values from initial registration.

Replace the OnConflict+Create pattern with explicit find-or-create
logic using Model().Updates(), which is the same pattern used
elsewhere in the codebase for device updates.

Changes:
- Check if pool exists by GUID before insert/update
- Use GORM's Updates() with a map for existing pools
- Explicitly set and include updated_at in updates

Closes #91

* chore(release): 1.13.1

## [1.13.1](https://github.com/Starosdev/scrutiny/compare/v1.13.0...v1.13.1) (2026-01-22)

### Bug Fixes

* **zfs:** ensure pool data updates are persisted to database ([#100](https://github.com/Starosdev/scrutiny/issues/100)) ([e37a924](https://github.com/Starosdev/scrutiny/commit/e37a924bf2f85e4f7a39b9bc5254d6e99d0fcb42)), closes [#91](https://github.com/Starosdev/scrutiny/issues/91)

* fix(smart): correct TB written/read calculation for Intel SSDs (#101)

* feat(dashboard): add SSD health metrics to dashboard cards

Display SSD health/wearout percentage on dashboard device cards when available.
This completes the dashboard portion of the feature request in #95 (detail page
was already addressed in PR #96).

Backend changes:
- Add PercentageUsed and WearoutValue fields to SmartSummary struct
- Extend InfluxDB query to fetch SSD health attributes (percentage_used,
  devstat_7_8, and wearout attributes 177/233/231/232)

Frontend changes:
- Add health fields to SmartSummary TypeScript interface
- Add getSSDHealth(), getSSDHealthLabel(), getSSDHealthDisplay() methods
- Display "Used" percentage for NVMe/DevStats (higher = more worn)
- Display "Health" percentage for wearout attributes (higher = healthier)
- Add 12 unit tests for new functionality

Closes #95

* fix(smart): correct TB written/read calculation for Intel SSDs (#93)

Intel and other vendor SSDs use 32MiB units for SMART attributes 241/242
instead of LBA counts. The frontend now detects the unit type from the
attribute name provided by smartctl and applies the correct conversion.

- Add Name field to SmartAtaAttribute to pass attribute name from smartctl
- Store attribute name in InfluxDB via Flatten/Inflate methods
- Add convertToTB helper that detects unit type from attribute name:
  - "32MiB" suffix: Intel/Crucial/Micron/InnoDisk SSDs (32 MiB per unit)
  - "GiB" suffix: Some SSDs reporting in GiB units
  - Default: LBA units (multiply by logical block size)

Closes #93

* chore(release): 1.13.2

## [1.13.2](https://github.com/Starosdev/scrutiny/compare/v1.13.1...v1.13.2) (2026-01-22)

### Bug Fixes

* **smart:** correct TB written/read calculation for Intel SSDs ([#101](https://github.com/Starosdev/scrutiny/issues/101)) ([ebef580](https://github.com/Starosdev/scrutiny/commit/ebef580da4e35aa403d374bf150c4b81b304fb1c)), closes [#95](https://github.com/Starosdev/scrutiny/issues/95) [#96](https://github.com/Starosdev/scrutiny/issues/96) [#95](https://github.com/Starosdev/scrutiny/issues/95) [#93](https://github.com/Starosdev/scrutiny/issues/93) [#93](https://github.com/Starosdev/scrutiny/issues/93)

* fix(frontend): update zfs pool model scrub property names to match the backend response (#103)

* chore(release): 1.13.3

## [1.13.3](https://github.com/Starosdev/scrutiny/compare/v1.13.2...v1.13.3) (2026-01-23)

### Bug Fixes

* **frontend:** update zfs pool model scrub property names to match the backend response ([#103](https://github.com/Starosdev/scrutiny/issues/103)) ([edce49b](https://github.com/Starosdev/scrutiny/commit/edce49b4e24da4d8698fb446093278b8fde8cb7e))

* docs(readme): update version and add contribution transparency

- Update fork version from v1.6.x to v1.13.x in comparison table
- Add note about this being a learning project
- Add transparency about AI-assisted development with manual review

* fix(frontend): remove unused Quill dependency (XSS vulnerability) (#104)

Remove Quill rich text editor package which was never actually used
in the application. Only CSS imports and style overrides existed
with no functional usage (no QuillModule, no editor components,
no API calls).

- Remove quill from package.json dependencies
- Remove CSS import from vendors.scss
- Delete unused _quill.scss override file (143 lines)
- Remove import from main.scss

This eliminates the XSS vulnerability (GHSA-4943-9vgg-gr5r) and
removes 18 packages from the dependency tree.

Closes #69

* chore(release): 1.13.4

## [1.13.4](https://github.com/Starosdev/scrutiny/compare/v1.13.3...v1.13.4) (2026-01-23)

### Bug Fixes

* **frontend:** remove unused Quill dependency (XSS vulnerability) ([#104](https://github.com/Starosdev/scrutiny/issues/104)) ([15e2a62](https://github.com/Starosdev/scrutiny/commit/15e2a62d1bac0f7674da9c4bf82797ec3575730c)), closes [#69](https://github.com/Starosdev/scrutiny/issues/69)

* docs(readme): use dynamic version badge instead of hardcoded version

Replace hardcoded version string with GitHub release badge that
auto-updates. Change Angular version to generic "Modern Angular"
to avoid manual updates on each Angular upgrade.

* fix(backend): reset device status when SMART data passes and add notification logging (#105)

This commit addresses two issues reported in GitHub issue #67:

1. Device status accumulation bug: Device failure status was never cleared
   once set because DeviceStatusClear() existed but was never called.
   Now the status resets to "passed" when current SMART data shows all
   attributes within thresholds.

2. Silent notification failures: Notification errors were silently ignored.
   Added warning logs when notifications fail to send, and debug logging
   throughout ShouldNotify() to help diagnose notification issues.

Changes:
- Add ResetDeviceStatus() to database interface and implementation
- Clear DeviceStatusFailedSmart in UpdateFromCollectorSmartInfo when
  manufacturer SMART status passes
- Call ResetDeviceStatus in upload handler when smartData.Status is passed
  but device still has failure flags
- Add debug logging to ShouldNotify() decision points
- Log notification send failures instead of ignoring them
- Regenerate mock database

Fixes #67

* chore(release): 1.13.5

## [1.13.5](https://github.com/Starosdev/scrutiny/compare/v1.13.4...v1.13.5) (2026-01-23)

### Bug Fixes

* **backend:** reset device status when SMART data passes and add notification logging ([#105](https://github.com/Starosdev/scrutiny/issues/105)) ([72d1773](https://github.com/Starosdev/scrutiny/commit/72d1773439f5a3f2b47456d977ec117d83c090af)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67) [#67](https://github.com/Starosdev/scrutiny/issues/67)

* chore: remove docs/plans from version control

Local planning documents should not be committed to the repository.
Added docs/plans/ to .gitignore.

* fix(backend): skip web integration tests when InfluxDB unavailable (#116)

Add SetupSuite() method to ServerTestSuite that checks InfluxDB
availability before running tests. If InfluxDB is not reachable,
tests skip gracefully with a helpful message pointing to setup
instructions in CLAUDE.md.

This improves developer experience by allowing `go test ./...` to
run without requiring InfluxDB setup for unrelated package tests.

Closes #78

* chore(release): 1.13.6

## [1.13.6](https://github.com/Starosdev/scrutiny/compare/v1.13.5...v1.13.6) (2026-01-23)

### Bug Fixes

* **backend:** skip web integration tests when InfluxDB unavailable ([#116](https://github.com/Starosdev/scrutiny/issues/116)) ([ed386d2](https://github.com/Starosdev/scrutiny/commit/ed386d2819b0f0271b6f1471f4be4fa2d1de0b0c)), closes [#78](https://github.com/Starosdev/scrutiny/issues/78)

* feat(backend): add SMART attribute overrides support (#118)

Implements SCR-114: Allow users to override SMART attribute behavior via
configuration. Users can now:

- Ignore specific attributes to prevent false positives
- Force attribute status to passed/warn/failed
- Set custom thresholds (warn_above/fail_above) for numeric values

Configuration is done via scrutiny.yaml under smart.attribute_overrides.
Each override specifies protocol (ATA/NVMe/SCSI), attribute_id, and
optionally wwn for device-specific overrides.

Changes:
- Add overrides package with AttributeOverride type and Apply functions
- Update SMART processing pipeline to apply overrides after status calc
- Update ShouldNotify to respect overrides when evaluating failures
- Add comprehensive unit tests for override logic
- Update example.scrutiny.yaml with documentation and examples

* chore(release): 1.14.0

## [1.14.0](https://github.com/Starosdev/scrutiny/compare/v1.13.6...v1.14.0) (2026-01-23)

### Features

* **backend:** add SMART attribute overrides support ([#118](https://github.com/Starosdev/scrutiny/issues/118)) ([e113d1f](https://github.com/Starosdev/scrutiny/commit/e113d1f7ab1d2a022e9d12a380abd229aeaad022))

* test(notify): add unit test for muted device notification skip (#119)

Adds test coverage for the muted device check in ShouldNotify().
Verifies that failing devices with Muted=true do not trigger notifications.

Closes #113

* feat(frontend): add UI for configuring SMART attribute overrides (#120)

Add Dashboard Settings UI section for managing SMART attribute overrides,
allowing users to add/remove overrides without editing config files.

Backend changes:
- Add AttributeOverride model with database migration
- Add repository methods for CRUD operations
- Add GetMergedOverrides to combine config + DB overrides
- Add API endpoints: GET/POST/DELETE /api/settings/overrides
- Integrate merged overrides into SMART processing pipeline
- Add ApplyWithOverrides and MergeOverrides functions

Frontend changes:
- Add AttributeOverride TypeScript interface
- Add AttributeOverrideService for API calls
- Add collapsible "SMART Attribute Overrides" section to Dashboard Settings
- Support ignore, force_status, and custom threshold actions
- Show source (config vs UI) and disable delete for config overrides

Closes #97

* chore(release): 1.15.0

## [1.15.0](https://github.com/Starosdev/scrutiny/compare/v1.14.0...v1.15.0) (2026-01-23)

### Features

* **frontend:** add UI for configuring SMART attribute overrides ([#120](https://github.com/Starosdev/scrutiny/issues/120)) ([fa9b54d](https://github.com/Starosdev/scrutiny/commit/fa9b54d2839a9d0621fbda32eb23407b0b896c3a)), closes [#97](https://github.com/Starosdev/scrutiny/issues/97)

* fix(frontend): improve detail view table layout for issue #122 (#127)

- Move device info card above table (full width layout)
- Change device info to horizontal grid (responsive columns)
- Reduce table cell padding (pr-6 to pr-4)
- Allow Name column text wrapping
- Add scroll shadow indicators for table overflow
- Support dark mode for scroll shadows

Fixes: SCR-122

* chore(release): 1.15.1

## [1.15.1](https://github.com/Starosdev/scrutiny/compare/v1.15.0...v1.15.1) (2026-01-24)

### Bug Fixes

* **frontend:** improve detail view table layout for issue [#122](https://github.com/Starosdev/scrutiny/issues/122) ([#127](https://github.com/Starosdev/scrutiny/issues/127)) ([b0907f8](https://github.com/Starosdev/scrutiny/commit/b0907f839478455888dc41a70bdb0da7406fe6fe))

* fix(backend): scsi wrongly uses nvme metadata (#124)

* fix(backend): update SCSI metadata handling in SmartScsiAttribute

Refactor the handling of SCSI metadata in the SmartScsiAttribute model to correctly reference ScsiMetadata instead of NmveMetadata.

introduce a new test case to validate the scrutiny logic for SCSI attributes under failure conditions, enhancing test coverage for the Smart module.

* fix(tests): correct expected value for scsi_grown_defect_list in SmartScsiAttribute tests

Update the expected value for the scsi_grown_defect_list attribute in the SmartScsiAttribute test case to reflect the correct state as per the latest data model changes. This ensures the test accurately validates the handling of SCSI metadata.

* chore(release): 1.15.2

## [1.15.2](https://github.com/Starosdev/scrutiny/compare/v1.15.1...v1.15.2) (2026-01-24)

### Bug Fixes

* **backend:** scsi wrongly uses nvme metadata ([#124](https://github.com/Starosdev/scrutiny/issues/124)) ([fac6c3e](https://github.com/Starosdev/scrutiny/commit/fac6c3ecbaad55ae78c31e5f3549222a25bc9ae2))

* update Go version and dependencies (#125)

* update Go version and dependencies

- Bump Go version from 1.20 to 1.24.0 in go.mod and CI configuration.
- Update various dependencies to their latest versions, including:
  - gin-gonic/gin from v1.6.3 to v1.9.1
  - sirupsen/logrus from v1.6.0 to v1.8.3
  - testify from v1.8.1 to v1.8.3
  - golang.org/x/sync from v0.3.0 to v0.18.0
  - golang.org/x/sys from v0.11.0 to v0.33.0
  - golang.org/x/term from v0.8.0 to v0.32.0
  - google.golang.org/protobuf from v1.31.0 to v1.33.0
- Update Dockerfiles to use golang:1.24-trixie and debian:trixie-slim as base images.

* Updated the banner display logic in collector-metrics, collector-selftest, collector-zfs, and scrutiny commands to store the formatted banner in a variable before printing. This improves code readability and maintains consistent styling across the commands.

* build: update Go 1.23 and dependencies for CVE fixes

* chore(release): 1.15.3

## [1.15.3](https://github.com/Starosdev/scrutiny/compare/v1.15.2...v1.15.3) (2026-01-24)

### Build

* update Go 1.23 and dependencies for CVE fixes ([bb36d66](https://github.com/Starosdev/scrutiny/commit/bb36d665bc3d04d9d8714152158943596d8e232c))

* fix(notify): correct repeat notification detection to compare against previous submission (#129)

The repeat detection logic was comparing the current SMART attribute value
against the previous day's aggregated value instead of the previous
submission's value. This caused notifications to repeat throughout the day
whenever a value changed from the previous day.

Changes:
- Add GetPreviousSmartSubmission() method that queries raw data without
  daily aggregation
- Update ShouldNotify() to use the new method for accurate comparison
- Fix logging bug where err == nil was used instead of err != nil

Fixes: #67

* chore(release): 1.15.4

## [1.15.4](https://github.com/Starosdev/scrutiny/compare/v1.15.3...v1.15.4) (2026-01-24)

### Bug Fixes

* **notify:** correct repeat notification detection to compare against previous submission ([#129](https://github.com/Starosdev/scrutiny/issues/129)) ([9930980](https://github.com/Starosdev/scrutiny/commit/993098092759d9568aba14de4dfa01188296d6a6)), closes [#67](https://github.com/Starosdev/scrutiny/issues/67)

* docs(readme): add new fork features and ZFS collector image

- Add S.M.A.R.T attribute overrides feature
- Add improved dashboard layout (top navigation)
- Add enhanced mobile UI
- Add ZFS collector image to Hub/Spoke deployment section

* fix(backend): use safe type assertions for SMART metrics parsing (#130)

Add safe type assertions with ok checks for temp, power_on_hours, and
power_cycle_count fields in NewSmartFromInfluxDB to prevent panics when
InfluxDB returns unexpected data types.

Closes #107

* chore(release): 1.15.5

## [1.15.5](https://github.com/Starosdev/scrutiny/compare/v1.15.4...v1.15.5) (2026-01-24)

### Bug Fixes

* **backend:** use safe type assertions for SMART metrics parsing ([#130](https://github.com/Starosdev/scrutiny/issues/130)) ([2ec3eb1](https://github.com/Starosdev/scrutiny/commit/2ec3eb1160e072f3c58bc5e7c1583648b1dba412)), closes [#107](https://github.com/Starosdev/scrutiny/issues/107)

* docs(collector): add env var override documentation and tests

- Add TestConfiguration_EnvironmentVariableOverride with 4 test cases
  to ensure env var configuration doesn't silently regress
- Document env var naming convention in example.collector.yaml header
- Add "Collector Environment Variable Overrides" section to README.md
  with mapping table and Docker example

Closes #109 (feature was already implemented in a783604)

* ci(docker): add concurrency and path filtering to docker-build workflow

- Add concurrency group to cancel in-progress builds when new commits arrive
- Add path filtering to skip builds for non-code changes (docs, README)
- Reduces wasted CI time when batching multiple merges to develop/master

* fix(notify): handle Zulip 60-character topic limit and add force_topic support (#132)

- Truncate auto-generated subjects to 60 characters (Zulip's limit enforced by shoutrrr)
- Add force_topic URL parameter to override the topic
- Also truncate force_topic to 60 chars for robustness (improvement over upstream)
- Add 5 unit tests for Zulip notification handling

Closes #110

* chore(release): 1.15.6

## [1.15.6](https://github.com/Starosdev/scrutiny/compare/v1.15.5...v1.15.6) (2026-01-24)

### Bug Fixes

* **notify:** handle Zulip 60-character topic limit and add force_topic support ([#132](https://github.com/Starosdev/scrutiny/issues/132)) ([a6b45cd](https://github.com/Starosdev/scrutiny/commit/a6b45cd7d6309e74e2fdf934fc3b9d8165c52b95)), closes [#110](https://github.com/Starosdev/scrutiny/issues/110)

* fix(docker): use exec in service scripts to reduce process overhead (#131)

Use exec to replace shell processes with main service processes,
eliminating unnecessary bash processes in the container process tree.

Changes:
- Change CMD to ENTRYPOINT in omnibus Dockerfile
- Add exec to cron, influxdb, and scrutiny service run scripts

This reduces memory usage and improves signal handling for graceful
container shutdowns.

Closes #111

* chore(release): 1.15.7

## [1.15.7](https://github.com/Starosdev/scrutiny/compare/v1.15.6...v1.15.7) (2026-01-24)

### Bug Fixes

* **docker:** use exec in service scripts to reduce process overhead ([#131](https://github.com/Starosdev/scrutiny/issues/131)) ([43eba12](https://github.com/Starosdev/scrutiny/commit/43eba12b7e574dede4fd2599a14b856369a8e713)), closes [#111](https://github.com/Starosdev/scrutiny/issues/111)

* feat(notify): add missed collector ping notifications

Add background monitoring to detect when collectors fail to send data
within the expected time window and send notifications via configured
channels.

Changes:
- Add MissedPingMonitor background scheduler that checks for stale devices
- Add GetDevicesLastSeenTimes() to query last submission times from InfluxDB
- Add MissedPingPayload and NewMissedPing() for notification handling
- Add database migration for new settings (notify_on_missed_ping,
  missed_ping_timeout_minutes, missed_ping_check_interval_mins)
- Add settings fields to Metrics struct
- Add 5 new tests for missed ping payload generation

Configuration via Settings API:
  curl -X POST http://localhost:8080/api/settings \
    -H "Content-Type: application/json" \
    -d '{"metrics": {"notify_on_missed_ping": true}}'

Closes #126

* fix(notify): improve missed ping monitor robustness and add tests

- Add graceful shutdown with signal handling (SIGINT/SIGTERM)
- Optimize repository usage with persistent connection
- Fix potential memory leak in notifiedDevices map
- Add context cancellation for in-flight operations
- Add 15 unit tests for monitor behavior
- Refactor checkMissedPings for lower cognitive complexity

* feat(ui): add missed ping notification settings to dashboard

- Add toggle to enable/disable missed collector ping notifications
- Add configurable timeout (minutes before alerting)
- Add configurable check interval (how often to check)
- Show timeout/interval fields only when feature is enabled

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* fix(api): return attribute override ID after save for UI deletion (#142)

The SaveAttributeOverride function was passing the override struct by
value, so the ID populated by GORM after creation wasn't returned to
the frontend. Additionally, gorm.Model serialized ID as uppercase "ID"
but the frontend expected lowercase "id".

Changes:
- Replace gorm.Model with explicit fields and proper json tags
- Change SaveAttributeOverride to use pointer parameter
- Update interface, handler, and mock to match

Fixes #141

---------

Co-authored-by: delacor <robin.tschirschnitz@googlemail.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Robin <robin.tschirschnitz@gmail.com>
Co-authored-by: Bence Nagy <quwisky@qwky.eu>

* refactor: migrate from moment.js to dayjs for date handling (#147)

- Removed moment.js dependencies from package.json and package-lock.json.
- Introduced dayjs as a lightweight alternative for date manipulation.
- Updated date handling in date-range component and related modules to use dayjs.
- Adjusted date formatting and parsing methods to align with dayjs API.
- Enhanced date range functionality with dayjs plugins for improved performance and features.

* chore(release): 1.15.8

## [1.15.8](https://github.com/Starosdev/scrutiny/compare/v1.15.7...v1.15.8) (2026-01-25)

### Refactoring

* migrate from moment.js to dayjs for date handling ([#147](https://github.com/Starosdev/scrutiny/issues/147)) ([ab6584d](https://github.com/Starosdev/scrutiny/commit/ab6584db48f761f332074672d2c11cfeaff36ed6))

* ci(release): add manual dispatch support for release workflow

Allows triggering releases manually when merge commits don't contain
conventional commit messages. Options: auto, patch, minor, major.

When a non-auto option is selected, creates an empty commit with the
appropriate conventional commit message to trigger semantic-release.

* Update Go dependencies in go.mod and go.sum (#146)

- Bump golang.org/x/crypto from v0.39.0 to v0.45.0
- Update golang.org/x/net from v0.38.0 to v0.47.0
- Upgrade golang.org/x/sys from v0.33.0 to v0.38.0
- Change golang.org/x/term from v0.32.0 to v0.37.0
- Update golang.org/x/text from v0.26.0 to v0.31.0

These updates improve security and performance by incorporating the latest versions of the dependencies.

* Release: Merge develop to master (#148)

* feat(backend): add container CPU quota awareness with automaxprocs (#133)

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* fix(mock): enhance ZFS pool management methods in MockDeviceRepo

- Added mock implementations for new ZFS pool management methods to improve testing capabilities.
- Updated existing mock methods to align with recent changes in the ZFS pool management interface

* chore(release): 1.10.0

## [1.10.0](https://github.com/Starosdev/scrutiny/compare/v1.9.1...v1.10.0) (2026-01-19)

### Features

* **dashboard:** add more sorting options ([#80](https://github.com/Starosdev/scrutiny/issues/80)) ([88ef36e](https://github.com/Starosdev/scrutiny/commit/88ef36e0d227437a9cbc4d8da9ac01bb6a80d5d5)), closes [#72](https://github.com/Starosdev/scrutiny/issues/72)
* **docker:** add ZFS collector to omnibus image ([#82](https://github.com/Starosdev/scrutiny/issues/82)) ([9ed219d](https://github.com/Starosdev/scrutiny/commit/9ed219d0e9779682f661c7dd073360f52179ee5e))
* **frontend:** add attribute history dialog for sparkline charts ([a1a67cf](https://github.com/Starosdev/scrutiny/commit/a1a67cf01063ac31c135ba39b9b4b88f994e7ed9)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

### Bug Fixes

* **ci:** limit ZFS collector to amd64 only ([46e4938](https://github.com/Starosdev/scrutiny/commit/46e4938b52fdbd98497a4d3ba4e6ea4e432d84ba))
* **ci:** remove arm/v7 from ZFS collector platforms ([d5ce8be](https://github.com/Starosdev/scrutiny/commit/d5ce8bee221b446592abe9fdd1e960563f44f551))
* **docker:** enable contrib repo for zfsutils-linux package ([c9fc565](https://github.com/Starosdev/scrutiny/commit/c9fc565b39d529f1f64397784fa4acef3edf9fb1))
* **frontend:** add debounce to sparkline hover to prevent flickering ([e987360](https://github.com/Starosdev/scrutiny/commit/e987360312be7de732a180bb70d6011ad70b7c52)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** disable tooltips on sparkline charts ([853d580](https://github.com/Starosdev/scrutiny/commit/853d5802b6cc9812ca2a1f611f7f9ccb5db91bda)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** prevent tooltip cutoff on sparkline charts ([1377179](https://github.com/Starosdev/scrutiny/commit/13771792c4c8474249bed66618c5430f58124ae3)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use ApexCharts native events for tooltip overflow fix ([0a16d4e](https://github.com/Starosdev/scrutiny/commit/0a16d4e127a2128d14bb5385f1d5c49819fa86ee)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)
* **frontend:** use fixed tooltip position for sparkline charts ([a81e08a](https://github.com/Starosdev/scrutiny/commit/a81e08a6a9331daf1fb3a04d0005da2b909ca04a)), closes [#71](https://github.com/Starosdev/scrutiny/issues/71)

* chore(release): 1.10.1

## [1.10.1](https://github.com/Starosdev/scrutiny/compare/v1.10.0...v1.10.1) (2026-01-20)

### Bug Fixes

* **mock:** enhance ZFS pool management methods in MockDeviceRepo ([c8b22fd](https://github.com/Starosdev/scrutiny/commit/c8b22fdcd6a8fc4f75a09ddb42453318110d2062))

* feat: written and read TBs (#74)

* feat(detail): add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

* fix: other failing tests for TBsStats

* add logicalblocksize Test

* fix broken test due to int64 transmission

* This adds mimetypes to fix issues with forever-loading screen in firefox making the app unusable.

* refactor(detail): update HTML template and TypeScript methods for TB calculations

- Refactored the HTML template to use conditional rendering for device details, improving readability and maintainability.
- Enhanced `getTBsWritten()` and `getTBsRead()` methods to differentiate between ATA and NVMe calculations, ensuring accurate TB calculations based on device type.
- Updated comments for clarity on the logic used in TB calculations.

* feat(detail): rebasing from master, add methods to calculate TBs written and read from LBAs

- Implemented `getTBsWritten()` and `getTBsRead()` methods in DetailComponent to calculate total terabytes written and read based on logical block size and LBA values from SMART results.
- Updated the HTML template to display TBs written and read if available.
- Added `logical_block_size` field to the Smart model to support these calculations.

---------

Co-authored-by: Robin <robin.tschirschnitz@gmail.com>

* chore(release): 1.11.0

## [1.11.0](https://github.com/Starosdev/scrutiny/compare/v1.10.1...v1.11.0) (2026-01-21)

### Features

* written and read TBs ([#74](https://github.com/Starosdev/scrutiny/issues/74)) ([10698c3](https://github.com/Starosdev/scrutiny/commit/10698c32e089fca86f4ab0d2d0ade1b53cdec94b))

* feat(detail): add SSD health metrics to detail component (#96)

* feat(detail): add SSD health metrics to detail component

- Implemented methods to retrieve SSD percentage used and wearout value based on SMART attributes.
- Updated the template to display SSD percentage used and…
Starosdev pushed a commit that referenced this pull request Jan 27, 2026
## [1.17.0](v1.16.3...v1.17.0) (2026-01-27)

### Features

* **api:** improve health check depth with structured response ([#139](#139)) ([#153](#153)) ([494f8f9](494f8f9))
* **backend:** add container CPU quota awareness with automaxprocs ([#133](#133)) ([45a8838](45a8838)), closes [#72](#72) [#82](#82) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#74](#74)
* **config:** make InfluxDB retention periods configurable ([#138](#138)) ([#152](#152)) ([b4c25b1](b4c25b1))
* **diagnostics:** add comprehensive diagnostics for missed ping monitoring ([#160](#160)) ([4a30a50](4a30a50)), closes [#126](#126) [#126](#126)
* **frontend:** improve temperature graph UX ([#40](#40)) ([#145](#145)) ([23912a5](23912a5))
* **notify:** add missed collector ping notifications ([#140](#140)) ([c2d8bb4](c2d8bb4)), closes [#72](#72) [#82](#82) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#74](#74)

### Bug Fixes

* **api:** return attribute override ID after save for UI deletion ([#142](#142)) ([5ef3d0f](5ef3d0f)), closes [#141](#141)
* **docker:** add SYS_ADMIN capability for NVMe device support ([#159](#159)) ([bfddd96](bfddd96)), closes [#26](#26) [#209](#209)
* **security:** prevent Flux query injection via parameterized queries ([#149](#149)) ([0fcb6f5](0fcb6f5)), closes [#135](#135) [#135](#135)
* **validation:** accept serial numbers as WWN fallback for NVMe/SCSI devices ([#158](#158)) ([c4daf08](c4daf08)), closes [#144](#144) [#133](#133) [#72](#72) [#82](#82) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#71](#71) [#74](#74)

### Refactoring

* **backend:** replace fmt.Printf with structured logging ([#136](#136)) ([#150](#150)) ([4369e9a](4369e9a))
* migrate from moment.js to dayjs for date handling ([#147](#147)) ([b6463cc](b6463cc))
@Starosdev Starosdev deleted the feature/SCR-75-zfs-collector-omnibus branch February 7, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant