Repository navigation
Add the AVD Dashboards application - #1
Merged
Merged
Conversation
Self-hosted Azure Virtual Desktop dashboards: a Bun container behind Azure Container Apps authentication, backed by Postgres, that reads AVD data from Azure directly or through Nerdio Manager. Multi-tenancy is a first-class concern rather than a later addition — a connection is an Azure service principal or managed identity, an Azure Lighthouse managing tenant, a Partner Center (GDAP) partner tenant, or a Nerdio Manager instance, and they can all feed the same dashboards. Azure and Nerdio records about one host pool merge on the ARM resource id. Onboarding is the part that usually stalls, so the connection wizard generates the exact `az` commands for the roles it needs, then proves the access with a permission checklist before anything syncs. Dashboards are built the same way: pick a question, preview the template against real data, adjust, save. Structure: packages/core metric catalog, dashboard templates, RBAC, schemas packages/db Drizzle schema and migrations packages/connectors one test/discover/sync interface, five implementations packages/demo synthetic data so the app is usable with no tenant apps/server API, EasyAuth, query engine, Postgres job queue, worker apps/web React SPA with the guided builder infra Bicep for Container Apps, Key Vault, Entra-auth Postgres Two things shape the design more than anything else: Tenant scope is enforced where the SQL is built, not in the UI. Widgets reference metric ids from a catalog that lives in code; every value a user can influence is a bound parameter. A viewer scoped to one customer who asks for another gets no rows rather than falling back to everything, and there are tests that assert exactly that. The repository has to stay free of anything identifying a real environment, so gitleaks runs as a pre-commit hook and in CI with rules that fail on tenant and subscription GUIDs, onmicrosoft.com domains and Nerdio instance URLs. Sample data uses Microsoft's fictional companies and placeholder GUIDs throughout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GHCR lowercases image paths, so ${{ github.repository }} on a repository with
capitals publishes somewhere the documentation does not mention. Pin the name
and make every reference — README, deploy docs, deploy script, parameters —
agree with what the release workflow actually pushes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three changes that turn a working app into a product. **The name.** Repository, image path, package scopes and UI all become DashFlow, with a mark and wordmark drawn as SVG so the identity lives in the repo rather than in a design tool. The local database and Azure resource prefix follow. **The design system.** Dark is now the designed default — this is a console people keep open all day — with light designed second rather than inverted. Real elevation ladder, self-hosted Inter with tabular numerals, and a component layer (drawer, modal, popover, toasts, multi-select, sortable paginated table) built in-house so there is no third-party theme to fight. A command palette on ⌘K reaches any dashboard, page or host pool. The validated series palette is untouched: it clears the colour-vision and contrast gates in both modes and should only change by re-running that check. Series colours now follow the entity rather than its array position, so filtering a chart no longer repaints the series that remain — a wrong answer that looked like a styling detail. **The depth.** Widgets can be dragged and resized on a 12-column grid, with the layout saved per widget and dashboards that predate it falling back to flowing by size. Clicking any point, bar or row opens the rows behind it, filtered by whatever was clicked and scoped exactly like the chart query. Widgets take per-dimension filters fed by a new values endpoint. Dashboards can be favourited, duplicated, searched and auto-refreshed. New screens: Explore for ad-hoc questions (URL-encoded, saveable onto a dashboard), host pool and session host pages, an error catalogue with the busiest users beside it, and Settings — which reports the real security posture rather than advice. Finally, `autoscale.actions` was a metric nothing could populate. Rather than leave a dead end, the worker now derives start, stop and drain actions from consecutive host health snapshots, which is true whether the scaling came from an Azure scaling plan, from Nerdio, or from a person. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**A demo anyone can click.** The UI now builds a second way, against a mock API backed by a synthetic estate generated in the browser — no server, no database. That is what ships to GitHub Pages on every merge, and it is the honest kind of demo: the same React app, the same metric catalog, the same dashboards. Keeping it honest needed a second implementation of the catalog in JavaScript, which is a liability unless something checks it. So `packages/demo/src/parity.test.ts` loads one generated dataset into real Postgres and runs identical questions through both the SQL engine and the evaluator — scalars, split series bucket by bucket, breakdown ordering, heatmap cells and a dimension filter. Percentiles interpolate the way `percentile_cont` does, because that is what the test demanded. **Browser tests.** Eight Playwright specs against that demo build, so CI needs no database to prove the app loads, a dashboard renders, drilling opens the records, Explore answers a question, the palette responds to ⌘K, and the theme toggles. **The public face.** A README with the live demo, real screenshots (captured from the demo build, so they can never leak a tenant), an honest comparison against AVD Insights, Workbooks and Nerdio's reporting, and the two claims worth making: tenant scope is enforced where the SQL is built, and the demo cannot drift from the product. Plus a roadmap that says what is not planned, a code of conduct, support and contribution guides, issue and PR templates, a changelog, and a Deploy to Azure button backed by the compiled template. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Self-hosted Azure Virtual Desktop dashboards: a Bun container behind Azure Container Apps authentication, backed by Postgres, reading AVD data from Azure directly or through Nerdio Manager.
What this adds
packages/corepackages/dbpackages/connectorstest/discover/syncinterface; Azure direct, Lighthouse, Partner Center (GDAP), Nerdio, demopackages/demoapps/serverapps/webinfraMulti-tenancy is a first-class concern rather than a later addition: connections can be a service principal or managed identity, an Azure Lighthouse managing tenant, a Partner Center partner tenant, or a Nerdio Manager instance — and they all feed the same dashboards. Azure and Nerdio records about the same host pool merge on the ARM resource id.
Two decisions worth reviewing
Tenant scope is enforced where the SQL is built, not in the UI. Widgets reference metric IDs from a catalog that lives in code, and every value a user can influence is a bound parameter. A viewer scoped to one customer who asks for another gets zero rows rather than falling back to everything.
apps/server/src/query/engine.test.tsasserts that, and that a filter value likeWindows 11'; drop table connection_facts; --is treated as a literal.The repo has to stay free of anything identifying a real environment. gitleaks runs as a pre-commit hook and in CI, with rules that fail on tenant/subscription GUIDs,
onmicrosoft.comdomains and Nerdio instance URLs. Sample data uses Microsoft's fictional companies and placeholder GUIDs.Verified
az bicep buildare clean; gitleaks reports no leaks across the full historyNot verified
Before merging
ghcr.io/BG-Red/AVD_Dashboards, which GHCR lowercases; the README referencesavd-dashboards. Pinimages:in.github/workflows/release.ymlor rename the repo.SECURITY.mdpoints at GitHub private vulnerability reporting — that needs enabling in the repo's security settings.🤖 Generated with Claude Code