Skip to Content
FrontendDemo Mode

Demo Mode

The demo mode system provides a fully client-side simulation of the ETL pipeline. It makes zero API calls, zero Supabase queries, and zero file uploads. Everything runs from hardcoded data and setTimeout timers.

Purpose

The demo runs on the public landing page (/) without requiring authentication. When a visitor clicks “Preview Demo” in the LandingHero, the useDemoMode hook fires and the same ProgressStepper and ResultsPanel components render with simulated data — giving users a realistic preview of what the pipeline does.

The useDemoMode Hook

File: hooks/useDemoMode.ts

State

{ active: boolean; // Whether the demo is running state: string; // Current pipeline state (idle/uploading/analyzing/extracting/complete) progress: JobProgress; // Full progress object, same shape as real pipeline start: () => void; // Begin simulation reset: () => void; // Stop and clear }

How It Works

  1. Calling start() sets active = true and begins stepping through DEMO_STEPS
  2. Each step updates state and progress with new values, then schedules the next step via setTimeout with the step’s delay
  3. Milestones accumulate exactly like the real pipeline — each step adds a new Milestone entry with Date.now() timestamp
  4. When the final step is reached (complete), the simulation stops
  5. Calling reset() clears the timeout, resets all state to defaults, and sets active = false
  6. The timer is cleaned up on component unmount via a useEffect return

The 23 Demo Steps

The simulation runs through 23 scripted steps with carefully timed delays:

#StatePctMessageDelay
1uploading5Uploading your File…600ms
2analyzing8Opening your File…800ms
3analyzing12Reading the File…500ms
4analyzing15Found 3 Sheets with 1,231 rows700ms
5analyzing16Scanning 3 Sheets for Tables1200ms
6analyzing19Found 5 Tables across 3 Sheets600ms
7analyzing22Picking the primary data Sheet2000ms
8analyzing25Looking at column headers…1500ms
9analyzing28Identifying charge layout per Table1200ms
10analyzing32Mapping columns to schema…1000ms
11analyzing38Locking in the layout…500ms
12analyzing40Found: Montrose at Vintage Park (02/10/2025)800ms
13extracting50Extracting Units in 6 passes…800ms
14extracting53Reading through each Table1500ms
15extracting55Got 18 Units so far…1500ms
16extracting62Got 36 Units so far…2000ms
17extracting68Got 54 Units so far…1800ms
18extracting75Got 72 Units so far…2000ms
19extracting82Got 89 Units so far…1500ms
20extracting88Found 106 Units1000ms
21extracting92Validating 106 Units600ms
22extracting95Building your clean File…500ms
23complete100All done!0ms

Total simulated duration is approximately 20 seconds.

Message Flow with Entity Terminology

The milestone messages deliberately use the Sheet/Table/Unit hierarchy to teach users the pipeline’s mental model:

FileSheetsTablesUnitsClean Output

  1. Sheets are discovered first (the raw Excel worksheets)
  2. Tables are found within Sheets (distinct data regions)
  3. Units are extracted from Tables (individual apartment/unit records)

These entity terms are color-coded by the ProgressStepper component’s colorizeMessage function.

Demo Property Data

At step 12 (40% progress), the demo reveals the detected property:

FieldValue
Property NameMontrose at Vintage Park
Report Date2025-02-10
Original FilenameMontrose_RentRoll_Feb2025.xlsx
File Size380,000 bytes
Total Rows1,231

Demo Results

When the simulation reaches complete, the progress object is populated with final results:

FieldValue
unit_count106
error_count1
warning_count5
total_chunks6

Unit Breakdown

{ "successful": 100, "flagged": 5, "failed": 1, "total": 106 }

Errors

  • Unit 2107: missing lease end date

Warnings

  • Row 45 (unit=2205): total_charges (1525) != sum (1525.00)
  • Row 18 (unit=1402): Occupied unit with zero base rent
  • Row 67 (unit=2501): duplicate unit_id '2501'
  • Row 89 (unit=3102): total_charges (1450) != sum (1415.00)
  • Row count mismatch: extracted 106 units but expected ~112 from data range

Demo Comparison Data

The DEMO_COMPARISON_DATA array contains 6 hardcoded ComparisonUnit objects representing Units from the Montrose property. These are used when the user clicks “Compare Source & Output” on the demo results panel.

Units

Unit IDStatusTenantSqftFloor PlanKey Details
1101OccupiedJohnson, Sarah842A1Base rent $1,195, pet fee $35
1102Vacant842A1Market rent only, no charges
1203OccupiedMartinez, David & Ana1124B2Base rent $1,600, pet $70, parking $75
2107OccupiedChen, Wei756S1Missing lease end date (flagged as error)
2205NoticePatel, Ravi1124B2Has move-out date 03/15/2025
3301OccupiedWilliams, Tanya982A2Has concession -$100

Difference Types

Each Unit includes a differences array showing what changed between source and cleaned output:

TypeMeaningExample
transformedValue was reformatted or normalized"OCC" becomes "Occupied", "$1,250.00" becomes 1250, "01/15/2024" becomes "2024-01-15"
missingExpected value was not found in sourceUnit 2107 has no lease end date in the source

Color-Coded Entity System

Throughout the demo (and the real pipeline), three entity types are visually distinguished in milestone messages:

EntityColorToken / HexUsage
FileDarktheme.other.textPrimaryThe uploaded file
SheetGreentheme.other.greenAccent (#2e6b4f)Excel worksheets
TableBrowntheme.other.brownAccent (#6b5c3e)Data regions within Sheets
UnitBluetheme.other.blueAccent (#3d8ab5)Individual apartment/Unit records

These colors are applied by ProgressStepper’s colorizeMessage function, which splits messages on /(File|Sheets?|Tables?|Units?)/g and wraps matches in styled <Text> spans with fw={600} (semibold) and fs="italic". The <E> and <Flow> components in this documentation mirror that same color system.

Integration

The landing page (/) wires everything together:

const demo = useDemoMode(); // In the JSX: {!demo.active && <LandingHero onPreviewDemo={demo.start} />} {demo.active && demo.state !== "complete" && ( <ProgressStepper pipelineState={demo.state} progress={demo.progress} /> )} {demo.state === "complete" && ( <ResultsPanel progress={demo.progress} jobId="demo" onReset={demo.reset} isDemo /> )}

When isDemo is true, the ResultsPanel disables the download button and the ComparisonView uses DEMO_COMPARISON_DATA instead of fetching from the API.

Last updated on