Skip to content

FormsPortal Triage Form — Questions & Paths ​

Reference for every question the customer-facing triage form asks, when each one is shown, and where the answers change the path through the form or the downstream routing.

Source of truth:

ConcernFile
Stepper, validation gates, skip-jumps, submissionFormsPortal/Components/Pages/Triage.razor
Answer model + out-of-scope clearingFormsPortal/Components/Forms/Triage/TriageModel.cs
Step UIFormsPortal/Components/Forms/Triage/Triage*.razor
Shared routing constants (also used by WebAPI/SQL)CommonDataAccess/Models/Forms/TriageFormModel.cs

Entry point: /triage/{SharingCode}. The sharing code is validated against ISharingCodeData.GetSharingCode(code); an invalid/expired code shows an error page and no form. The code carries PrimeJobID / PrimeContactID, which drive the Welcome step details and all post-submission routing.

Staff completing the form for a customer use /triage/staff/{SharingCode} instead: the same form and submission, behind an EntraID sign-in. A signed-in staff member sees a banner with a copy-the- customer-link button, and the submission records their UPN (SubmittedByUPN). See TriageReporting-Spec.md.


1. Steps ​

The stepper has 11 steps (stepTitles in Triage.razor:205). Indexes matter — the skip logic and the Review "Edit" buttons both address steps by index.

#StepComponentShown when
0WelcomeTriageWelcome.razorAlways
1Emergency helpTriageEmergency.razorAlways
2Multiple dwellingsTriageMultiDwelling.razorAlways
3TenantsTriageTenants.razorMulti-dwelling claim only
4The damageTriageDamage.razorSingle-property path only
5Damage detailsTriageDamageDetails.razorSingle-property path only
6PhotosTriagePhotos.razorSingle-property path only
7AuthorisationTriageAuthorisation.razorSingle-property path only
8Support for youTriageSupport.razorSingle-property path only
9ContactTriageContact.razorSingle-property path only
10Review & signTriageReviewSign.razorAlways

Progress is autosaved on every Next, Previous and step completion (SaveProgressAsync).


2. The two paths ​

Everything hinges on TriageModel.IsMultiDwellingClaim, defined in TriageStatusRouting.IsMultiDwellingClaim:

IsMultiDwelling == "Yes"  AND  PropertyResponsibilityScope != "Single Property or unit"

Path A — single property (the common case). Steps 0 → 1 → 2 → 4 → 5 → 6 → 7 → 8 → 9 → 10. Taken when the claim isn't multi-dwelling, or when it is but the customer is only responsible for their own unit. Step 3 (Tenants) is skipped.

Path B — genuine multi-dwelling / strata. Steps 0 → 1 → 2 → 3 → 10. Taken when the claim is multi-dwelling and the customer is responsible for multiple units (strata manager, agent, multi-unit owner). Steps 4–9 are skipped entirely: no damage questions, no photos, no authorisation, no support questions, no appointment contact, and no signature is required on the Review step.

The Previous button mirrors these jumps (OnPreviousClickAsync): from step 4 back to 2 on Path A, and from step 10 back to 3 on Path B — so the customer never lands on a step that was never shown.

Wrong property is a third, terminating path. Answering "No — something isn't right" on Welcome ends the form immediately: the stepper is replaced with a "Thanks for letting us know" page and EnqueueSiteRejectedAlertAsync() alerts the office. Nothing further is asked.


3. Questions, by step ​

* = required (enforced by the step-completion gate in OnStepperInteraction; failing it cancels the Next and shows a warning snackbar).

Step 0 — Welcome ​

Shows job number, property address and contact from Prime.

  • Is this the correct property? * — Yes — these details are correct / No — something isn't right
    • Only asked when the Prime job summary actually loaded. If it didn't, the step passes through with no question.
    • "No" terminates the form (see above). "Yes" is the only way to continue.
    • Autosaved the moment it's answered, so a "No" is recorded even if the window is closed.

Step 1 — Emergency help ​

  • Do you require emergency assistance to make the property safe and/or prevent further damage? *
    • Yes — and a make safe has not been arranged to my knowledge → raises a make safe phone call on submission
    • Yes — however already arranged → no phone call (one is already in hand)
    • No — no emergency assistance required → no phone call
    • Option text comes from TriageEmergencyAssistance constants — the same strings are compared in RaiseMakeSafeIfRequiredAsync and inside spMakesafeInsertPhoneCallFromTriageForm. Changing the wording means changing it in all three places.
    • A "What is a Make-Safe?" info dialog is available.

Step 2 — Multiple dwellings (the routing fork) ​

  • Does this claim involve damage to multiple dwellings or units within a strata complex? * — Yes / No
    • No → jump straight to step 4 (The damage). Path A.
  • Are you responsible for a single property or unit or multiple property or unit within this claim? *
    • Shown only when the answer above is "Yes". Switching back to "No" clears it.
    • Single Property or unit → jump to step 4. Path A — treated exactly like "No" from here on.
    • Multiple properties or units (e.g. as a strata manager, agent, or owner of several units) → continue to step 3. Path B.

Step 3 — Tenants (Path B only) ​

  • Repeating table of affected units. At least one row required; every row needs a valid Unit number *, First name *, Last name *, Phone number * and Email address *.
    • Phone: ^\+?[0-9 ]{8,15}$. Email: ^[^@\s]+@[^@\s]+\.[^@\s]+$ (TriageContactValidation).
  • Completing this step jumps to step 10 (Review & sign).

Step 4 — The damage (Path A only) ​

  • What is the best way to describe the damage at your property? * — single choice from: Fire, Water, Flood, Sewage overflow, Break in, Hail, Storm, Impact, Tenant damage, Other. This answer gates the three conditional questions below and also selects the photo tips shown on step 6.
    • Explain damage types sits between the question and the choices; a one-line summary of the chosen type is shown under the choices.
    • Explain damage types link opens a dialog listing every type with a longer description; choosing one there sets the answer.
    • Names, summaries and descriptions all come from TriageDamageTypes (FormsPortal TriageModel.cs), which also feeds the AI check below.
  • Can you provide a brief description of what happened and what items were damaged? * — free text, directly below the damage type
  • Is a fence the only thing that's been damaged? * — Yes, only a fence / No, other parts of the property are damaged (saved as Yes / No in IsFenceOnlyDamage) — always asked; helper text "This includes fences shared with a neighbour." Yes, only a fence hides the mould, solar panels, wet area, timber flooring and room count questions (marked † below).
  • Is there any mould present? * † — Yes / No — only for Water, Flood, Sewage overflow, Storm (MouldRelevantDamageTypes)
  • Do you have solar panels on your roof? * † — Yes / No — only for Hail, Storm (SolarPanelRelevantDamageTypes)
  • Is the damage located in a wet area (Bathroom/Laundry/Toilet)? * † — Yes / No — only for Water, Flood, Sewage overflow (WetAreaRelevantDamageTypes)
  • Is there damage to your timber flooring or floating/laminate flooring? * † — Yes / No
  • How many rooms have been damaged? * † — 1 room / 2 or 3 rooms / 4 or more rooms / Extensive damage throughout — drives the booking type (§5) Changing the damage type clears any now-irrelevant mould / solar / wet-area answer immediately, and choosing Yes, only a fence clears the † answers.

AI damage type check ​

Customers often pick a type that doesn't match what they describe (e.g. Other or Flood for a burst pipe). When the description loses focus (and again on Next, as a fallback) it is classified by AI (ClassifyTriageDamageTypePromptTemplate, IAIParseTextService.ClassifyTriageDamageType) and an information panel appears under the description — "This damage sounds more like Storm. … Are you OK if we change the damage type to Storm?" with Yes, change to Storm / No, keep … buttons — only when the AI's type:

  • has confidence ≥ TriageDamageTypes.SuggestionMinConfidence (0.85),
  • differs from the chosen type,
  • is not Other (the AI never moves a customer to Other), and
  • hasn't already been offered on this submission (a declined suggestion isn't asked again).

The panel is a panel rather than a dialog so it can't be dismissed by accident. Next is blocked until the customer accepts or declines. Accepting changes the damage type (any new sub-question — mould / solar / wet area — appears on the same step) and hides the panel. Declining keeps the panel with only the Yes, change to … button, so the customer can still change their mind; it disappears once the damage type is the AI's.

The AI check itself never holds the customer up: it runs in the background as soon as the description loses focus and the panel appears when the answer arrives (the customer can keep answering meanwhile); Next waits at most 3 s for a check still running, and the call itself is capped at 8 s with no reasoning (≈1.5–2 s typical). A late answer never offers once the customer has left the step. Any timeout or failure (including no OpenAI:ApiKey) means no suggestion and the form carries on.

Recorded in FormData: DamageTypeAiSuggestion (type offered, empty if none), DamageTypeAiConfidence, DamageTypeBeforeAi (the customer's pick when offered), DamageTypeAiResponse (Accepted / Declined; the AI's reason is shown in the panel but not saved) and DamageTypeAiAdjusted (true when the saved damage type is the AI's; reset if the customer later picks a type themselves). Checks that don't prompt are only logged. All five are columns on vEthFormTriageSubmission (see TriageReporting-Spec.md). When a suggestion was offered, TriageFormDataFormatter adds a Damage Type AI Suggestion line under Damage Types, e.g. "Fire - accepted (customer chose Other, AI confidence 97%)", so it appears in the PDF summary uploaded to Prime, the AI job summary and the make safe phone call message.

AI fence only check ​

The same description is also read by AI (ClassifyTriageFenceOnlyPromptTemplate, IAIParseTextService.ClassifyTriageFenceOnly) to see whether it says a fence is the only thing damaged. When the customer has answered the fence question (and again on Next), a panel appears under it — "Your description sounds like other parts of the property are damaged. … Would you like to change your answer to "No, other parts of the property are damaged"?" with Change my answer / Keep my answer buttons (no bare yes/no wording) — only when the AI answers a confident (≥ 0.85) Yes or No that differs from the customer's answer and hasn't been offered before (Unsure never prompts). Next is blocked until the customer accepts or declines; accepting changes the answer (a Yes clears the † answers). Timeouts, failures and the 3 s / 8 s limits are the same as the damage type check.

Recorded in FormData: FenceOnlyAiSuggestion, FenceOnlyAiConfidence, FenceOnlyBeforeAi (the customer's answer when offered) and FenceOnlyAiResponse (Accepted / Declined). When offered, TriageFormDataFormatter adds a Fence Only AI Suggestion line under Fence Only Damage, e.g. "Yes - declined (customer answered No, AI confidence 97%)", so it appears in the PDF uploaded to Prime. All four are columns on vEthFormTriageSubmission (see TriageReporting-Spec.md).

Step 5 — Damage details (Path A only) ​

  • Do you know what date the damage occurred? * — Yes / No
  • Please advise what date the damage occurred * — date picker, max today — only when the answer above is "Yes"; switching to "No" clears the date
  • Is your property domestic or commercial in nature? * — Domestic (house/unit/townhouse) / Commercial (business/office/factory) — overrides the room-count booking rule (§5)
  • Do you have any specific appointment requests and/or any specific history…? — free text, optional

Step 6 — Photos (Path A only) ​

  • Optional but recommended; any image format, 10 MB per file, uploaded to the triage-images blob container.
  • The tips panel is tailored to the damage type chosen on step 4 (falls back to a generic list).

Step 7 — Authorisation (Path A only) ​

  • I / We have read, understand and accept the above and authorise Ethos Building & Restoration to proceed. * — checkbox, must be ticked to continue.

Step 8 — Support for you (Path A only) ​

  • Do you have any special requirements? * — Yes / No
  • Which kind of help would you like us to provide? * — only when "Yes"; at least one must be selected. Options: Language or literacy support, Accessibility or mobility support, Mental health considerations, Safety or family-violence related contact needs, Cultural preferences, Remote location or connectivity constraints, Age-related preferences, Financial difficulty, Other.
    • Switching to "No" clears the selections.
    • On submission each selected option tags the Prime job with its matching "Vulnerable Customer - …" filter tag (WebAPI TriageFinalizeQueueService.TagVulnerableCustomerAsync; tag IDs keyed on the TriageSupportNeeds constants the form uses). Best-effort, like the Multi Unit tag.

Step 9 — Contact (Path A only) ​

  • Are you the best contact to arrange an estimator appointment with? * — Yes / No
  • Only when "No" (all three required):
    • Name of the best contact person *
    • Phone number (mobile preferred) of the best contact person *
    • What is this contact's relationship to you/the claim? * — Partner/spouse, Family member, Tenant, Property manager, Real estate agent, Friend/neighbour, Other
      • Each option maps to a Prime relationship type via TriageContactRelationships (Relative / Tenant / Real Estate / Family/Friend / Main Contact), used when the contact is created against the Prime job.
    • Switching back to "Yes" clears all three.

Step 10 — Review & sign ​

  • Summary rows with per-section Edit buttons. On Path B only the "Damage" row is shown; on Path A the Photos, Authorisation, Support and Appointment-contact rows are shown too.
  • Signature * — draw on canvas, or upload — required on Path A only. Path B submits without one.
  • The submission PDF prints the full Authorisation to proceed waiver and the acceptance line (ticked or not) directly above the signature. The wording lives once in TriageAuthorisationTerms (TriageFormModel.cs) and is shared by the Authorisation step and the PDF.

4. Answer clean-up ​

TriageModel.ClearOutOfScopeAnswers() runs on every save, so the stored payload only ever contains what the current answers actually put in scope. It's what stops a stale answer surviving when the customer goes back and changes a routing question:

  • Not multi-dwelling → PropertyResponsibilityScope cleared.
  • Path B → damage, damage-details, photos, authorisation, support, contact and signature answers all cleared.
  • Path A → the Tenants list cleared.
  • Damage type no longer relevant → mould / solar / wet-area answers cleared.
  • Damage date not known → date cleared. No support needs → selections cleared. Best contact "Yes" → alternate contact fields cleared.

Already-uploaded photo blobs are deliberately left in place (private and unreferenced); only the metadata is dropped.


5. What the answers do on submission ​

In order, from case 10 of OnStepperInteraction:

  1. Save + SetTriageSubmitted (stamps SubmittedAt — the finalize task and AI summary key off it — and SubmittedByUPN for staff), then mark the sharing code used.
  2. Make safe — a phone call is raised only for "Yes — and a make safe has not been arranged to my knowledge". Retried in the background if the first attempt fails.
  3. Booking routing — inline on submit since UserStory1947, while the customer sees "Preparing your booking…" (CommonPrimeAPI/Services/TriageBookingRoutingService.cs). The customer is then taken straight to the booking page (/booking/va/{code} or /booking/estimator/{code}; the /staff/ route when a staff member submitted). The booking-link SMS is still sent, in case they close the page without booking. When nothing goes to the insured, or routing couldn't finish on submit, they get the thank-you page as before, and the queued TriageFinalizeSubmission task routes it instead (as it did for every submission under UserStory1750). Stamped ethFormTriage.BookingRoutedAt before that task is queued, so it never books twice. The decision is recorded in ethFormTriage.BookingOutcome. The Prime filter tags are added by the finalize task. Rules follow the Triage Form High Level V9 process diagram; first match wins:
ConditionOutcome (BookingOutcome)
Path B (multi-dwelling claim)No automatic booking; the case manager alert lists the units (ManualBookingsTeam)
Commercial, 2+ rooms (2–3, 4+, extensive)Complex Quotation link
Commercial, 1 room — or no room count (fence only)Field Quotation link
Domestic, Yes, only a fenceDesktop VA link (+ Desktop Video Assessment job tag)
Domestic, 4+ rooms / Extensive damage throughoutComplex Quotation link
Domestic, wet area or 2–3 roomsField Quotation link
Domestic, 1 room, not a wet area, no Specialist Report allocationDesktop VA link
Domestic, 1 room, not a wet area, with a Specialist Report allocationNothing to the insured — case manager told (CaseManagerReview)

Two readings of the diagram to confirm: a domestic wet area with 4+ rooms matches both the Field and the Complex condition and gets Complex; a commercial fence-only claim has no room count and gets Field.

"Specialist Report allocation" means a primeAllocations row with AllocationType of Specialist Report, Roof Report, Plumbing Report, Electrical Report or Flooring Report that is not Cancelled (spPrimeJobHasSpecialistReportAllocation). The allocations are synced from Prime (and saved) just before. This is the only outcome that waits on Prime: on submit the sync gets one attempt, cut off after 5 seconds, and the finalize task retries it after 10 and 30 seconds. If it still fails, routing throws and the task retries rather than guess.

Skipped entirely if the sharing code has no PrimeJobID.

  1. Prime job status is set server-side by the queued TriageFinalizeSubmission processing (TriageStatusRouting.StatusFor): MultiUnitBookingRequired on Path B; Estimator Appointment Required when a booking link was sent; Insured Triage Complete - awaiting review when nothing was sent to the insured (the specialist report case, or a booking that failed and is being retried). If Prime refuses the status (e.g. a status requirement the job doesn't meet, such as "Site form at status - Customer triage | Completed"), the failure is held: tags, contacts and both emails still go out, the case manager alert says the status couldn't be changed and quotes Prime's reason, and the task is then failed so the patch is retried.
  2. Case manager alert — one email per submission, carrying every outcome. Subject "{JobNumber} - {Suburb} {State} - Triage form submitted". The body has:
    • when make safe is required, one of three notes, keyed off ethFormTriage.MakeSafePhoneCallID (set by spMakesafeInsertPhoneCallFromTriageForm in the same transaction as the call):
      • call raised (after hours) — informational: the on-call team has it, with a link to /phonecall/{id}; no action for the case manager;
      • no call, submitted in business hours — red "Make Safe is required" banner: please arrange the make safe;
      • no call, submitted after hours — the same red banner, saying the after-hours call couldn't be confirmed and to check with the on-call team. This covers a failed call and the one race: FormsPortal awaits the first make safe attempt before queueing this task, but if that attempt fails its retries (+10s, +20s) run in the background and can land after this email.
    • what the booking decision did (which link was sent), or, for CaseManagerReview, "It has been identified that a specialist report and Desktop VA are required to progress the assessment of this claim. Please arrange for these to be booked.";
    • when the status patch failed, "The job status could not be changed to "{status}"" with Prime's error text, asking them to update it in Prime;
    • the PDF attached, plus a link to view it in AdminPortal ({AdminPortal:BaseUrl}/view/forms/triage-images/{PdfBlobName}), and a link to the job in Prime. Make safe team email — when the insured asked for a make safe in business hours (step 1, no phone call raised, whatever the damage type), the finalize task emails makesafe@ethosbuilding.com.au: subject "{JobNumber} - {Suburb} {State} - Restoration make safe required", asking the team to review the file and contact the insured. Separate from the emergency make safe phone call (step 2); stamped ethFormTriage.MakeSafeTeamAlertedAt.
  3. AI job summary queued last (from FormsPortal); a task still pending once WebAPI creates the booking lands in the booking priority bucket.

Related specs: docs/specs/TriageBookingRouting-Spec.md, docs/specs/TriageInvite-Spec.md.