The user journey
This page follows a user from sign-in to a submitted claim. It is the best single page for support: it names what the user sees, what each state means, and which part of the app is responsible. File references point into frontend/src so engineers can jump to the code.
The whole journey at a glance
1. Sign in
The app is gated by AdjustSquare single sign-on. An unauthenticated user is sent to the AdjustSquare login page and returns with a token, which the app exchanges for a session.
- Pages:
login,auth/callback,logout. - State:
lib/auth.tsxholds the user and token, persists them tolocalStorage, and falls back to abt_shared_datacookie for same-subdomain deployments. - The full sequence (redirect, JWT validation, team and user auto-provisioning) is documented in authentication.
2. The dashboard
After sign-in the user lands on the Dashboard (app/dashboard/page.tsx), which lists their team's claims (with a per-claim Usage column) and exposes the Create claim action. Stat cards headline total claims, average items per claim, and the average processing time per catalogued item (from GET /api/dashboard/metrics). On prepaid-billing instances a persistent credits widget in the shell also shows the team's available balance and a Buy credits button; on invoiced instances it is hidden.
- Shell:
components/AppShell.tsxandcomponents/Sidebar.tsxprovide the left nav (Dashboard, Training, Help, Settings), the team and environment badge, and the user footer.
3. Create a claim and add rooms
Creating a claim (components/CreateClaimModal.tsx) captures the claim number, date of loss, ZIP or Canadian postal code, and loss type. Opening the claim (app/claims/[id]/page.tsx) shows its rooms, and the user adds rooms with components/CreateRoomModal.tsx.
Media is always uploaded into a room, and the room name becomes the room on every item the upload produces. Setting up rooms up front keeps the inventory organized.
New users can learn this whole journey hands-on in Training (/training): guided missions run the real flows inside a sandboxed training claim, with deterministic fixture media, points, badges, and a shareable certificate at the end. See Training and certification.
3b. Optional: ask the insured to start it off
Instead of gathering everything themselves, the adjuster can hand the first pass to the person who actually knows what was lost. Ask the Insured on the claim page emails the homeowner a private link (components/InviteInsuredModal.tsx).
They open it on a phone, with no account and no sign-in, and are walked through the claim's rooms one at a time. In each room they can add photos or a video with a note on each file, type items into a table, or skip the room. It saves as they go, so they can stop and come back to the same link. When they press Send, everything lands on the claim:
| What they added | Where it lands | What it costs |
|---|---|---|
| Photos of a room | A photo job per room at awaiting_grouping, each photo carrying their note | Nothing until the adjuster presses Process |
| A video | Its own job at awaiting_confirmation | Nothing until the adjuster confirms it |
| Typed items | Inventory items on the claim, immediately | Nothing, ever: they named them, so the AI is never called |
The adjuster reviews it all as normal. Nothing is auto-sent to Contents Estimation, because sending freezes a claim's items and would remove the chance to correct anything. The claim page shows how far each invitation got, and a link can be resent or revoked. See Insured inventory link.
4. Upload media
From a room (app/rooms/[id]/page.tsx) the user drops any mix of files or folders into a single upload area (components/RoomUpload.tsx). There are no per-type tabs: the component classifies each file as photo, video, audio, or PDF by extension (lib/media.ts, with a MIME tiebreak for WEBM), queues everything, and uploads in one pass. All photos in a drop become one photo job (a "set"), and any PDFs ride with them into that same job; each video and each audio file becomes its own job. Uploads report real progress bars (chunked uploads and XMLHttpRequest in lib/api.ts).
| Type | What happens after upload |
|---|---|
| Video | A job is created and the video pipeline starts immediately (after the credit confirmation on prepaid instances). |
| Audio | A job is created and the audio pipeline starts immediately (after the credit confirmation on prepaid instances). |
| Photos | A job is created in awaiting_grouping. The user groups same-item photos in components/GroupPhotosModal.tsx, then presses Process. |
| PDF with photos | The job is created in importing_pdf and the photos are read out of the document in the background, then it becomes an ordinary awaiting_grouping photo job. Photos printed under one item label arrive already merged, whether the label sits on each photo or as a heading above a run of them, and any note printed beside a photo is kept and passed to the AI as a hint. A label printing more than MAX_PHOTOS_PER_ITEM (5) photos is split into several balanced groups, each one its own AI request and its own credit, and the grouping screen says so. Cover sheets and summary pages are found and skipped, so the file does not have to be trimmed first. See PDF import. |
| Contents list for a whole claim | Imported from the claim page instead of a room, because one list covers a whole house. The rooms printed in the document become rooms on the claim, each with its own awaiting_grouping photo job. See PDF import. |
On prepaid instances, video and audio jobs park at awaiting_confirmation after upload. The uploader collects every parked job from the drop and asks for one combined credit confirmation (components/ConfirmUploadsModal.tsx) instead of one dialog per file; cancelling discards the parked jobs before any credits are spent.
Photo grouping is the key difference: photos do not auto-process. The user merges shots that show the same item (so the AI treats them as one), then explicitly starts processing. See the AI pipeline.
5. Watch processing
While a job runs, the user sees live progress (components/ProcessingStatus.tsx). The frontend opens a Server-Sent Events stream and receives progress, log lines, and final metrics as they happen.
Job statuses support should recognize
| Status | Meaning |
|---|---|
pending | Queued, pipeline about to start. |
importing_pdf | Reading the item photos out of an uploaded PDF. Moves to awaiting_grouping by itself when done. |
awaiting_grouping | Photo job waiting for the user to group photos and press Process. |
extracting | Pulling frames and audio from the video (or reading the audio file). |
transcribing | Running Deepgram on the narration or audio. |
segmenting | Splitting the video into time chunks. |
analyzing | The AI vision calls are running (the long stage). |
synthesizing | Saving items and cropping photos. |
complete | Done. Items are ready to review. |
error | Something failed. error_message has the detail; the pipeline logs explain it. |
A job interrupted mid-run (a deploy restarting the backend, a crash) does not stay frozen: the recovery sweep requeues it automatically (stage reads "Restarting after an interruption") and it runs again from scratch. See troubleshooting.
6. Review the inventory
The review surface is components/InventoryTable.tsx, with per-item editing in components/ItemModal.tsx. There are several ways to get through the list:
- Manual review: scan the table, open items, edit fields inline.
- Guided Review (
components/ReviewMode.tsx): a focused, one-item-at-a-time flow with keyboard shortcuts; for audio items it can play back just the slice of the recording that mentions the item. - Bulk actions: select many rows and apply the same change (condition, room) at once.
- Filtering and sorting: narrow the table by room, confidence, flag, or approval state.
Confidence is shown per item (lib/confidence.ts), and items below 0.6 arrive flagged. Source badges (lib/sourceTag.ts) mark whether an item came from video, photo, or audio.
7. Approve items
Only approved items are submitted and exported. Users approve items one at a time, in bulk, or automatically:
- Auto-approval rules (
Settings,lib/automationSettings.tsx) approve items that clear a confidence threshold and an allowed-condition list, optionally skipping flagged items. Rules can run automatically the moment a job finishes, or on demand. See automation and prompts.
8. Submit to Adjust Square
When the inventory is ready, the user submits with components/SubmitClaimModal.tsx. They confirm claim details, pick which rooms to send, and choose whether to send only approved items.
- The first submission creates the claim and all items on Adjust Square in one call.
- Later submissions add only the new (still unsubmitted) items to the same claim.
- Photos upload and AI processing on the Adjust Square side are triggered in the background, so the modal returns quickly.
The full mechanics, including the per-user authentication, are in the Adjust Square integration.
9. Export (optional)
At any time the user can export an inventory to Excel or CSV, for a single job or a whole room, optionally limited to approved items (lib/api.ts, backend inventory routes). The Excel export includes a summary sheet, per-room sheets, and — when the items have photos — a Photos sheet. In the Excel file every item name is a hyperlink to that item's primary photo, and the Photos sheet carries a link to each of an item's other photos, since a cell can only hold one link. The links point at the unauthenticated /api/photos/... route, made absolute with PUBLIC_BASE_URL or, when that is blank, with the origin the export was requested from.
The Help Center and the Activity Log
- Help Center (
app/help): in-app, task-focused articles written from the home Dashboard outward. Content lives infrontend/src/content/help. - Activity Log (Settings): every meaningful action is recorded, and many actions can be restored (undone) from here. See observability.
If a user says "my items are wrong," first check the job status and its logs (the Logs page, app/logs, admins only; filter it to the user's team). Most "wrong output" reports trace back to a quiet narration (poor transcription), a photo batch that was not grouped, or low-confidence items that were never reviewed.