ModulesPrestartsOverview

Prestarts

The Prestarts module handles daily safety checklists created by supervisors before each work shift. Prestarts capture shift details, weather forecasts, dynamic custom fields, activities with assigned resources, file attachments, sign-ons, and comments. This is the first “operational data entry” module — building on the custom fields configuration layer.

Lifecycle

Prestarts follow a two-stage lifecycle:

  1. Draft — Core fields (supervisor, datetime, duration, shift type, location) are editable. Activities, sign-ons, and comments can be added.
  2. Published — Core fields are locked. The briefed activities keep their plan, but their cost code and actual quantity can still change. Activities added after publish can be changed and deleted. Photos and files can still be added (they show as “Added after publish”), but not removed. Comments remain open for ongoing discussion.

Publishing is a one-way transition. Published prestarts will later create linked diary entries automatically.

Draft prestarts can be changed many at once from the list (supervisor, shift, duration, location) — see Bulk Edit & Undo.

Duplicated and new prestarts start at the project’s configured prestart time for the shift (Shift Configuration), falling back to a fixed time when none is set.

Data Model

Enums

EnumValuesDescription
prestart_statusdraft, publishedPrestart lifecycle stage
prestart_duration0, 15, 30, 60Toolbox talk duration (minutes)
shift_typeday, afternoon, nightShift type

Prestarts

ColumnTypeDescription
idUUIDPrimary key
project_idUUIDForeign key to projects
org_idUUIDForeign key to organizations (tenant isolation)
supervisor_idUUIDForeign key to users (supervisor running the prestart)
prestart_datetimeTIMESTAMPTZWhen the prestart occurs
durationprestart_durationToolbox talk duration in minutes
shift_typeshift_typeDay, afternoon, or night shift
site_locationTEXTFree-text location description
weather_dataJSONBStored weather forecast from Open Meteo
custom_field_valuesJSONBMap of field definition UUID to value
statusprestart_statusDraft or published
published_atTIMESTAMPTZWhen the prestart was published (NULL if draft)
diary_idUUIDFuture FK to diaries table
metadataJSONBExtensible unstructured data
deleted_atTIMESTAMPTZSoft-delete timestamp
created_atTIMESTAMPTZAuto-set on insert
updated_atTIMESTAMPTZAuto-updated via trigger

Indexes:

  • (org_id, project_id, status) WHERE deleted_at IS NULL — list queries with status filter
  • (org_id, project_id, supervisor_id) — filter by supervisor
  • (project_id, prestart_datetime DESC) WHERE deleted_at IS NULL — chronological listing

Activities

Activities are reusable work items linked to either a prestart or a diary (future). They describe the work to be performed during a shift.

ColumnTypeDescription
idUUIDPrimary key
prestart_idUUIDFK to prestarts (nullable, for diaries)
diary_idUUIDFuture FK to diaries
project_idUUIDFK to projects
org_idUUIDFK to organizations
descriptionTEXTActivity description (required)
custom_field_valuesJSONBDynamic field values
sort_orderINTEGERDisplay ordering
metadataJSONBExtensible data
deleted_atTIMESTAMPTZSoft-delete
created_atTIMESTAMPTZAuto-set
updated_atTIMESTAMPTZAuto-updated via trigger

Activity Resources

Many-to-many link between activities and users (workers assigned to the activity).

ColumnTypeDescription
idUUIDPrimary key
activity_idUUIDFK to activities
user_idUUIDFK to users
org_idUUIDFK to organizations
created_atTIMESTAMPTZAuto-set

Unique constraint on (activity_id, user_id).

Prestart Files

Attachments linked to either a prestart or an activity.

ColumnTypeDescription
idUUIDPrimary key
prestart_idUUIDFK to prestarts (nullable)
activity_idUUIDFK to activities (nullable)
org_idUUIDFK to organizations
file_nameTEXTOriginal filename
file_urlTEXTServer path to stored file
file_sizeBIGINTSize in bytes
mime_typeTEXTMIME type
uploaded_byUUIDFK to users
metadataJSONBExtensible data
deleted_atTIMESTAMPTZSoft-delete
created_atTIMESTAMPTZAuto-set

CHECK constraint: at least one of prestart_id or activity_id must be set.

Prestart Sign-Ons

Records which workers attended the prestart meeting.

Anyone with company-wide access (for example a Master Admin) can sign themselves on to any project in their organisation, including the office QR sign-on, without being added to the project first.

ColumnTypeDescription
idUUIDPrimary key
prestart_idUUIDFK to prestarts
user_idUUIDFK to users
org_idUUIDFK to organizations
project_idUUIDFK to projects (denormalized for NOTIFY)
signed_atTIMESTAMPTZWhen the user signed on
metadataJSONBExtensible data
created_atTIMESTAMPTZAuto-set

Unique constraint on (prestart_id, user_id).

Prestart Comments

Discussion threads on prestarts, available to any project member.

ColumnTypeDescription
idUUIDPrimary key
prestart_idUUIDFK to prestarts
user_idUUIDFK to users (comment author)
org_idUUIDFK to organizations
project_idUUIDFK to projects (denormalized for NOTIFY)
contentTEXTComment text
metadataJSONBExtensible data
deleted_atTIMESTAMPTZSoft-delete
created_atTIMESTAMPTZAuto-set
updated_atTIMESTAMPTZAuto-updated via trigger

Design note: project_id is denormalized on prestart_sign_ons and prestart_comments to enable zero-cost LISTEN/NOTIFY triggers. Without it, the trigger function would need to JOIN through the prestarts table to find the project_id, which is not possible in a simple trigger function.

API Endpoints

All endpoints are under /v1/orgs/{orgId}/projects/{projectId}/.

Prestarts

MethodPathAuthDescription
GET/prestartsAny project memberList with filters
POST/prestartsSupervisor+ or adminCreate draft
GET/prestarts/{prestartId}Any project memberFull detail
GET/prestarts/{prestartId}/adjacentAny project memberPrevious and next day (details)
PUT/prestarts/{prestartId}Creator or adminUpdate draft
POST/prestarts/{prestartId}/publishCreator or adminPublish
DELETE/prestarts/{prestartId}Creator or adminSoft delete

Activities

MethodPathAuthDescription
POST/prestarts/{prestartId}/activitiesCreator or adminAdd activity
PUT/prestarts/{prestartId}/activities/{activityId}Creator or adminUpdate activity
DELETE/prestarts/{prestartId}/activities/{activityId}Creator or adminRemove activity

Activity Resources

MethodPathAuthDescription
POST/prestarts/{prestartId}/activities/{activityId}/resourcesCreator or adminAssign user
DELETE/prestarts/{prestartId}/activities/{activityId}/resources/{userId}Creator or adminUnassign user

Files

MethodPathAuthDescription
POST/prestarts/{prestartId}/filesCreator or adminUpload to prestart
POST/prestarts/{prestartId}/activities/{activityId}/filesCreator or adminUpload to activity
DELETE/files/{fileId}Creator or adminRemove file

Sign-Ons

MethodPathAuthDescription
POST/prestarts/{prestartId}/sign-onsCreator or adminAdd sign-on
DELETE/prestarts/{prestartId}/sign-ons/{signOnId}Creator or adminRemove sign-on

Comments

MethodPathAuthDescription
GET/prestarts/{prestartId}/commentsAny project memberList comments
POST/prestarts/{prestartId}/commentsAny project memberAdd comment
PUT/prestarts/{prestartId}/comments/{commentId}Author onlyEdit comment
DELETE/prestarts/{prestartId}/comments/{commentId}Author or adminDelete comment

Weather

MethodPathAuthDescription
GET/weather?date=YYYY-MM-DDAny project memberFetch forecast using project lat/lng

Architecture

Real-Time Updates

All prestart tables fire LISTEN/NOTIFY triggers on the project_changes channel:

Postgres trigger fires → pg_notify('project_changes', payload)
Go WebSocket hub receives notification → broadcasts to org room
Browser WebSocket client receives message → TanStack Query cache invalidation

The INVALIDATION_MAP in ws-provider.tsx maps table names to query keys:

  • prestarts → ["prestarts", orgId, projectId] + ["prestart", orgId, projectId, prestartId]
  • activities → ["prestart", orgId, projectId]
  • prestart_sign_ons → ["prestart", orgId, projectId]
  • prestart_comments → ["prestart-comments", orgId, projectId] + ["prestart", orgId, projectId]

Weather Integration

The weather endpoint proxies the Open Meteo API. Projects must have latitude, longitude, and timezone configured (via the project detail Overview tab) for weather to work. The forecast is stored as JSONB in weather_data on the prestart.

Custom Field Values

Dynamic custom fields (configured at the org/project level) are stored as { "field-def-uuid": value } in the custom_field_values JSONB column on both prestarts and activities. Field definitions come from the custom_field_definitions table with entity_type = 'prestart_diary' or 'activity'.

Security

Tenant Isolation

Every query includes AND org_id = $org_id. The org_id is extracted from the verified session, never from request parameters.

Role-Based Access

ActionAllowed Roles
List/View prestartsAny project member
Create prestartsupervisor, senior_supervisor, master_admin, organisational_manager
Edit/Publish/DeletePrestart creator OR admin (master_admin, organisational_manager)
Manage activities/filesPrestart creator OR admin
Add/remove sign-onsPrestart creator OR admin
Add commentAny project member
Edit commentComment author only
Delete commentComment author OR admin

Input Validation

  • BFF (Next.js): Zod schemas validate all inputs before proxying to Go
  • Go API: Struct validation + UUID parsing on all path parameters
  • Database: Foreign key constraints, CHECK constraints, NOT NULL constraints

Key Files

FilePurpose
backend/db/migrations/007_prestarts.sqlSchema: 3 enums, 6 tables, indexes, triggers
backend/db/queries/prestarts.sql7 prestart queries (sqlc)
backend/db/queries/activities.sql8 activity + resource queries
backend/db/queries/prestart_files.sql3 file queries
backend/db/queries/prestart_sign_ons.sql3 sign-on queries
backend/db/queries/prestart_comments.sql4 comment queries
backend/api/internal/prestart/service.goBusiness logic (~930 lines)
backend/api/internal/prestart/handler.goHTTP handlers + routes (~860 lines)
backend/api/internal/weather/service.goOpen Meteo API client
backend/api/internal/weather/handler.goWeather HTTP handler
apps/web/src/actions/prestarts.ts20 BFF server actions
apps/web/src/actions/weather.tsWeather BFF action
apps/web/src/app/_components/prestart-detail.tsxDetail view with tabs
apps/web/src/app/_components/prestart-form.tsxCreate/edit form
apps/web/src/app/_components/prestart-comments.tsxComments section
apps/web/src/app/admin/prestarts/_components/prestart-table-v2.tsxPrestart list table