Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PoPunkouterSoftware

PoPunkouterSoftware is a .NET 10 Blazor Web App with a server host, a WebAssembly client, and operational endpoints for the Azure inventory report, the app portfolio, and diagnostics.

Solution Layout

  • src/PoPunkouterSoftware.API/: ASP.NET Core host + BFF. Feature slices under Features/<Area>/ (Config, Diag, Portfolio, SignIns); host-level plumbing that belongs to no slice lives in Host/. Hosts the Blazor WASM shell.
  • src/PoPunkouterSoftware.Client/: WASM UI, layouts, pages, and static assets.
  • src/PoPunkouterSoftware.Shared/: contracts and models shared between the host and client.
  • src/PoPunkouterSoftware.Infrastructure/: Azure and integration adapters.
  • tests/PoPunkouterSoftware.Unit/: xUnit, strictly no-I/O.
  • tests/PoPunkouterSoftware.Integration/: WebApplicationFactory + Azurite Testcontainers.
  • tests/PoPunkouterSoftware.E2EAPI/: pure-HTTP contract tests against a live instance.
  • tests/PoPunkouterSoftware.E2EUI/: C# Playwright browser tests (run on demand against a live instance).
  • SCRIPTS/: setup and automation helpers.

Local Development

Prerequisites:

  • .NET SDK from global.json
  • Node.js for Playwright tests
  • Docker Desktop for Azurite-backed integration scenarios

Common commands:

dotnet build .\PoPunkouterSoftware.sln
dotnet test .\tests\PoPunkouterSoftware.Unit
dotnet test .\tests\PoPunkouterSoftware.Integration

Available VS Code tasks in this workspace include:

  • build
  • test-unit
  • start-azurite
  • start-api-server
  • deep-clean (removes every bin/ and obj/; dotnet clean leaves obj/ behind)

The app runs locally on HTTP port 8000.

Runtime Notes

  • /health is the deep probe (Key Vault, Table Storage); /health/live is a static liveness ping.
  • /api/diag/* (summary, report, refresh, cancel-refresh, restart/{name}, ai) expose diagnostics; /diag itself was removed 2026-09-04 — diagnostics surface in the /azure Advanced diagnostics drawer. restart/{name} restarts (or starts) one scanned App Service and sits behind the same management gate as refresh; in Azure it also needs Website Contributor, which infra does not grant.
  • Each scan also reads Azure Resource Health (for down apps), Azure Advisor, 24h exception types per app from the shared Application Insights component (SignIns:ResourceId), and open Dependabot alerts per matched repo (needs Dependabot enabled on the repo and a PAT with "Dependabot alerts: read").
  • Four keyless public APIs feed the scan through the public-api HttpClient: each matched repo's Directory.Packages.props (read with the GitHub PAT) is checked against nuget.org for newer versions and OSV.dev for known advisories; the Azure Retail Prices API prices B1/S1/P0v3 in each app's region; RDAP reads the registration expiry of any custom domain. Each catalog entry in apps.json may set expect, text the live page must contain; a page that answers 2xx without it is flagged. Each entry may also carry a stack block of short labels (frontend, backend, realtime, data, extras = the app's unique tech, ai, signIn, delivery) plus a details map of the same keys holding the full wording, and an aiServices list (cloud, name, use, optional) for the AI column. An entry may also set androidPackage; the nightly scan checks anonymously whether its Google Play page and its githubRepo are public, and the home page links each only once it is — the home page's matrix of how each app is built.
  • Push alerts go through ntfy (Alerts:NtfyTopic): app down/up, failed scan, spend spike, an SSL certificate crossing 14 days, the month-end forecast crossing the budget, a page losing its expect text, a custom domain crossing 30 days to expiry. weekly-digest.yml sends a Monday summary to the same topic. deploy.yml (rollback) and screenshots.yml (Lighthouse drop of 15+ points) send to the same topic via the optional NTFY_TOPIC GitHub secret, falling back to the Key Vault secret.
  • deploy.yml backs up the live site, smoke-tests /health/live, /health and /api/diag/summary after deploying, and redeploys the backup if the smoke test fails.
  • Azure behavior prefers Key Vault and managed identity when available, with local fallback configuration for development.
  • The client dashboard consumes the shared Azure report models generated by the server and infrastructure layers.
  • /settings holds every visitor preference — theme, density, sound and details — in localStorage, each defaulting to the simplest option.

Configuration

appsettings.json holds values only; what each section means lives here. Secrets come from Key Vault kv-poshared2 under the prefix PoPunkouterSoftware-- and are never committed.

Key What it does
AzureBlobStorage:Endpoint Public endpoint of the account holding the app-screenshots container, used on the managed-identity path. screenshots.yml is the only writer; the app only reads. Without it stored screenshots never serve, which looks exactly like none were ever captured. Azurite wins in Development.
ApplicationInsights:ConnectionString Left blank; supplied by the vault secret ApplicationInsights--ConnectionString or APPLICATIONINSIGHTS_CONNECTION_STRING.
FeatureFlags:EnableManagementActions On everywhere so uptime-scan.yml can POST /api/diag/refresh. Production still demands Security:ManagementApiKey, and /api/config reports false there, so no visitor sees a button that would 401.
FeatureFlags:EnableAutoInventoryRefresh A portfolio load with a report older than 12h starts a background rescan (30-min cooldown). Defaults on outside Development/Testing.
FeatureFlags:EnableAiSummary The AI status paragraph on /azure; false falls back to the rule-based narrative.
StatusNarrator:* Azure AI Foundry chat completions on po-aiservices-shared2 (gpt-5.4-nano). Deliberately NOT named AzureAi: the vault's estate-wide AzureAI--* secrets would be picked up case-insensitively and 401 every call. Blank ApiKey means Entra ID (needs Cognitive Services OpenAI User), falling back to the vault's AzureOpenAI--ApiKey.
SignIns:* The /users roster, read live from the shared Application Insights component's traces (UserSignedIn). Needs Monitoring Reader; anything missing degrades to "unavailable", never a 500. WindowDays is capped at 90 (the component's retention).
Budget:MonthlyUsd Monthly ceiling for the /azure forecast. 0 or absent shows the projection with no comparison.
Alerts:* ntfy push alerts. Off while NtfyTopic is blank; on ntfy.sh the topic IS the credential, so set it only through the vault secret PoPunkouterSoftware--Alerts--NtfyTopic. SiteUrl is where a tapped alert opens.
RateLimits:* Global (not per-IP) ceilings on /api/signins and POST /api/diag/ai, the two anonymous endpoints that cost money per call.
Retention:HistoryDays Days before history rows are pruned (0 disables). Blob lifecycle is in infra/main.bicep.
Pinger:* Background sweep that warms cold starts and records daily reachability for the uptime grid. Off means the grid uses scan observations alone.
Security:ManagementApiKey Required in Production when management actions are on — the filter fails closed without it. Vault secret PoPunkouterSoftware--Security--ManagementApiKey, same value as the MANAGEMENT_API_KEY GitHub secret.

Testing Strategy

  • Unit tests (PoPunkouterSoftware.Unit) cover pure logic and API helpers, no I/O.
  • Integration tests (PoPunkouterSoftware.Integration) cover host configuration, diagnostics endpoints, and Azure Table Storage behavior via WebApplicationFactory + Testcontainers Azurite.
  • E2E tests (PoPunkouterSoftware.E2EAPI, PoPunkouterSoftware.E2EUI) cover the HTTP contract and browser flows against a live instance; on demand, not in CI. E2EUI runs axe-core's WCAG 2.1 A/AA rules over every page (Deque.AxeCore.Playwright) and fails on serious or critical violations.
  • Each tier has a hard test budget — 100 Unit, 50 Integration, 25 E2E-API, 25 E2E-UI. Adding a test means removing one; prefer widening an existing test's assertions.

Developer Guidance

  • Read CLAUDE.md before broad changes — it is the single context map. (AGENT.MD was merged into it and deleted; AGENTS.md only points there.)
  • Keep /api/diag/* available but do not link them from the UI — diagnostics surface only in the /azure Advanced diagnostics drawer.
  • Preserve Po-prefixed naming and strict build quality defaults from Directory.Build.props.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages