PowerHive Codebase Assistant
You are an expert guide for the PowerHive codebase, a Go-based automation platform for managing cryptocurrency mining hardware. Use this skill to understand architecture, navigate code, debug issues, and implement features.
Codebase Overview
PowerHive is a SQLite-backed automation system that discovers miners on local networks, polls their firmware APIs for status and telemetry, and provides a web dashboard for monitoring and control.
**Core Architecture:**
`cmd/automation/` — Application entry point and service orchestration`internal/app/` — Background services (discovery, status polling, telemetry polling)`internal/database/` — SQLite persistence layer with store API`internal/firmware/` — Typed client for miner firmware REST API`internal/server/` — HTTP API + embedded web dashboard`internal/config/` — JSON configuration loader`docs/` — API specifications and implementation plans**Tech Stack:**
Go 1.25.2 with `modernc.org/sqlite` (pure-Go SQLite driver)Standard library HTTP server (no frameworks)Embedded frontend (HTML/CSS/JS in `internal/server/web/`)Step-by-Step Instructions
1. Understanding Architecture Questions
When asked about system architecture or component relationships:
**Read key structural files:**
`cmd/automation/main.go` — Bootstrap sequence and service wiring`internal/app/app.go` — Application struct and service coordination`docs/implementation-plan.md` — High-level design decisions**Map data flow:**
Discovery → Database → Polling Services → HTTP API → DashboardFirmware Client ← All Services (shared HTTP client for miner communication)**Identify integration points:**
`database.Store` — Central data access layer used by all services`internal/firmware.Client` — Firmware API abstraction used by discovery and pollersContext cancellation — Coordinated shutdown across all goroutines2. Debugging Issues
**For discovery problems:**
Read `internal/app/discovery.go` — Network scanning and miner detection logicCheck `enumerateHosts`, `lightScan` worker pools (32 and 8 workers respectively)Verify firmware endpoints: `/api/v1/info`, `/api/v1/model`, `/unlock`, `/apikeys`Review `config.json` — Network subnets and probe timeout settings**For polling issues:**
Status poller: `internal/app/status_poller.go` — `/api/v1/summary` and `/api/v1/perf-summary`Telemetry poller: `internal/app/telemetry_poller.go` — `/api/v1/chains`Note: Telemetry still requires `model.max_preset` to be set (unlike status poller)Check worker pool sizes (default 4 for status) and timeouts in config**For API/database issues:**
Read `internal/database/store.go` and specific files (`miners.go`, `statuses.go`, `telemetry.go`)Check `internal/server/*.go` for HTTP handler logicReview `schema.go` for table structure and relationshipsNote: `ListMiners` now left-joins `statuses` for hydrated responses**For frontend issues:**
Read `internal/server/web/app.js` — Client-side state management and renderingCheck `deriveMinerStatus` function for status display logicAuto-refresh polls every 10 seconds (`AUTO_REFRESH_MS`)3. Implementing Features
**Before writing code:**
1. Read the relevant existing implementation file(s)
2. Review `docs/firmware-api.md` if touching firmware client
3. Check database schema in `internal/database/schema.go`
4. Understand DTO mappings in `internal/server/*.go`
**For new database entities:**
1. Add schema DDL in `schema.go` (use `CREATE TABLE IF NOT EXISTS`)
2. Define Go types in `internal/database/types.go`
3. Implement CRUD methods in new `internal/database/<entity>.go` file
4. Update `Store.Init()` to run new schema statements
**For new API endpoints:**
1. Add route handler in `internal/server/server.go`
2. Define request/response DTOs with validation
3. Implement database operations via `Store`
4. Add corresponding frontend fetch calls in `app.js`
**For new background services:**
1. Create service struct in `internal/app/<service>.go`
2. Implement `Run(ctx context.Context)` method with cancellation support
3. Use worker pools for concurrent operations (see existing pollers)
4. Wire into `app.New()` and `app.Run()` in `cmd/automation/main.go`
4. Code Navigation Patterns
**Finding firmware endpoint usage:**
Search `internal/firmware/client.go` for method definitionsCross-reference with `docs/firmware-api.md` for API specCheck service files in `internal/app/` for invocation patterns**Tracing data persistence:**
Start with `internal/database/types.go` for entity definitionsFind corresponding store methods in `internal/database/<entity>.go`Check callers in `internal/app/` services**Understanding API responses:**
Read `internal/server/*.go` for DTO definitions (`toMinerDTO`, `toStatusDTO`, etc.)Check `formatTime` helper for timestamp formattingReview frontend rendering in `app.js` for expected structure5. Testing Approach
**Currently no automated tests exist. When adding tests:**
**For database layer:**
Use in-memory SQLite (`:memory:`) for test isolationTest `Store` methods with known fixturesVerify constraint handling and null behavior**For firmware client:**
Mock HTTP responses using `httptest.Server`Test JSON marshaling/unmarshaling edge casesVerify timeout and error handling**For server handlers:**
Use `httptest.ResponseRecorder` for request/response testingMock `Store` interface for isolationTest DTO validation and error responsesImportant Constraints
Known Limitations
**Telemetry eligibility:** Telemetry poller still requires `model.max_preset` (unlike status poller). Consider aligning behavior.**No data retention:** Status and telemetry snapshots accumulate indefinitely. Implement cleanup if storage becomes a concern.**No authentication:** Dashboard API is unauthenticated. Add auth layer before production deployment.**No configuration overrides:** Config path and settings are hard-coded. Add flag/env support for multi-environment deployments.**Error surfacing:** Background pollers log errors but don't expose them to UI. Consider adding last-error fields per miner.Code Patterns to Follow
Use context cancellation for all long-running operationsApply worker pools for concurrent network operations (see existing services)Wrap errors with context using `fmt.Errorf("operation: %w", err)`Use nullable SQL types (`sql.NullString`, etc.) with pointer helpers in `database/helpers.go`Validate inputs before database writes (see `updateMinerRequest`, `updateModelRequest`)Dependencies
**Go version:** Module declares 1.25.2 (future). Verify toolchain availability.**SQLite driver:** `modernc.org/sqlite` (pure-Go, large dependency tree)**No third-party frameworks:** Standard library only for HTTP and JSONCommon Tasks
**Add a new miner property:**
1. Update schema in `schema.go` (add column)
2. Add field to `Miner` struct in `database/types.go`
3. Update `UpsertMiner` in `database/miners.go`
4. Modify `toMinerDTO` in `internal/server/*.go`
5. Update frontend rendering in `app.js`
**Add a new firmware endpoint:**
1. Define request/response types in `internal/firmware/types.go`
2. Add client method in `internal/firmware/client.go`
3. Document endpoint in `docs/firmware-api.md`
4. Invoke from appropriate service in `internal/app/`
**Modify polling behavior:**
1. Read existing poller (`status_poller.go` or `telemetry_poller.go`)
2. Adjust worker pool size, timeout, or eligibility logic
3. Update config schema if adding new intervals
4. Test with `config.json` changes
**Debug discovery issues:**
1. Check `config.json` subnets and timeouts
2. Add logging in `discovery.go` (use `slog`)
3. Verify firmware `/api/v1/info` endpoint is reachable
4. Confirm API key generation succeeds (check `markOffline` logic)
Example Usage
**"How does discovery work?"**
Read `internal/app/discovery.go`, explain subnet enumeration → light scan → firmware probes → database upsert → API key generation flow.
**"Why isn't telemetry showing up for new miners?"**
Check if `model.max_preset` is set. Telemetry poller skips miners without it (unlike status poller). Recommend aligning behavior or setting preset first.
**"Add an endpoint to list all models"**
1. Read existing handler pattern in `internal/server/server.go`
2. Add `GET /api/models` route
3. Implement handler calling `store.ListModels()`
4. Define `toModelDTO` mapping
5. Return JSON response
**"The frontend shows duplicate status badges"**
Read `app.js`, check `deriveMinerStatus` function. Likely mapping issue between firmware state and UI badges. Review status DTO structure from API.
Reference Files
**Always consult these when working on related features:**
`docs/firmware-api.md` — Authoritative firmware endpoint spec`config.json` — Runtime configuration defaults`internal/database/schema.go` — Complete database schema`cmd/automation/main.go` — Application bootstrap and shutdown flow