aaa522058e
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
aaa522058e |
Settings → App config: surface RunMode + FleetIngest push state
ConfigOverviewService now reports the runtime mode and (on Client only)
the fleet-push configuration + live push-state per resource. The token
is reduced to a boolean (TokenConfigured) in the DTO — never a string —
so it cannot be accidentally serialised.
Backend
- FleetIngestInfoDto: { enabled, url, intervalSeconds, batchSize,
batchMaxBytes, tokenConfigured }. No Token property at all.
- FleetPushStateRowDto: { resourceType, lastCursor, lastSyncedAt,
consecutiveFailures, lastError }.
- ConfigOverviewDto gains RunMode (string), nullable FleetIngest +
FleetPushState (null in Admin mode).
- ConfigOverviewService becomes async + injects IServiceProvider so it
can read AppDbContext in Client mode without that DbContext being
required (GetService returns null in Admin mode, where it's not
registered).
- AdminConfigEndpoints awaits the async call.
Tests (+3, 56/56 passing)
- FleetIngestInfoDto has no Token property (reflection check).
- Serialised DTO never contains the literal token value (string scan).
- ConfigOverviewDto's FleetIngest + FleetPushState are nullable so
Admin-mode payloads serialise them as absent rather than empty.
Frontend
- ConfigOverviewCard adds a Run mode row to the Application section
(gold tag for Admin, blue for Client).
- New "Fleet push (Client → Admin)" descriptions card (enabled, token
configured, url, interval, batch sizes) — hidden in Admin mode.
- "Push state per resource" table — resource, last cursor, last sync,
consecutive failures (color-coded), last error.
Verified end-to-end on the dev host
- /api/admin/config-overview on the Client returns runMode=Client +
fleetIngest={enabled,url,interval,batchSize,batchMaxBytes,tokenConfigured}
+ fleetPushState[3] rows (sites/devices/measurements, failures=0).
- The 64-char dev token (from the running Client's .env) is verified
absent from the response body via direct string search.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
e17921a122 |
Add portal: customer-facing white-labeled monitoring stack
New top-level portal/ project, peer to console/ and firmware/. Delivers a .NET 10 + React 18 + TimescaleDB + Grafana stack, one container set per customer behind Traefik. Built in 12 phases per FrontEndPrompt spec; no changes to existing console or firmware. Backend (src/Tau.Acuvim.Portal/): - .NET 10 minimal API, Serilog, ASP.NET Identity (cookie auth, lockout). - Single AppDbContext with identity / app / monitoring schemas. - MigrateAsync + TimescaleBootstrapper (idempotent hypertable creation) + IdentityBootstrapper (seeded admin + branding) on startup. - Pure CostCalculator + DB-backed RateService for tariffs (effective-dated, TOU periods, VAT, fixed charges, per-municipality timezone). - BrandingService with logo upload to mounted volume. - Time-series ingest + bucketed query services (time_bucket aggregates, ON CONFLICT for idempotent re-delivery). - ConfigOverviewService with redaction-by-construction (passwords never in payload). - DataProtection keys persisted to /data/keys volume for cookie survival across container restarts. Frontend (frontend/): - React 18 + TypeScript + Vite + Ant Design 5 + TanStack Query. - BrandingProvider + ThemedRoot for live re-themed white-labelling. - RequireAuth / RequireRole guards. - Pages: Login, Dashboard, Dashboards (embedded Grafana), Sites (admin), Settings tabs (Branding / Rates / Users / Grafana / App config). Infra: - Dev (docker-compose.yml) and prod (docker-compose.prod.yml) compose files. Three services per customer; Traefik subdomain + same-origin /grafana path-prefix routing wired with labels. - Grafana 11 with provisioned timescaledb datasource (uid pinned) and starter power-overview.json dashboard with device template variable. - Compose project name documented as lowercase (Compose v2 requirement). Tests (tests/Tau.Acuvim.Portal.Tests/): - xUnit, 40 tests. Covers CostCalculator (period match, TZ, overlap, VAT, fixed), ConnectionStringResolver (all 4 precedence branches incl. Production refusal), TariffValidator, DayOfWeekFlag. - All passing locally against .NET 10. Docs: - README.md (onboarding + 11 spec sections), OPERATIONS.md (per-customer provisioning, secret rotation, backup, troubleshooting), TESTING.md (manual integration scenarios, frontend test scaffolding recipe). Production safety guards: - Refuses to start if Authentication:DefaultAdminPassword is unchanged default in Production. - Refuses to start if Database:AutoProvisionLocalTimescaleDb=true in Production. - Prod Grafana ships with anonymous off and auth mode unset (three options documented in README Security) so iframe refuses to load until a deliberate prod auth choice is made. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |