# Contributing Thank you for your interest in contributing to Scrutiny! This is an actively maintained community fork. ## Before You Start - Check [GitHub Issues](https://github.com/Starosdev/scrutiny/issues) for existing issues and planned work - For bug reports or feature requests, please open a GitHub issue first - For large changes, please discuss your approach in an issue before starting work ## Branch Workflow We use a Gitflow-style workflow: - `master` - Production-ready code (protected) - `develop` - Integration branch for features - `feature/SCR-{id}-description` - New features - `fix/SCR-{id}-description` - Bug fixes - `hotfix/SCR-{id}-description` - Urgent production fixes ### Creating a PR 1. Fork the repository and create your branch from `develop` 2. Follow the commit convention: `type(scope): description` 3. Ensure all tests pass 4. Update `README.md` when your change affects the top-level product surface, feature set, supported deployment paths, or published image matrix 5. Submit a PR to `develop` (or `master` for hotfixes) ### Loop Pilot Workflows This repo also has read-only and draft-only loop pilot workflows on `master`. - `loop-pilot-triage.yaml` can run on schedule or via `workflow_dispatch`. - `loop-pilot-pr-babysitter.yaml` and `loop-pilot-dependency-sweeper.yaml` are manual analyzers only. - These workflows publish markdown artifacts and Actions summaries, but they do not commit, push, merge, label, or comment on PRs. ## Code Style - No emojis in code, commits, comments, or documentation - Follow existing code patterns and formatting - Run linting before submitting: `npm run lint` (frontend) ## Project Structure The Scrutiny repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) containing source code for: - Scrutiny Backend Server (API) - Scrutiny Frontend Angular SPA - S.M.A.R.T Collector Depending on the functionality you are adding, you may need to setup a development environment for 1 or more projects. ## Docker Testing Standard For this repo, "local Docker testing" means the Zeus Unraid host, not this Mac. Use Zeus over LAN `192.168.1.33` or NetBird `100.66.106.240` for Docker image builds, compose bring-up, and container validation. Keep native source workflows such as `go run`, `go test`, `npm start`, and `npm test` on your workstation unless the task specifically requires host-level device access from Zeus. # Modifying the Scrutiny Backend Server (API) 1. install the [Go runtime](https://go.dev/doc/install) (v1.25+) 2. download the `scrutiny-web-frontend.tar.gz` for the [latest release](https://github.com/Starosdev/scrutiny/releases/latest). Extract to a folder named `dist` 3. create a `scrutiny.yaml` config file ```yaml # config file for local development. store as scrutiny.yaml version: 1 web: listen: port: 8080 host: 0.0.0.0 database: # can also set absolute path here location: ./scrutiny.db src: frontend: path: ./dist influxdb: retention_policy: false log: file: 'web.log' #absolute or relative paths allowed, eg. web.log level: DEBUG ``` 4. if you need a Dockerized InfluxDB dependency, start it on Zeus rather than on this Mac. ```bash docker run -p 8086:8086 -e INFLUXD_USE_HASHED_TOKENS=false --rm influxdb:2.9 ``` 5. start the scrutiny web server ```bash go mod vendor go run webapp/backend/cmd/scrutiny/scrutiny.go start --config ./scrutiny.yaml ``` 6. open your browser to [http://localhost:8080/web](http://localhost:8080/web) # Modifying the Scrutiny Frontend Angular SPA The frontend is written in Angular. If you're working on the frontend and can use mocked data rather than a real backend, you can follow the instructions below: 1. install [NodeJS](https://nodejs.org/en/download/) 2. start the Angular Frontend Application ```bash cd webapp/frontend npm install --legacy-peer-deps npm run start -- --serve-path="/web/" --port 4200 ``` 3. open your browser and visit [http://localhost:4200/web](http://localhost:4200/web) ## Frontend config initialization rule Frontend code should treat application config as available immediately from defaults, then hydrated asynchronously from `/api/settings`. - `ScrutinyConfigService` is expected to emit a complete default-backed `AppConfig` on first subscription. - Components should not rely on config streams starting as `null` or waiting for router/media events to settle before reading config fields. - Server-loaded settings should merge over defaults so nested config reads remain safe during startup and after login redirects. - Keep defensive guards in route/layout code anyway. Router and media observers can still fire before a component finishes its own local initialization. This avoids startup races where layout or theme code reads `config.layout` before the initial settings request completes. # Modifying both Scrutiny Backend and Frontend Applications If you're developing a feature that requires changes to the backend and the frontend, or a frontend feature that requires real data, you'll need to follow the steps below: 1. install the [Go runtime](https://go.dev/doc/install) (v1.25+) 2. install [NodeJS](https://nodejs.org/en/download/) 3. create a `scrutiny.yaml` config file ```yaml # config file for local development. store as scrutiny.yaml version: 1 web: listen: port: 8080 host: 0.0.0.0 database: # can also set absolute path here location: ./scrutiny.db src: frontend: path: ./dist influxdb: retention_policy: false log: file: 'web.log' #absolute or relative paths allowed, eg. web.log level: DEBUG ``` 4. start a InfluxDB docker container. ```bash docker run -p 8086:8086 -e INFLUXD_USE_HASHED_TOKENS=false --rm influxdb:2.9 ``` 5. build the Angular Frontend Application ```bash cd webapp/frontend npm install --legacy-peer-deps npm run build:prod -- --watch --output-path=../../dist # Note: `build:prod` uses the production configuration. Without it, app will display mocked data for api calls. ``` 6. start the scrutiny web server ```bash go mod vendor go run webapp/backend/cmd/scrutiny/scrutiny.go start --config ./scrutiny.yaml ``` 7. open your browser to [http://localhost:8080/web](http://localhost:8080/web) If you'd like to populate the database with some test data, you can run the following commands: > NOTE: you may need to update the `local_time` key within the JSON file, any timestamps older than ~3 weeks will be automatically ignored > (since the downsampling & retention policy takes effect at 2 weeks) > This is done automatically by the `webapp/backend/pkg/models/testdata/helper.go` script ``` docker run -p 8086:8086 -e INFLUXD_USE_HASHED_TOKENS=false --rm influxdb:2.9 # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/testdata/register-devices-req.json localhost:8080/api/devices/register # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata.json localhost:8080/api/device/0x5000cca264eb01d7/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date.json localhost:8080/api/device/0x5000cca264eb01d7/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date2.json localhost:8080/api/device/0x5000cca264eb01d7/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-fail2.json localhost:8080/api/device/0x5000cca264ec3183/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-nvme.json localhost:8080/api/device/0x5002538e40a22954/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi.json localhost:8080/api/device/0x5000cca252c859cc/smart # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi2.json localhost:8080/api/device/0x5000cca264ebc248/smart go run webapp/backend/pkg/models/testdata/helper.go curl localhost:8080/api/summary ``` # Modifying the Collector ``` brew install smartmontools go run collector/cmd/collector-metrics/collector-metrics.go run --debug ``` # Debugging If you need more verbose logs for debugging, you can use the following environmental variables: - `DEBUG=true` - enables debug level logging on both the `collector` and `webapp` - `COLLECTOR_DEBUG=true` - enables debug level logging on the `collector` - `SCRUTINY_DEBUG=true` - enables debug level logging on the `webapp` In addition, you can instruct scrutiny to write its logs to a file using the following environmental variables: - `COLLECTOR_LOG_FILE=/tmp/collector.log` - write the `collector` logs to a file - `SCRUTINY_LOG_FILE=/tmp/web.log` - write the `webapp` logs to a file Finally, you can copy the files from the scrutiny container to your host using the following command(s) ``` docker cp scrutiny:/tmp/collector.log collector.log docker cp scrutiny:/tmp/web.log web.log ``` # Docker Development Run these commands on Zeus, not on this Mac. ``` docker build -f docker/Dockerfile . -t ghcr.io/starosdev/scrutiny:local docker run -it --rm -p 8080:8080 \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ --device=/dev/sdb \ ghcr.io/starosdev/scrutiny:local /opt/scrutiny/bin/scrutiny-collector-metrics run ``` # Running Tests ## Backend Tests Backend tests require a running InfluxDB container: ```bash docker run -p 8086:8086 -d --rm \ -e DOCKER_INFLUXDB_INIT_MODE=setup \ -e DOCKER_INFLUXDB_INIT_USERNAME=admin \ -e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \ -e DOCKER_INFLUXDB_INIT_ORG=scrutiny \ -e DOCKER_INFLUXDB_INIT_BUCKET=metrics \ -e DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-super-secret-auth-token \ -e INFLUXD_USE_HASHED_TOKENS=false \ influxdb:2.9 go test ./... # Run all tests go test -v ./webapp/backend/pkg/web/... # Run tests in specific package go test -v -run TestFunctionName ./path/to/pkg/ # Run specific test by name go test -coverprofile=coverage.txt ./... # Run with coverage ``` If you use the Dockerized InfluxDB path above, run that container on Zeus. ## Frontend Tests ```bash cd webapp/frontend npm test # Run tests with watch mode npm test -- --watch=false # Run tests once npm test -- --watch=false --browsers=ChromeHeadless # Headless CI mode npx ng test --watch=false --code-coverage # Run with coverage ``` # API Endpoints Use the canonical API contract instead of maintaining partial tables here: - OpenAPI: [docs/openapi.yaml](./docs/openapi.yaml) - Swagger UI: [docs/swagger-ui.html](./docs/swagger-ui.html) - API overview: [docs/API.md](./docs/API.md) - Runtime Swagger UI path: `/docs/api` - Runtime OpenAPI path: `/api/docs/openapi.yaml` - Runtime default: docs/spec require auth unless `web.docs.public=true` The OpenAPI spec is expected to track the active route surface in `webapp/backend/pkg/web/server.go`.