StormWater Inspection Module — Complete Business Logic Reference
Overview: Comprehensive guide to StormWater inspection scheduling, workflows, status management, and dashboard functionality. This reference explains how inspections are triggered, tracked, and managed throughout their lifecycle.
Last Updated: February 2026
Table of Contents
- Key Terms & Definitions
- Inspection Types
- Project Types: Fluid vs Non-Fluid
- Inspection Frequencies
- Routine Inspection Scheduling — Non-Fluid Projects
- Routine Inspection Scheduling — Fluid Projects (Twice-a-Week)
- Post-Rainfall Inspection — Precipitation-Based (Non-Event)
- Rainfall Event Inspection — ENVR Event-Based
- Dashboard Card Logic: Inspections Due, Past Due, Missed, Draft
- Inspection Submission & Rescheduling Logic
- Deferral Logic
- Timezone-Based Scheduling
- Comparative Summary Tables
- Scenario Walkthroughs
1. Key Terms & Definitions
1.1 Inspection Item Statuses
| Status | ID | Description |
|---|---|---|
Draft | 1 | Inspector has saved but not submitted |
Open | 2 | Has open corrective action items |
Closed | 3 | All actions resolved |
Submit | 5 | Successfully submitted/completed |
NA | 6 | Not applicable |
SubmitForReview | 7 | Submitted, awaiting review |
ActionPending | 8 | Inspection is due and awaiting completion by inspector |
Scheduled | 9 | Future-dated inspection, not yet actionable |
Missed | 10 | Inspection was not completed within the allowed window |
SubmittedByOther | 11 | Submitted by another inspector |
NotScheduled | 12 | Placeholder for fluid twice-a-week 2nd term (not yet active) |
1.2 Inspection Types
| Type | ID | Description |
|---|---|---|
Routine | 1 | Scheduled routine inspection (calendar-based) |
PostRainfall | 2 | Triggered by rainfall exceeding threshold |
Routine_PostRainfall | 3 | Combined — can satisfy both routine and post-rainfall requirements |
1.3 Inspection Frequencies
| Frequency | ID | Scheduling Rule |
|---|---|---|
Daily | 1 | Every calendar day |
Weekly | 2 | Once per week on a fixed InspectionDay (0=Sun … 6=Sat) |
Monthly | 3 | Once per month on a fixed day of the month |
Quarterly | 4 | Once every 3 months on a fixed day |
TwiceAWeek | 5 | Two inspections per week — behavior differs for Fluid vs Non-Fluid |
BiWeekly | 6 | Once every 14 days on a fixed day of the week |
Custom | 7 | Every N days (FrequencyInDays) from the start date |
1.4 Dashboard Cards
| Card Name | ID |
|---|---|
InspectionsDue | 1 |
PastDueInspections | 2 |
Draft | 3 |
OpenItems | 4 |
1.5 Rainfall Event Statuses
| Status | ID | Description |
|---|---|---|
Active | 0 | Rainfall event is ongoing |
InActive | 1 | Rainfall event has ended (4 consecutive zero-precipitation hours) |
1.6 Setup Statuses
| Status | ID | Description |
|---|---|---|
defaultSetup | 0 | Normal active setup created by admin |
setupCreatedByInspection | 1 | Setup auto-created during ad-hoc "Add Report" submission |
2. Inspection Types
2.1 Routine Inspections (Type = 1)
- Calendar-driven inspections generated by the scheduler.
- The scheduler (
GetTodayRoutineInspection) runs once per timezone window (EST → CST → MST → PST) daily. - Only projects with
InsTypeId = Routine (1)orRoutine_PostRainfall (3)are included. - Scheduling is purely based on frequency and the configured inspection day(s).
2.2 Post-Rainfall Inspections (Type = 2)
- Triggered when precipitation data from the previous day exceeds the project's
RainfallThreshold. - Generated by the scheduler (
GetTodayInspection) using daily precipitation records fromSwProjectPrecip. - Only projects with
InsTypeId = PostRainfall (2)orRoutine_PostRainfall (3)are included. - Non-event states only — states where
IsEventSwInsis NOT true use this path.
2.3 Routine + Post-Rainfall Combined (Type = 3)
- Projects configured as
Routine_PostRainfallparticipate in both the routine scheduler and the post-rainfall/event scheduler. - For Fluid projects, when a rainfall event triggers an inspection, the
InsTypeIdis forced toRoutine_PostRainfall (3)regardless of the setup's original type. This satisfies both the routine and rainfall inspection requirement in a single report.
3. Project Types: Fluid vs Non-Fluid
The IsFluid flag on the SwProject entity fundamentally changes how twice-a-week inspections are scheduled and how submission/rescheduling behaves.
| Feature | Non-Fluid | Fluid |
|---|---|---|
| Twice-a-Week Days | Fixed to InspectionDay and InspectionDay2 from setup | Dynamic — 1st always on Monday, 2nd flexible |
| InsTerm Field | Empty string ("") | "1" for first, "2" for second inspection of the week |
| Future Scheduling | Pre-scheduled on both configured days for 3 months | Only Monday inspections pre-scheduled for next 3 weeks |
| Submission Behavior | All ActionPending inspections for same config are deleted | Only the first ActionPending inspection is deleted |
| Inspection Day Changes on Submit | Yes — setup's InspectionDay updates to the day of submission | No — for TwiceAWeek; Yes — for other frequencies |
| Sunday Visibility | Visible | Hidden from dashboard on Sundays |
| PostRainfall Type Override | No — keeps original InsTypeId | Yes — forced to Routine_PostRainfall (3) |
4. Inspection Frequencies
4.1 Daily (FrequencyId = 1)
Scheduling: An inspection is generated every calendar day.
Special "Daily Report" Mode: If the setup has no Question Set selected (QuestionSetId == null || 0) and is not external, it operates as a "Daily Report" with different handling:
- One inspection per month (not per day) is created in the
SwInstable. - Individual daily data points are tracked via
SwInsDailyReportentries. - The single monthly inspection's
ScheduleDateis updated to today each day. - Prior month inspections are marked
Missedif stillActionPending.
Standard Daily: If a Question Set is selected, a new SwIn record is created each day with Status = ActionPending.
4.2 Weekly (FrequencyId = 2)
Scheduling: Fires on the configured InspectionDay (day of week: 0=Sunday … 6=Saturday).
Trigger condition: currentDayOfWeek == setup.InspectionDay
Future scheduling: 3 future inspections are pre-scheduled with Status = Scheduled.
Missed logic: Previous ActionPending inspections with ScheduleDate < today are marked Missed when the next inspection is generated.
4.3 Twice-a-Week (FrequencyId = 5)
This frequency has two completely different behaviors depending on whether the project is Fluid or Non-Fluid. See Sections 5 and 6 for detailed breakdowns.
4.4 Bi-Weekly (FrequencyId = 6)
Scheduling: Fires on the configured InspectionDay (day of week), but only if at least 14 days have passed since the last inspection.
Trigger condition: currentDayOfWeek == setup.InspectionDay AND the most recent previous inspection's ScheduleDate + 14 days > today check fails (i.e., 14+ days have elapsed).
Future scheduling: 3 future inspections are pre-scheduled with Status = Scheduled.
4.5 Monthly (FrequencyId = 3)
Scheduling: Fires when currentDay == setup.InspectionDay (day of month, e.g., the 15th).
Future scheduling: 3 future inspections are pre-scheduled.
4.6 Quarterly (FrequencyId = 4)
Scheduling: Fires when currentDay == setup.InspectionDay AND the current month aligns with the quarterly cycle based on InspectionMonth.
Quarter calculation: Starting from InspectionMonth, the system checks if the current month is InspectionMonth, InspectionMonth + 3, InspectionMonth + 6, or InspectionMonth + 9 (wrapping around at 12).
Future scheduling: 3 future inspections are pre-scheduled.
4.7 Custom (FrequencyId = 7)
Scheduling: Fires every N days (FrequencyInDays) calculated from the InspectionStartDate.
Trigger condition: (today - InspectionStartDate).TotalDays % FrequencyInDays == 0
Future scheduling: 3 future inspections are pre-scheduled.
5. Routine Inspection Scheduling — Non-Fluid Projects
5.1 Entry Point
The scheduler calls GetTodayRoutineInspection() which:
1. Queries all active setups with InsTypeId = Routine (1) or Routine_PostRainfall (3).
2. Filters setups whose frequency matches today (see frequency rules above).
3. For each matching setup, processes the inspection.
5.2 Processing Flow for Each Setup (Non-Fluid, Non-TwiceAWeek)
1. Update today's existing Scheduled inspection → ActionPending
2. Update rainfall amount from yesterday's precipitation data
3. Mark old ActionPending inspections (ScheduleDate < today) → Missed
4. If no inspection exists for today → Create new SwIn with Status = ActionPending
5. Pre-schedule next 3 future inspections with Status = Scheduled
5.3 Processing Flow for Non-Fluid Twice-a-Week
Since isFluid == false, the standard processing path is followed:
- Both
InspectionDayandInspectionDay2are used to determine if today is an inspection day. - Inspections are created/scheduled on both fixed days.
- The
GetNextInspectionDaterecursive method generates future dates for both days each week. InsTermis set to empty string.- Old
ActionPendinginspections are markedMissed. - 3 future inspections (covering both days) are pre-scheduled.
5.4 Missed Marking (Non-Fluid Routine)
When: Every time the scheduler runs for a setup.
Condition: ScheduleDate < today AND Status == ActionPending AND same SetupId
Action: Status is changed to Missed (10).
This means: If an inspector does not complete a weekly inspection by the day the next one generates, it automatically becomes Missed.
6. Routine Inspection Scheduling — Fluid Projects (Twice-a-Week)
Fluid twice-a-week inspections have a completely unique scheduling model.
6.1 Key Concepts
- Weekly cycle: Sunday through Saturday.
- Two terms per week: Term 1 and Term 2, tracked via the
InsTermfield. - Dynamic scheduling: The second inspection's activation day depends on when conditions are met.
- Scheduler runs daily for fluid TwiceAWeek setups (the filter
m.isFluid == truebypasses the day-of-week check).
6.2 Monday or First Run of the Week
When DayOfWeek == Monday OR no inspections exist for the current week:
1. Mark all ActionPending inspections from PRIOR weeks → Missed
2. If an existing Scheduled inspection for this week exists:
→ Update its Status from Scheduled → ActionPending (Term 1)
Else:
→ Create new inspection: InsTerm = "1", Status = ActionPending
3. If today is NOT Friday AND no Term 2 exists for this week:
→ Create new inspection: InsTerm = "2", Status = NotScheduled
4. Pre-schedule next 3 weeks (Monday dates) with Status = Scheduled
Term 1: Created as ActionPending — immediately visible on dashboard.
Term 2: Created as NotScheduled (12) — NOT visible on dashboard yet.
6.3 Term 2 Activation (Tuesday through Friday)
The second inspection becomes ActionPending (visible) when specific conditions are met:
On Tuesday, Wednesday, or Friday:
- Condition: The week has exactly 2 inspections where both are either
SubmitorNotScheduled. - This means: Term 1 was submitted, and Term 2 is still
NotScheduled→ activate Term 2.
On Thursday:
- Condition: The week has exactly 1 inspection that is either
ActionPendingorSubmit. - This means: If only one inspection exists or Term 1 is still pending, activate Term 2 on Thursday regardless.
Activation action: The NotScheduled Term 2 inspection is updated to ActionPending.
6.4 Missed Marking (Fluid Twice-a-Week)
When: At the start of each new week (Monday processing).
Condition: ScheduleDate < thisWeekStart AND Status == ActionPending AND same SetupId
Action: Status changed to Missed (10).
Key difference from Non-Fluid: Missed marking only happens for inspections from prior weeks, not just prior days. This gives the inspector the entire week to complete both terms.
6.5 Sunday Handling
Fluid TwiceAWeek inspections are completely hidden from the dashboard on Sundays:
!(currentDate.DayOfWeek == DayOfWeek.Sunday
&& frequency.InsFrequencyId == InspectionFrequencyId.TwiceAWeek
&& project.IsFluid == true)
6.6 Friday Handling
On Fridays, Term 1 inspections that are still ActionPending are included in the Past Due count. This creates urgency to complete them before the weekend.
7. Post-Rainfall Inspection — Precipitation-Based (Non-Event)
This applies to states where IsEventSwIns is NOT true (i.e., rainfall inspections are based on daily precipitation data, not real-time ENVR events).
7.1 Trigger Mechanism
The scheduler (GetTodayInspection with IsEventSwIns = null/false) runs daily and:
1. Queries all active setups with InsTypeId = PostRainfall (2) or Routine_PostRainfall (3).
2. Retrieves precipitation data from SwProjectPrecip for the period from Friday (if Monday) or yesterday to today.
3. For each setup: if any precipitation record exceeds the project's RainfallThreshold → generate inspection.
7.2 Deduplication
Before generating, the system checks:
- If an
ActionPendinginspection already exists for today with the same SetupId → skip (no duplicate).
7.3 Missed Marking
Previous ActionPending inspections with ScheduleDate < today for the same setup are marked Missed.
This is a key difference from event-based inspections — non-event rainfall inspections DO get marked as Missed automatically.
7.4 Inspection Creation
Status = ActionPending
ScheduleDate = today
InsTypeId = setup's original InsTypeId (no override)
RainEventId = 0 (no event association)
Rainfall = the actual precipitation amount that exceeded threshold
7.5 After Post-Rainfall Processing
The system then calls GetTodayRoutineInspection() to also process routine inspections for the same timezone. This ensures both rainfall-triggered and routine inspections are handled in a single scheduler run.
8. Rainfall Event Inspection — ENVR Event-Based
This applies to states where IsEventSwIns = true. These inspections are driven by real-time rainfall data from the ENVR/EvenTrack weather API.
8.1 Trigger Mechanism
A separate Lambda function (GenerateRainafallSwInspection in RainfallBusinessLogic) runs on a scheduled basis (typically hourly) and:
1. Queries all active setups with InsTypeId = PostRainfall (2) or Routine_PostRainfall (3) in states where IsEventSwIns = true.
2. Calls the ENVR API (GetPrecipLastHourData) to get the last hour's precipitation for each project's weather account.
3. Manages rainfall events and potentially generates inspections.
8.2 Rainfall Event Lifecycle
┌─────────────────────────────────────────────────────────────┐
│ RAINFALL EVENT LIFECYCLE │
├─────────────────────────────────────────────────────────────┤
│ │
│ [API returns Precip > 0, No active event] │
│ ↓ │
│ CREATE new SwInsRainEvent (Status = Active) │
│ CREATE SwInsRainEventDatum (hourly data point) │
│ ↓ │
│ [Cumulative precip >= RainfallThreshold?] │
│ YES → GENERATE INSPECTION │
│ NO → Continue monitoring │
│ │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ │
│ [API returns Precip > 0, Active event exists] │
│ ↓ │
│ ADD SwInsRainEventDatum (new hourly data point) │
│ UPDATE event EndDateTime │
│ ↓ │
│ [Cumulative precip just crossed RainfallThreshold?] │
│ YES → GENERATE INSPECTION (first time crossing only) │
│ NO → Continue monitoring │
│ │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ │
│ [API returns Precip = 0, Active event exists] │
│ ↓ │
│ ADD SwInsRainEventDatum (zero reading) │
│ INCREMENT consecutive zero count │
│ ↓ │
│ [4 consecutive zero readings?] │
│ YES → DEACTIVATE event (Status = InActive) │
│ NO → Continue monitoring │
│ │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ │
│ [API returns Precip = 0, No active event] │
│ → IGNORED (no action taken) │
│ │
└─────────────────────────────────────────────────────────────┘
8.3 Inspection Generation from Events
When GenerateInspection is triggered:
1. It calls SwAdminInspection.GetTodayInspection(timeZone: null, IsEventSwIns: true, projectList).
2. Inside GetTodayInspection, for event-based inspections:
- No deduplication check — a new inspection is created every time the threshold is crossed, even if one already exists for today.
- No missed marking — the
if (IsEventSwIns != true)block skips both deduplication and missed-marking logic. - No routine inspection generation — the
GetTodayRoutineInspection()call is also skipped whenIsEventSwIns == true.
8.4 Event-Based Inspection Details
Status = ActionPending
ScheduleDate = today (weekday) OR next Monday (if Saturday/Sunday)
InsTypeId = Routine_PostRainfall (3) for Fluid projects, original type for Non-Fluid
RainEventId = the associated SwInsRainEvent.RainEventId
Rainfall = cumulative precipitation from the event
8.5 Weekend Handling
If a rainfall event triggers an inspection on Saturday or Sunday, the ScheduleDate is set to the next Monday:
if (IsEventSwIns == true && ((int)currentDate.DayOfWeek == 6 || (int)currentDate.DayOfWeek == 0))
{
inspection.ScheduleDate = nextMonday;
}
8.6 Event Capture (Updating Existing Inspections)
After generating new inspections, CaptureRainfallEvent updates all existing ActionPending and Draft inspections for the same project with the latest rainfall data:
RfEventAmt→ current cumulative precipitationRfEventDate→ current timestampRfEventAmtPrv→ previous precipitation value (shifted)RfEventDatePrv→ previous date (shifted)RfEventDuration→ hours since event startRainfall→ updated to latest cumulative value
This means inspections that were already on the dashboard get their rainfall data continuously updated as the event progresses.
8.7 Two Events on the Same Day
If two separate rainfall events occur on the same day (Event 1 ends, Event 2 starts):
| Step | Event 1 Inspection | Event 2 Inspection |
|---|---|---|
| Event 1 threshold crossed | Created: ActionPending, RainEventId = Event1 | — |
| Event 1 ends (4 zero hours) | Still ActionPending, no status change | — |
| Event 2 threshold crossed | No status change — still ActionPending | Created: ActionPending, RainEventId = Event2 |
| Result | Both appear on dashboard as "Inspections Due" |
The first inspection is NOT moved to Missed or Past Due when the second event fires. There is no code path that changes the status of existing event-based inspections when new events occur.
9. Dashboard Card Logic: Inspections Due, Past Due, Missed, Draft
9.1 Base Query (Common to All Cards)
All dashboard cards share the same base query that filters:
SwInsSetup.IsActive = true AND IsDeleted = false
SwIn.IsDeleted = false
SwIn.ScheduleDate <= today
SwIn.Status IN (ActionPending, Draft)
Additional filters:
- User/team assignment matching
- Organization matching
- Fluid TwiceAWeek inspections are hidden on Sundays
9.2 Inspections Due (Card 1)
Definition: Total count of all inspections matching the base query.
Formula: COUNT(all records from base query)
This includes ALL ActionPending and Draft inspections with ScheduleDate <= today, regardless of how overdue they are. Past Due and Draft inspections are subsets of this total.
9.3 Past Due (Card 2)
Definition: Inspections that have exceeded their expected completion window.
Formula (broken down by type):
| Inspection Type | Past Due Condition |
|---|---|
| Non-event, any frequency (RainEventId = null or 0) | ScheduleDate < today |
| Event-based (RainEventId > 0) | today >= ScheduleDate + 2 days |
| Fluid TwiceAWeek, Term 1 | Only on Fridays: DayOfWeek == Friday AND InsTerm == "1" |
| Fluid TwiceAWeek, any term | ScheduleDate.DayOfWeek == Saturday (i.e., carried over from prior week) |
| Non-Fluid, non-TwiceAWeek | Standard ScheduleDate < today rule applies |
Key insight: Event-based inspections get a 2-day grace period before appearing as Past Due. Non-event inspections become Past Due the very next day.
9.4 Draft (Card 3)
Definition: Inspections saved but not yet submitted.
Formula: Status == Draft (1)
9.5 Missed (Not a Dashboard Card — Background Status)
Important: "Missed" is NOT a visible dashboard card. It is a status (10) that inspections are moved to by the scheduler, effectively removing them from the dashboard entirely.
Once an inspection is marked Missed, it no longer appears in any dashboard card because the base query only includes ActionPending (8) and Draft (1).
9.6 Complete Dashboard Card Comparison
| Card | Non-Event Routine | Event-Based (Rainfall) | Fluid TwiceAWeek |
|---|---|---|---|
| Inspections Due | ScheduleDate <= today AND (ActionPending OR Draft) | Same | Same, except hidden on Sunday |
| Past Due | ScheduleDate < today | ScheduleDate + 2 days <= today | Friday: Term 1 is Past Due; Saturday-dated: always Past Due |
| Draft | Status == Draft | Same | Same |
| Missed | Auto-marked by scheduler when next inspection generates | Never auto-marked (code commented out) | Auto-marked at start of new week for prior week's inspections |
10. Inspection Submission & Rescheduling Logic
10.1 Non-Fluid Project Submission
When an inspection is submitted (Status → Submit):
If submitted on the scheduled day (InspectionDay matches current day):
- All other
ActionPendinginspections with the same configuration are soft-deleted. - No rescheduling needed — future inspections are already on correct days.
If submitted on a different day than scheduled (early submission of a Scheduled inspection):
1. The inspection's ScheduleDate is updated to today.
2. The setup's InspectionDay is updated to the current day of the week.
3. All existing Scheduled future inspections for this setup are deleted.
4. New future inspections are generated based on the new inspection day.
This means: For Weekly, BiWeekly, Monthly, and Quarterly non-fluid inspections, submitting early permanently changes the inspection schedule to the new day.
10.2 Fluid Project Submission (Twice-a-Week)
Same-day duplicate prevention: If an inspection has already been submitted or saved as draft for the current date in this week, a validation error is returned: "Inspection has already been completed for this date".
When submitting via "Add Report" (direct inspection):
- The first
ActionPendingorScheduledinspection in the current week is soft-deleted. - The submitted inspection takes the deleted inspection's
InsTerm.
No day rescheduling occurs for TwiceAWeek fluid inspections — the system deliberately skips rescheduling for this frequency.
10.3 Fluid Project Submission (Non-TwiceAWeek Frequencies)
For fluid projects with Weekly, Monthly, etc.:
- All
ActionPendinginspections for matching setups (excludingPostRainfallandTwiceAWeek) are deleted. - If the submission day differs from the setup's
InspectionDay: - All
Scheduledfuture inspections are deleted. - Setup's
InspectionDayandInspectionMonthare updated. - New future inspections are rescheduled from the new day.
10.4 Non-Fluid Project Submission (Add Report / Direct Inspection)
When submitted via "Add Report" (IsDirectIns = true):
- All
ActionPendinginspections for matching setups (same project, question set, frequency, type) are soft-deleted.
10.5 Submission Impact on Inspection Day — Summary Table
| Project Type | Frequency | Submitted on Scheduled Day | Submitted on Different Day |
|---|---|---|---|
| Non-Fluid | Weekly | No change | InspectionDay → current DayOfWeek; reschedule future |
| Non-Fluid | BiWeekly | No change | InspectionDay → current DayOfWeek; reschedule future |
| Non-Fluid | Monthly | No change | InspectionDay → current Day; reschedule future |
| Non-Fluid | Quarterly | No change | InspectionDay → current Day; InspectionMonth → current Month; reschedule future |
| Non-Fluid | TwiceAWeek | No change | InspectionDay → current DayOfWeek; reschedule future (both days) |
| Non-Fluid | Custom | No change | Reschedule from current day |
| Fluid | TwiceAWeek | No change | No change — TwiceAWeek is explicitly skipped |
| Fluid | Weekly | No change | InspectionDay → current DayOfWeek; reschedule future |
| Fluid | Other | No change | InspectionDay updated; reschedule future |
| Any | PostRainfall | Never rescheduled | Never rescheduled — PostRainfall is explicitly skipped |
11. Deferral Logic
Inspections can be deferred by the inspector instead of being completed.
11.1 Deferral Types
| Type | `IsMissedDeferral` | New ScheduleDate | Use Case |
|---|---|---|---|
| Standard Deferral | false | today + 1 day | Inspector cannot complete today, defers to tomorrow |
| Missed Deferral | true | today | Missed inspection is being rescheduled to today |
11.2 Deferral Processing
1. ScheduleDate is updated based on deferral type.
2. DeferredCount is incremented by 1.
3. A SwInsDeferral record is created with the reason and comment.
4. The inspection remains ActionPending — it does not change status.
11.3 Deferral Impact on Dashboard
- A deferred inspection stays in "Inspections Due" with its new
ScheduleDate. - If the new
ScheduleDateis tomorrow (standard deferral), it temporarily disappears from the dashboard (since the base query filtersScheduleDate <= today) but reappears the next day. - If it's a missed deferral (
ScheduleDate = today), it remains visible immediately.
12. Timezone-Based Scheduling
12.1 Scheduler Execution Windows
The routine scheduler (GetTodayRoutineInspection) is timezone-aware. It determines the timezone based on the current UTC hour:
| UTC Hour | Timezone Processed |
|---|---|
| 6–7 | Eastern (EST) |
| 7–8 | Central (CST) |
| 8–9 | Mountain (MST) |
| 9–10 | Pacific (PST) |
| After 10 | null (all timezones processed) |
Each site is assigned a timezone, and only sites matching the current processing window are included.
12.2 Rainfall Event Scheduler
The rainfall event scheduler (GenerateRainafallSwInspection) is not timezone-filtered — it processes all projects across all timezones in every run, since rainfall events are real-time and not calendar-bound.
13. Comparative Summary Tables
13.1 Inspection Generation — When & How
| Frequency | Non-Fluid | Fluid |
|---|---|---|
| Daily | Every day, 1 inspection | Every day, 1 inspection |
| Daily (No QS) | 1 inspection/month, daily reports tracked separately | Same |
| Weekly | On InspectionDay each week | On InspectionDay each week |
| TwiceAWeek | On InspectionDay and InspectionDay2 each week | Every day (scheduler decides whether to create/activate) |
| BiWeekly | On InspectionDay every 14 days | On InspectionDay every 14 days |
| Monthly | On day InspectionDay of each month | Same |
| Quarterly | On day InspectionDay of the configured quarterly months | Same |
| Custom | Every N days from start date | Same |
| PostRainfall (Non-Event) | When daily precip > threshold | Same |
| PostRainfall (Event) | When ENVR cumulative precip crosses threshold | Same, but InsTypeId forced to Routine_PostRainfall |
13.2 Missed Marking — When Inspections Become Missed
| Scenario | Non-Fluid | Fluid |
|---|---|---|
| Routine (non-TwiceAWeek) | Next day when scheduler runs and generates the next inspection | Same |
| TwiceAWeek Routine | When next scheduled day arrives and old inspection is still ActionPending | Only at start of new week (Monday) for prior week's inspections |
| PostRainfall (Non-Event) | Next day when scheduler runs and a new rainfall inspection triggers | Same |
| PostRainfall (Event-Based) | Never (code commented out as of Oct 2025) | Never |
| Daily Report | Prior month's inspection marked Missed when new month starts | Same |
13.3 Past Due — When Inspections Show as Past Due on Dashboard
| Scenario | Condition |
|---|---|
| Non-event, all frequencies | ScheduleDate < today (next day) |
| Event-based (has RainEventId) | today >= ScheduleDate + 2 days (2-day grace) |
| Fluid TwiceAWeek, Term 1 | Only on Fridays |
| Fluid TwiceAWeek, carried from prior week | ScheduleDate.DayOfWeek == Saturday |
13.4 Inspection Day Change — Complete Matrix
| Trigger | Weekly | BiWeekly | TwiceAWeek (Non-Fluid) | TwiceAWeek (Fluid) | Monthly | Quarterly | Custom | PostRainfall |
|---|---|---|---|---|---|---|---|---|
| Scheduled submission | No change | No change | No change | No change | No change | No change | No change | N/A |
| Early submission (different day) | Day changes | Day changes | Day changes | No change | Day changes | Day+Month changes | Reschedule | Never |
| Scheduler generates next | Fixed day | Fixed day | Fixed days | Monday + dynamic | Fixed day | Fixed day+month | Fixed interval | On threshold breach |
14. Scenario Walkthroughs
Scenario 1: Weekly Non-Fluid, Inspector Misses Scheduled Day
- Setup: Weekly, InspectionDay = Wednesday (3)
- Wednesday: Scheduler creates inspection,
Status = ActionPending,ScheduleDate = Wed - Inspector does nothing all week
- Next Wednesday: Scheduler runs again:
1. Previous Wed inspection (ActionPending, ScheduleDate < today) → Marked Missed
2. New inspection created for today: ActionPending, ScheduleDate = this Wed
- Dashboard impact: Old inspection disappears (Missed ≠ ActionPending), new one appears as "Inspections Due"
Scenario 2: Fluid Twice-a-Week, Normal Week
- Monday: Scheduler creates:
- Term 1:
InsTerm = "1",Status = ActionPending(visible) - Term 2:
InsTerm = "2",Status = NotScheduled(not visible) - Tuesday: Inspector submits Term 1. Dashboard shows 1 inspection submitted.
- Wednesday: Scheduler sees Term 1 is
Submitand Term 2 isNotScheduled(count = 2) → Activates Term 2:Status → ActionPending(now visible) - Thursday: Inspector submits Term 2. Both inspections completed for the week.
Scenario 3: Fluid Twice-a-Week, Inspector Doesn't Submit Term 1 Until Thursday
- Monday: Term 1 created (
ActionPending), Term 2 created (NotScheduled) - Tuesday–Wednesday: Term 2 activation conditions not met (Term 1 still ActionPending, not Submit)
- Thursday: Scheduler activates Term 2 anyway (Thursday special rule: only 1 ActionPending/Submit exists)
- Now both Term 1 and Term 2 are
ActionPending - Friday: If Term 1 still
ActionPending→ shows as Past Due on dashboard - Next Monday: Any still-ActionPending inspections from prior week → Marked Missed
Scenario 4: Rainfall Event — Two Events Same Day
- 10:00 AM: ENVR reports 0.3 inches for Project X. No active event → New event created (Event 1, Active).
- Cumulative = 0.3 inches. Threshold = 0.5 inches. No inspection yet.
- 11:00 AM: ENVR reports 0.25 inches. Event 1 data point added.
- Cumulative = 0.55 inches > 0.5 threshold → Inspection 1 generated (
ActionPending,RainEventId = Event1) - 12:00 PM: ENVR reports 0.0 inches. Zero count = 1.
- 1:00 PM: ENVR reports 0.0 inches. Zero count = 2.
- 2:00 PM: ENVR reports 0.0 inches. Zero count = 3.
- 3:00 PM: ENVR reports 0.0 inches. Zero count = 4 → Event 1 deactivated (InActive).
- 4:00 PM: ENVR reports 0.4 inches. No active event → New event created (Event 2, Active).
- Cumulative = 0.4 inches < 0.5 threshold. No inspection yet.
- 5:00 PM: ENVR reports 0.2 inches. Event 2 data point added.
- Cumulative = 0.6 inches > 0.5 threshold → Inspection 2 generated (
ActionPending,RainEventId = Event2) - Dashboard: 2 inspections in "Inspections Due". Inspection 1 is NOT moved to Missed or Past Due.
- Day + 2: Both inspections move to Past Due if still not submitted.
- Indefinitely: Both remain in Past Due — they are never automatically marked Missed.
Scenario 5: Non-Fluid Monthly, Inspector Submits Early
- Setup: Monthly, InspectionDay = 15
- March 15: Scheduler creates inspection. Inspector doesn't complete it.
- March 20: Inspector submits the inspection (which was Scheduled for April 15, or submits the ActionPending one early).
- Rescheduling occurs:
1. Setup's InspectionDay changes from 15 to 20.
2. All existing Scheduled inspections are deleted.
3. New future inspections are created for the 20th of each month.
- From now on: Monthly inspections are on the 20th, not the 15th.
Scenario 6: Post-Rainfall Non-Event, Rainfall on Two Consecutive Days
- Day 1: Precipitation = 0.8 inches > threshold 0.5. Inspection created:
ActionPending,ScheduleDate = Day 1. - Day 2: Precipitation = 0.6 inches > threshold 0.5.
- First: Day 1's inspection (
ActionPending,ScheduleDate < today) → Marked Missed - Then: New inspection created:
ActionPending,ScheduleDate = Day 2 - Dashboard: Day 1 inspection gone (Missed), Day 2 inspection visible as "Inspections Due"