Skip to content

Dashboard: sign-in, setup wizard and administration - #9

Open
koculu wants to merge 3 commits into
mainfrom
feature-dashboard-admin-auth-wizard
Open

koculu wants to merge 3 commits into
mainfrom
feature-dashboard-admin-auth-wizard

Conversation

@koculu

@koculu koculu commented Oct 19, 2026

Copy link
Copy Markdown
Member

Dashboard: sign-in, setup wizard and administration

The dashboard was a single-user development demo: engine options lived in code, sites and the time zone in appsettings.json, and nothing was protected. This PR turns it into an application you can deploy: users and sessions stored in ZoneTree, a first-run setup wizard, and an admin panel where every engine option, index and rollup can be changed.

What changes for someone running the dashboard

  • First run opens a setup wizard. When startup output settles, the console ends with a box holding a setup link, which carries a one-time key. The steps are: administrator account → sites and their domains → time zone → collection preset (Privacy first / Standard / Full detail) → review, where an "Advanced settings" section shows every option. The time zone, data directory, write-ahead-log directory and visitor sketch precision are fixed after setup.
  • Everything requires signing in except the tracker script and the beacon endpoint.
  • Roles: exactly one administrator; other users are analysts (reports and query explorer) or viewers (reports), with access to all sites or only assigned ones.
  • Admin panel (/admin/): server status (engine state, background index builds, partitions), sites, users and their sessions, indexes and rollups, settings, audit log. Saving shows what changes and when each change applies: at once, after a short engine reopen, or after a restart. Changes that delete data need confirmation. If the engine can't open with the new settings, the previous settings are reopened.
  • The topbar account menu uses PureStack's sign-in component, with Account, Account settings, Administration (administrator only) and Sign out.
  • Beacons are assigned to sites by page domain (exact host or *.example.com). Traffic from other domains goes to the primary site or is ignored, depending on a setting. Recording visits to the dashboard itself is optional.

Breaking changes

  • Removed configuration keys: Analytics:DataDirectory, Analytics:TimeZone, Dashboard:Sites, Dashboard:RefreshSeconds. After setup, the stored settings are the source of truth. Server-level options left: Urls, Dashboard:SystemDirectory, Dashboard:Path, Dashboard:Watch, and Analytics:SeedDemo (which now also seeds right after setup).
  • The Connection page and the browser-side overrides of the dashboard config are gone, along with bearer-token support in the UI.
  • DashboardAnalyticsOptions.ConfigurePrimary is gone; that class now configures only the Development sample and benchmark engines.
  • Not exposed in the dashboard at all: the B+tree lock mode, B+tree node and leaf sizes, and Bloom filters.

Implementation

Server (apps/ZoneTree.Analytics.Dashboard/server)

  • System/SystemStore: one ZoneTree<string,string> with the default AsyncCompressed WAL. Users, sessions, settings and the audit log share it through key prefixes. It refuses a non-empty directory it didn't create.
  • Auth/: PBKDF2-SHA256 password hashes. Session tokens are 256-bit random values; the store keeps only their SHA-256. Session cookies are HttpOnly and SameSite=Lax, and Secure over HTTPS. A per-user security stamp ends all of a user's sessions when their role, sites, password or status changes. It also adds an ASP.NET Core authentication handler, a sign-in throttle, and a check that rejects state-changing requests from other origins.
  • Settings/: DashboardSettings is the persisted model. Its [Setting] metadata produces a schema that both the wizard and the admin forms render. SettingsMapper maps settings to AnalyticsOptions and validates them with the engine's rules. SettingsService reviews changes, classifies when each applies and saves them.
  • Engine/EngineHost: requests take a lease on the engine; a reopen waits for leases to end, then reopens, rolling back on failure. EngineMiddleware gives reporting and tracker requests the leased engine by wrapping RequestServices; a scoped registration would dispose the shared engine at the end of each request. It also resolves beacon sites.
  • Setup/: the setup key, the wizard's API, and the console banner.
  • Development sample datasets now record their own time zone, so a dataset created before setup still opens. A sample dataset that fails to open no longer stops the server.
  • server/data/** is excluded from build content; the Web SDK had been copying dataset metadata JSON into the build output.

UI (apps/ZoneTree.Analytics.Dashboard/ui)

  • New pages: /signin/, /signout/, /setup/, /account/, /account/settings/ and /admin/*. Sign-in, sign-out and setup use a new auth template with a theme toggle.
  • Shared helpers: lib/session.ts, lib/settings-model.ts with components/settings-fields.ts (the settings forms built from the schema), lib/admin.ts (review before save), and components/sites-editor.ts.
  • Navigation shown by role; the server enforces access regardless.

Library

  • AnalyticsOptions.Validate() is public: it runs the engine's option checks without opening storage.
  • New AddZoneTreeAnalyticsWeb() registers the web options and reporting limits without an engine, for hosts that replace engines at runtime.

Testing

  • New DashboardAdministrationTests covering:
    • password hashing
    • the single-administrator rule
    • access by role and site
    • sessions: only hashes stored, ended by security changes, survive a restart
    • schema and preset coverage
    • mapping settings to engine options
    • rejecting invalid settings
    • reopening with new settings, data-loss confirmation, refusing changes to fixed settings, persistence
    • rollback when the engine can't open
    • site resolution
    • the setup key
  • The unit test project now references the dashboard server project instead of linking its files. 134 dashboard-related .NET tests pass. The full suite was not run.
  • Web tests: 38 pass. The tracker integration test now completes setup on a fresh host first.
  • Manual end-to-end checks against a running server in Chrome:
    • the wizard
    • signing in
    • every admin page
    • viewer and analyst access
    • beacon site routing
    • persistence across restarts
    • engine reopen with a background index build
    • the setup banner position in watch mode

Analyst-only queries: a viewer now gets 403 on /query, /query/ and /QUERY/; analysts still get through. I attached the analyst requirement to the query endpoint itself instead of matching the URL. The engine middleware now picks the engine from the same kind of endpoint tag, so no check depends on how a URL is spelled.
Sign-in redirects: return URLs with a tab, a newline or a backslash all end on the dashboard's front page after sign-in, and a normal path like /pages/?site=blog is kept. The check now asks the browser's own URL parser and accepts only the same origin. A new web test covers these cases.
Reverse proxies: the server now reads the forwarded headers proxies send, trusting loopback proxies by default. Other proxy addresses go in a new Dashboard:KnownProxies setting, which the dashboard README and docs-site guide now describe. A sign-in through an HTTPS proxy succeeds and gets a Secure cookie, and other origins still get 403.
Sign-in throttle: of 20 simultaneous wrong passwords, 5 get 401 and 15 get 429.
Attempts are counted before the password check.
A second, larger limit per client address stops user-name rotation.
At most half the processors hash passwords at once; extra attempts wait their turn.
@koculu
koculu force-pushed the feature-dashboard-admin-auth-wizard branch from b4b1708 to 9133ba7 Compare October 19, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant