The Safety Inspection Admin controls inspection templates, questions, schedules, and field deployment for Weekly Safety, QC layers, surveys, and closeout checklists. Changes take effect immediately — the mobile form always fetches the latest question configuration from the database.
Questions — add, edit, reorder, and deactivate inspection questions.
Branch Tree — visual map of all conditional parent–child relationships.
Score Legend — view which questions contribute to each scoring category and their weights.
Submissions — browse, inspect, and delete completed inspection records.
Schedule — configure inspection cadence, crew requirements, and per-job overrides.
This admin page uses the Supabase service-role key embedded in the HTML — it is not public-facing. Only share the URL with safety managers and system administrators.
Field crews never access this page. They use the mobile inspection form at safety-inspection.html. Each crew member chooses how questions are displayed on their own phone — scroll through all questions or step through one at a time (see Field Form).
Use + New Template in the admin top bar to create a brand-new inspection type (not just add questions to an existing one). The AI wizard defines the template registry row, questions, schedule, and optional field deploy in one flow.
| Action | When to use |
|---|---|
| + New Template | You need a new slug and template in the registry (e.g. a one-off warranty punch list, a new QC checklist type). |
| Import with AI | You already selected a template in the dropdown and want to add or replace questions on that template only. |
| Field | Rules |
|---|---|
| Template slug | Lowercase letters, numbers, underscores; 3–48 chars; must start with a letter. Immutable after creation (e.g. tpo_warranty_qc). |
| Layer | safety, qc_layer1 (Federal), qc_layer2 (Daily), qc_layer3 (Closeout), or custom. |
| Status | testing = admin preview only, not on mobile. active = crews see it when schedule says due. |
federal_job = true in tbl_job_inspection_flags for the inspection to appear on mobile. The deploy panel can set this when you enter job IDs.
Questions are stored in tbl_safety_question_config. Every active question is fetched fresh each time a field
user opens the inspection form, so changes apply to the next submission immediately.
PPE_05), Question Text, and Field Key (auto-filled from Question ID if left blank).Click the Edit button on any row to open the edit drawer. All fields are editable including the question text, answer type, and scoring weight.
To change display order, edit the Order number in the drawer, or use the ⇧ ⇩ arrow buttons on the question row to move it up or down one position. Reordering updates display_order for all affected questions in a single batch.
Toggling a question inactive hides it from the mobile form without removing it from the database. Past submissions that answered the question are preserved and still visible in the Submissions tab.
There is no delete button by design — deactivate instead of deleting to preserve historical data integrity.
| Type | When to Use | Scorable? |
|---|---|---|
| yes_no_na_notsure | Standard safety questions where an observer may be uncertain | Yes |
| yes_no_na | Compliance checks with a clear pass/fail (no uncertainty option) | Yes |
| pass_fail_na | QC / closeout items (PASS / FAIL / N/A on mobile) | Yes |
| number | 1–5 satisfaction or survey ratings (e.g. GC Check In). Pass values default to 4 and 5. | Yes |
| text | Free-form notes, descriptions, names, task identification | No |
| multiselect | Checklists where multiple answers apply simultaneously | No |
The inspection generates a percentage score per category and an overall score. Scores are computed server-side when the inspection is submitted and stored permanently in the record.
Each scorable question has a Score Weight (points) and a Score Category. When a question is answered, its weight is added to the category’s possible total. If the answer is a pass value (yes or na), the weight is also added to earned points.
Category score = earned ÷ possible × 100. Overall score is the same calculation across all categories combined.
Conditional questions that are never shown (parent answer did not trigger them) are excluded from scoring entirely.
| Category Key | Display Name | Typical Questions |
|---|---|---|
| ppe_site | PPE & Site Safety | Hard hat, vest, eye protection, housekeeping |
| fall_protection | Fall Protection | Harness, guardrails, ladder safety |
| hot_work | Hot Work | Fire extinguisher, permits, combustible clearance |
| overhead_tools | Overhead / Tools | Overhead hazards, tool tethering, barricades |
| traffic | Traffic & Access | Traffic control, flagging, equipment proximity |
["yes","na"] for yes/no types, ["pass","na"] for pass/fail, and ["4","5"] for number ratings. Only change when you need custom pass logic.
Any question can optionally require or allow a photo. Photos are uploaded to the job-log-photos Supabase storage bucket and linked to the inspection record by UUID.
| Field | Default | Behaviour |
|---|---|---|
| photo_enabled | Off | Shows a camera button beneath the question on the mobile form. If off, no photo option appears. |
| photo_required | Off | Blocks form submission if no photo is attached to this question. Only meaningful when photo_enabled is also on. |
| photo_prompt | Empty | Helper text shown above the camera button (e.g. “Photograph the first-aid kit location”). Optional. |
Conditional questions are hidden until a specified parent question is answered with a trigger value. This keeps the form concise while enabling drill-down on problem areas.
conditional.["no","not_sure"]."yes", "no", "na", "not_sure". Example: ["no","not_sure"]. Do not use display labels like “Yes” or “No”.
The Branch Tree tab renders the full parent–child hierarchy. Each parent question is shown with its trigger values and an indented list of the child questions it controls. Useful for auditing logic before adding new conditional questions.
Questions with no parent (top-level) are not shown in the tree — only conditional relationships appear.
The Schedule tab controls when inspections are due, how the system responds to failing scores, and whether crew presence is required before prompting a field user.
The global row (Job ID = All jobs) applies to every job unless a per-job override exists. Override rows take full precedence for that specific job.
| Setting | Default | Meaning |
|---|---|---|
| interval_days | 7 | Days between inspections when score is acceptable (80+). The next due date is set to submission date + interval on every submit. |
| elevated_interval_days | 2 | Days between inspections when the last score was below the deficiency threshold. A 2-day cadence continues until the score recovers. |
| deficiency_threshold | 80 | Score strictly below this value triggers elevated cadence on next requeue. |
| recovery_threshold | 90 | Score at or above this confirms full recovery; mode returns to standard. |
| require_active_crew | ✓ | When enabled, the inspection button is only shown on the mobile app if Buildertrend timecards show crew activity on the job within the last 7 days. Disabling always shows the button regardless of crew data. |
AR25-020) and adjust any thresholds, then click Add Override. Remove an override to revert to global settings.
The lower section shows a live row for every job that has submitted at least one inspection. Each row displays the job’s next due date, current mode, last score, and whether Buildertrend reports active crew.
Use the Reset Due Date date picker and Set button to manually override the next due date for a job — useful for rescheduling after a site shutdown or holiday.
| Mode | Trigger | Next Due |
|---|---|---|
| standard | Score ≥ 80 on last submission (or default) | Submission date + interval (7 days) |
| elevated | Score < deficiency threshold (< 80) | Submission date + elevated interval (2 days) |
| snoozed | User tapped “Snooze 1 day” on mobile | Original due date + 1 day |
safety-schedule-sweep) runs at 06:00 UTC every day. It refreshes the Crew Active flag for all jobs from Buildertrend timecard data, and automatically restores snoozed rows back to their previous mode once the snoozed date has passed.
The Deploy to Field panel on the Schedule tab controls whether crews see a template on mobile. Schedule configuration (intervals, thresholds) does not deploy by itself — deployment is a separate step.
| Template status | Mobile behavior |
|---|---|
| active | Eligible to appear when a per-job schedule row exists and the checklist is due or has a today draft. |
| testing | Hidden from Field / Forms Job Checklists. Admin can still open via direct link. |
| Goal | Action |
|---|---|
| Hide template everywhere | Uncheck Activate template, leave Job IDs empty, click Deploy to jobs → status returns to testing. |
| Hide for one job only | Active Job Schedules → Delete that job’s row. |
| Stop federal QC on a non-federal job | Delete schedule row and/or clear federal_job on that job (do not mark federal on deploy). |
| Remove a stuck draft banner | Submissions tab → delete the incomplete submission for that job/date. |
qc_layer3_prefinal, qc_layer3_final) — queued when job % Complete ≥ 95 (pre-final first, then final after submit).Field guide: Closeout QC & Job Checklists Help
safety-inspection-dashboard.html aggregates submissions across jobs. Use the template filter to switch between Weekly Safety, QC layers, surveys, and closeout templates.
The first KPI chip label changes by template filter:
Pass/fail coloring uses each question’s score_pass_values from question config:
| Answer type | Pass values (default) |
|---|---|
yes_no_* | yes, na |
pass_fail_na | pass, na |
number (1–5 surveys) | 4, 5 |
A rating of 5 on a satisfaction survey should show Pass (green), not fail.
The Submissions tab lists every inspection record in tbl_safety_inspections, sorted by date descending. Use it to audit completed inspections, review answers, and delete test records.
Click the Job ID link (blue, underlined) on any submission row to expand a full Q&A panel beneath it. Questions are grouped by section. Answers are colour-coded: Yes / N/A = pass, No = fail (row highlighted red), Not Sure = caution.
Photo thumbnails load at the bottom of the panel. Click any thumbnail to open the full-size image in a new tab. Signed URLs expire after 1 hour.
Click the Job ID again to collapse the panel.
The Delete button on a submission row permanently removes that record from the database. After deletion, the field user can re-submit a fresh inspection for the same job and date.
This is the correct way to reset a test submission or allow a crew member to redo an inspection that was submitted in error.
Use the toolbar at the top of the Submissions tab to filter by Job ID (partial match), Submitted By email (partial match), or exact Date. Filters apply client-side to the loaded batch of up to 200 records. Click Refresh to reload from the database.
The field form at safety-inspection.html is used for Weekly Safety and other inspection templates (Federal, Daily, Closeout).
Admins configure questions and schedules; field users complete inspections on their phones.
Below the progress bar, each user sees a How to view toggle. This is a personal preference — admins do not force one layout for everyone.
| Mode | Best for | Behavior |
|---|---|---|
| All questions | Long checklists, jumping around, reviewing earlier answers | Classic scroll: every visible question on one page. Section headers group related items. |
| One at a time | Focused walk-throughs, shorter surveys, less scrolling on small screens | Carousel: one question card at a time with Back and Next. Tapping YES/NO/PASS/FAIL or a 1–5 rating advances automatically when the question is complete (including required photos). |
The choice is saved in the browser (localStorage key jrco-inspection-display-mode) and applies to every inspection on that device until the user changes it. Users can switch modes at any time during a draft — answers are preserved.
Follow-up questions appear when a parent answer triggers them, in both view modes. In carousel mode, the step counter updates when new questions become visible.
Next is blocked until the current question is answered. If a photo is required, the user must attach one before advancing. Review Score still validates the full form and jumps to the first incomplete item.
| Config type | Field UI |
|---|---|
yes_no_na / yes_no_na_notsure | YES / NO / N/A (and NOT SURE) |
pass_fail_na | PASS / FAIL / N/A |
number | 1–5 rating buttons (surveys, satisfaction) |
text | Free-text area |
multiselect | Chip toggles |
Question IDs are not shown to field users. Validation messages use question text only.
safety-inspection.html?jobId=JOB-ID&template=TEMPLATE_SLUG&date=YYYY-MM-DD.
Template slug examples: weekly_safety, qc_layer1_followup.
| Table | Purpose |
|---|---|
| tbl_safety_question_config | Question definitions: text, section, answer type, photo settings, scoring, conditional parent links. |
| tbl_safety_inspections | Submitted inspection records: answers (JSONB), scores (JSONB), photo UUIDs, completion flag. |
| tbl_safety_schedule_config | Global and per-job schedule thresholds: interval days, deficiency/recovery score limits, crew requirement. |
| tbl_safety_inspection_schedule | Live schedule state per job: next due date, mode (standard/elevated/snoozed), last score, crew active flag. |
| tbl_job_log_photos | Photo metadata: storage path, original filename, caption, job ID, log date, uploader email. |
| Function | Actions |
|---|---|
| field-safety-inspection | get_questions, get_inspection, get_schedule, snooze_inspection, submit_inspection |
| safety-schedule-sweep | POST (no action param) — refreshes crew_active from BT timecards, restores expired snooze modes. Runs nightly via pg_cron. |
| mobile-upload-job-photo | Multipart POST: uploads image to job-log-photos bucket, inserts metadata row, returns signed URL. |
The inspection button on the Field tab is only shown when action is required. It is hidden in all other states to avoid clutter. The Daily Log card on the Project tab always shows the full status regardless.
| State | Field Tab Button | Daily Log Card | Snooze? |
|---|---|---|---|
| Due today | Visible — red, “Inspection due today” | Due today | Yes |
| Elevated, due | Visible — red, ⚠ “Re-inspection due — score below 80” | Re-inspection due | Yes |
| Draft in progress | Visible — red, “Draft in progress — tap to continue” | Draft saved | No |
| Complete | Hidden | Score% — Complete ✓ | No |
| Not due yet | Hidden | Next due [date] | No |
| Snoozed | Hidden | Snoozed — due [date] | No |
| No crew active | Hidden | No crew active / Next due [date] | No |
Same list appears on Field tab and Forms → Job Checklists. Hidden when complete until due again; only today’s in-progress draft counts (not yesterday’s submission).
| State | Blue banner |
|---|---|
| Due today | Visible |
| Draft today | Visible — “Draft in progress” |
| Complete, not due | Hidden |
| Template testing | Hidden |
| Federal template, job not marked federal | Hidden (template_blocked) |
The mobile app has two surfaces for field paperwork. They use different data models and must not be mixed in admin.
| Surface | What appears | Examples |
|---|---|---|
| Field tab | Mandated, scored inspections (red = Weekly Safety; blue = QC / closeout / surveys) | Weekly Safety, Daily QC, GC Check In, Closeout Final QC |
| Forms tab → Job Checklists | Same mandated checklists as Field tab, shown as blue banner tiles when due (mirror for discoverability) | Closeout Pre-Final Walk, Closeout Final QC + Warranty |
| Forms tab → Submit a Form | Voluntary safety forms (creates safety queue cases) | Incident Report, Safety Violation, Good Catch |
Closeout templates (qc_layer3_prefinal, qc_layer3_final) are offered automatically when a job’s % Complete ≥ 95 (from CRM variance). No manual “Deploy to Field” is required for each closeout job, though admin deploy remains a valid override.
require_active_crew = false) so supers/foremen can complete punch and warranty sign-off after crew roll-off.Field user guide: Closeout QC & Job Checklists Help