M7: release polish — export/import, docs, easy docker push
- Easy docker push (MQTTower ergonomics + the image push it lacks): VERSION file → version-tag.yml (semver-guard auto-tag) → docker-publish.yml (buildx multi-arch → GHCR, registry centralized for one-line retarget to git.finalfactory.de) + ci.yml + build-and-push.ps1. - Verified end to end: deploy/Dockerfile builds; docker compose stack (app + timescaledb) comes up healthy; /healthz and the dashboard respond in-container. - JSON config export/import (ExportService) with id remapping on restore + GET /export, POST /import endpoints; round-trip test preserves meter→type, meter-scoped tariff, category links. - README, HA/Tasmota/MQTT wiring guide (docs/wiring.md), Unraid template. - CLAUDE.md updated to reflect the built codebase. - i18n: locale-aware number/currency formatting (de-DE); full de UI string localization deferred. 95 tests green (56 Core + 39 integration). Claude-Session: https://claude.ai/code/session_01WujdMtMJPbxDpDnMeK22rr
This commit is contained in:
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
MeterVault is a self-hosted, local-first energy & utility metering platform: it ingests meter data from Home Assistant, Tasmota and MQTT on a schedule, stores every reading timestamped and immutable, normalizes it into consumption, and turns it into cost dashboards. Energy types (electricity, water, heating oil, gas, …) and meters are **user-defined, never hardcoded**.
|
||||
|
||||
**Status: pre-code.** The repository currently contains only the design spec and reference data — no solution, projects, or build yet. The first coding task is milestone **M0** (scaffold) from the spec.
|
||||
**Status: implemented (M0–M7).** The full solution is built and green — five projects, ~95 tests, working Docker deploy. `docs/SDD.md` remains the design reference; the milestone map (§12) matches the git history (M0…M7 commits). Remaining refinements (HA WebSocket push, dedicated PV/oil dashboard panels, full admin CRUD, full de-DE UI localization) are noted at the end of their milestone commits.
|
||||
|
||||
## Source of truth
|
||||
|
||||
@@ -21,29 +21,42 @@ MeterVault is a self-hosted, local-first energy & utility metering platform: it
|
||||
|
||||
.NET (current LTS — .NET 10, .NET 8 acceptable), C# · ASP.NET Core + **Blazor Server** · **MudBlazor** components · **ApexCharts** (Blazor-ApexCharts) · **MQTTnet** · **PostgreSQL + TimescaleDB** · **EF Core (Npgsql)** for schema/CRUD + **Dapper** for hot-path time-series reads · `BackgroundService` hosted services for ingestion/aggregation · **xUnit + Testcontainers** (Timescale image) · Docker Compose + GHCR.
|
||||
|
||||
## Intended project layout (created during M0, per SDD §11)
|
||||
## Project layout
|
||||
|
||||
```
|
||||
/src/Core domain entities, enums, interfaces, expression evaluator (no infra deps)
|
||||
/src/Infrastructure EF Core + Npgsql, Dapper repos, Timescale raw-SQL migrations, MQTT/HA clients, CSV importer
|
||||
/src/App ASP.NET Core host: Blazor Server UI + REST API + hosted workers
|
||||
/tests/Core.Tests unit: deltas, swaps, tariff resolution, oil rate, CSV parsing
|
||||
/tests/Integration.Tests Testcontainers (Timescale): ingest→aggregate→cost e2e
|
||||
/tests/fixtures the 4 reference CSVs + expected outputs
|
||||
/deploy Dockerfile, docker-compose.yml (app + timescaledb), unraid-template.xml
|
||||
/src/Core domain entities + enums; pure Normalization engine (mode strategies,
|
||||
expression evaluator); Parsing (German dialect); Costing (TariffResolver)
|
||||
/src/Infrastructure MeterVaultDbContext + migrations (relational + raw-SQL Timescale);
|
||||
Import (CsvImporter, profiles, ImportService), Ingestion (MQTT/HA workers,
|
||||
IngestionService), Normalization service, Costing/Dashboard/Backup services
|
||||
/src/App ASP.NET Core host: Blazor Server UI (Components/), REST API (Api/), hosted
|
||||
workers, Program.cs (Serilog, migrate+seed on startup, /healthz)
|
||||
/tests/Core.Tests unit (no Docker): parsers, normalizers, swap→12, tariff resolver
|
||||
/tests/Integration.Tests Testcontainers (Timescale): reconciliation vs the 4 fixtures,
|
||||
import commit/revert, ingestion, cost, CAgg refresh, API, export, render
|
||||
/deploy Dockerfile, docker-compose.yml (app + timescaledb), build-and-push.ps1, unraid-template.xml
|
||||
```
|
||||
|
||||
## Commands (apply once M0 has scaffolded the solution)
|
||||
Central package versions live in `Directory.Packages.props`; shared build/style in
|
||||
`Directory.Build.props` + `.editorconfig`. Snake_case table/column mapping via
|
||||
`UseSnakeCaseNamingConvention`. EF migrations are exempt from code-style enforcement (see `.editorconfig`).
|
||||
|
||||
## Commands
|
||||
|
||||
```powershell
|
||||
dotnet build # build the solution
|
||||
dotnet test # all tests (Integration.Tests needs Docker for Testcontainers)
|
||||
dotnet test tests/Core.Tests # unit tests only (no Docker needed)
|
||||
dotnet test --filter "FullyQualifiedName~Csv" # a single test / class by name filter
|
||||
dotnet run --project src/App # run app + workers locally
|
||||
dotnet test tests/Integration.Tests --filter "FullyQualifiedName~Reconciliation" # one class/area
|
||||
dotnet ef migrations add <Name> -p src/Infrastructure -s src/App -o Persistence/Migrations
|
||||
dotnet run --project src/App # run app + workers locally (needs a Timescale DB)
|
||||
docker compose -f deploy/docker-compose.yml up # app + TimescaleDB together
|
||||
```
|
||||
|
||||
**Timescale-in-EF gotchas** (already handled — follow the pattern): hypertable/CAgg DDL lives in
|
||||
raw-SQL migrations; continuous-aggregate creation + policies use `migrationBuilder.Sql(..., suppressTransaction: true)`, one statement each; CAgg policy `end_offset` must be ≥ one bucket. Tests
|
||||
pause the compression job (historical fixture data would otherwise deadlock imports).
|
||||
|
||||
## Core architecture (the part that spans multiple files)
|
||||
|
||||
**Data pipeline — one direction, layered (SDD §4.2, §5, §7):**
|
||||
|
||||
Reference in New Issue
Block a user