Skip to content

Architecture Overview ​

Azure Local Surveyor is a single-page React application that translates the S2D_Capacity_Calculator.xlsx workbook into a typed, versioned, browser-resident planning tool. This page describes the four main layers and how they fit together.


Layers ​

mermaid
graph TB
    User(("User"))

    subgraph UI ["UI Layer — React + React Router"]
        Pages["Pages\nHardwarePage · WorkloadsPage · AvdPage\nSofsPage · AksPage · MabsPage\nVolumesPage · ReportsPage"]
        Components["Components\nHardwareForm · WorkloadPlanner · AvdPlanner\nSofsPlanner · VolumeTable · FinalReport\nCapacityReport · ComputeReport · HealthCheck"]
    end

    subgraph State ["State Layer — Zustand (persisted)"]
        Store["useSurveyorStore\nhardware · advanced · volumes · volumeMode\navd · avdEnabled · sofs · sofsEnabled\naks · mabs · mabsEnabled · virtualMachines\nservicePresets · customWorkloads"]
    end

    subgraph Engine ["Engine Layer — Pure TypeScript"]
        EngFns["capacity.ts · compute.ts · volumes.ts\navd.ts · avd-pools.ts · sofs.ts\naks.ts · mabs.ts · mabs.ts\nworkloads.ts · service-presets.ts\ncustom-workloads.ts · healthcheck.ts\nworkload-volumes.ts · hardware.ts"]
    end

    subgraph Exports ["Export Layer"]
        Exporters["pdf.ts · xlsx.ts · markdown.ts\npowershell.ts · json.ts"]
        Files["Downloads\n.pdf · .xlsx · .md · .ps1 · .json"]
    end

    User --> Pages
    Pages --> Components
    Components <-->|read/write| Store
    Store -->|inputs| EngFns
    EngFns -->|results| Components
    EngFns -->|results| Exporters
    Store -->|inputs| Exporters
    Exporters --> Files

UI Layer ​

As of v2.8.0 (unchanged in 2.9.0), /storage/* and /planning/* form independent planning areas. A React context selects the appropriate Zustand store for all page and component hooks. Workload Planning retains the legacy surveyor-state storage key; Storage Sizing uses surveyor-storage-state. Project restore and storage exports sanitize workload fields. Explicit reviewed copy actions are the only normal UI path that changes inputs in the other area. Legacy routes redirect to Workload Planning.

The shared layout provides stable area navigation and project controls. Specialized workloads have a single navigation home. The recommendations engine evaluates reviewed OEM examples against the shared fit calculation, while the storage exporter uses only storage inputs.

Pages (src/pages/) are React Router route components. Each page initialises its section of the store and delegates planning UI to one or more components.

PageComponents usedPrimary engine call
HardwarePageHardwareForm, AdvancedSettings— (inputs only)
WorkloadsPageWorkloadPlannercomputeCapacity, computeAvd, computeAks, computeSofs, computeMabs, computeWorkloadTotals
AvdPageAvdPlannercomputeAvd
SofsPageSofsPlanner, SofsReportcomputeSofs
AksPageinlinecomputeAks
MabsPageinlinecomputeMabs
VolumesPageVolumeTablecomputeVolumeSummary, computeQuickStart
ReportsPageCapacityReport, ComputeReport, FinalReport, HealthCheck, SofsReportall engine modules

Components (src/components/) are self-contained UI units. They read from the Zustand store, call engine functions for display, and write back to the store on user input. Components never hold derived state — every derived value is computed on each render from the current store snapshot.


State Layer ​

src/state/store.ts is a single Zustand store that is persisted to localStorage with versioned migrations. Every user-editable field lives here; computed results are never stored — they are re-derived on every render.

Store sliceShapeDefault source
hardwareHardwareInputsDEFAULT_HARDWARE in types.ts
advancedAdvancedSettingsDEFAULT_ADVANCED_SETTINGS in types.ts
volumesVolumeSpec[][]
volumeMode"workload" | "generic""workload"
avdAvdInputs (with pools[])single pool, 100 users
avdEnabledbooleanfalse
sofsSofsInputsdefaults in types.ts
sofsEnabledbooleanfalse
aksAksInputs (with aks.enabled)1 cluster, 3 control, 3 workers
mabsMabsInputsdefaults in types.ts
mabsEnabledbooleanfalse
virtualMachinesVmScenarioenabled: false
servicePresetsServicePresetInstance[][]
customWorkloadsCustomWorkload[][]

The store uses version 8 (as of v1.5.0). Migrations run on startup if the persisted version is older; see store.ts for the migration chain.


Engine Layer ​

All engine functions are pure — they take typed inputs and return typed results with no side-effects, no React imports, and no global state. This makes them trivial to test independently and safe to call from both UI components and exporters.

Module dependency graph ​

mermaid
graph LR
    HW["hardware.ts\nvalidateHardwareInputs()"]
    CAP["capacity.ts\ncomputeCapacity()"]
    COMP["compute.ts\ncomputeCompute()"]
    VOL["volumes.ts\ncomputeVolumeSummary()\ntoWacSize()\ncomputeQuickStart()"]
    HC["healthcheck.ts\nrunHealthCheck()"]
    WL["workloads.ts\ncomputeWorkloadTotals()\nvmScenarioTotals()"]
    AVD["avd.ts\ncomputeAvd()\navd-pools.ts"]
    SOFS["sofs.ts\ncomputeSofs()"]
    AKS["aks.ts\ncomputeAks()"]
    MABS["mabs.ts\ncomputeMabs()"]
    SP["service-presets.ts\ncomputeAllServicePresets()\ngetCatalogEntry()"]
    CW["custom-workloads.ts\ncomputeAllCustomWorkloads()"]
    WVOL["workload-volumes.ts\nworkload-driven volume rows"]

    CAP --> VOL
    CAP --> HC
    COMP --> HC
    VOL --> HC
    WL --> HC
    AVD --> WL
    SOFS --> WL
    AKS --> WL
    MABS --> WL
    SP --> WL
    CW --> WL
    CAP --> WVOL
    WL --> WVOL

Key interfaces ​

All input and result types are defined in src/engine/types.ts. The type file is the single authoritative reference for:

  • all *Inputs shapes (user-editable fields)
  • all *Result shapes (engine outputs)
  • shared enums: ResiliencyType, DriveMedia, AvdWorkloadType
  • DEFAULT_HARDWARE and DEFAULT_ADVANCED_SETTINGS constants

Export Layer ​

src/exporters/ contains five export functions, one per format. All exporters are called from FinalReport.tsx and receive the same state object (a Pick<SurveyorState, ...> containing all relevant store slices). Each exporter re-runs the engine to compute a fresh, consistent snapshot — nothing is cached between UI renders and export.

FileFormatKey output
pdf.tsPDFMulti-section report with all planner results
xlsx.tsExcelMulti-sheet workbook with hardware, capacity, workloads, AVD, SOFS
markdown.tsMarkdownHuman-readable planning summary
powershell.tsPowerShellNew-Volume commands for all planned volumes
json.tsJSONVersioned SurveyorPlan manifest (see plan-manifest.md)

The JSON exporter is the primary machine-readable handoff artifact. Its schema is versioned independently of the app version — see plan-manifest.md for the full schema and Ranger integration notes.


OEM Hardware Presets ​

src/engine/presets/ contains static hardware preset files for OEM server models. Selecting a preset in HardwareForm populates the hardware inputs in one click. Model and solution-tier metadata comes from primary OEM documentation. Numeric values are editable planning examples. See OEM planning presets for review dates, sources and the scope of verification.

FileModels
dell-ax.tsAX-670, AX-770, AX-660, AX-760, AX-4510c, AX-4520c
lenovo-mx.tsMX630/MX650 V3 and V4, MX650a V4, MX455 V3 Edge
hpe-proliant.tsDL380 Gen12, DL360 Gen12, DL380 Gen11, DL145 Gen11
dataon.tsAZL-8208i, AZS-7224

Share URL ​

The app supports a share URL that base64-encodes the current Zustand store state into the URL hash. This allows a complete plan to be shared as a single URL without any server-side storage. The share URL is a UI convenience; for durable baseline artifacts use the JSON export.

Released under the MIT License.