Skip to content

Data model

The data model follows one idea: field events are the evidence; everything the system writes is drawn from them. Each record below belongs to one of six kinds, and the kind decides who may write it. Model names are the Prisma schema’s (packages/db/prisma/schema/), which is the source of truth for every field, enum and model name.

Client ──► Project ◄── DeclarationEvent (a project: one client, one declaration event)
│
├── Contract (a prime) ──► Rule ──► RuleCriterion, RuleAction ──► PayItem
├── Form ──► FormDebrisType PayItem ──► PayItemRate (one per prime)
├── DisposalSite, MapVersion ──► Zone
├── Certification ──► CertificationBox
├── Roe ──► RoeScopeItem
├── Assignment (a person, a day, their work, a site, a phone)
│
└── FieldEvent (COL · DIS · HOC · HOD · URT), grouped by workflow + bare ticket number
│
▼ the worker
CompletedLoad / CompletedHaulOut · Transaction · Flag · ReconciliationRun
RecordsWhat they are
Client, DeclarationEventThe jurisdiction paying; the disaster and its reference (DR-9001-FL), shared by many clients’ projects
ContractorA hauling company (or a monitoring sub, such as a temp agency): a prime on a project, or a sub typed in at certification, at most two tiers
User, UserPermission, ViewerProjectPeople with a login: admins, managers/analysts (with their grants), field monitors, read-only viewers (with their projects)
Device, MasterPasscode, FirmSettingsEnrolled phones; the firm’s one master passcode (only its slow hash); the installation’s settings, such as what the firm calls its ADMS
The firm’s listsProgramType, DebrisType, PayableType, KindOfWork, ItemName, VehicleType, VehicleFeature, CrewType, SiteType, SiteLabel, IncidentType, Reason, SurveyWorkType, ClockActivity, FieldTag, … (see Lists)
RecordsWhat they are
ProjectOne body of work for one client under one declaration event: program type, active window, time zone, how tickets are numbered, split loads allowed, its check settings
ContractA name, its prime and an optional link to the signed copy
Form, FormDebrisType, FormDefinitionOne form per kind of document; the debris types added to it; the firm’s own fields
PayItem, PayItemRate, PayItemCrewDayStepA priced line of the contract, a rate for each prime, crew-day steps
Rule, RuleCriterion, RuleActionPricing: one contract, its ifs, its actions (Add, Remove, Void ticket)
DisposalSite, SiteAreaVersion, DisposalSiteTippingFeeWhere debris goes, its type and facts, its area, the pay item for its tipping fee
MapVersion, ZoneThe project’s boundary and zones, by version
NumberSeries, NumberBlock, ControlRangeTicket, cert and ROE number series, the blocks phones hold, the ranges of pre-printed stock
Certification, CertificationBoxA container or a crew, its measured boxes (capacity is computed from them)
Roe, RoeScopeItemA right of entry and its scope
AssignmentOne person’s work for one day
RecordsWhat they are
FieldEventOne model, five kinds: collection, disposal, haul-out collection, haul-out disposal, unit rate. Its ticket number, times with the phone’s offset, GPS as exact decimals, the cert number as scanned, debris type, load call or weight, measurement, the assignment and setup version it was made under
FieldEventItem, CarriedTicket, FieldEventWaypointItemised counts and hours; tickets a load carries; waypoints marked on a collection
ScaleReceiptA hand-transcribed scale receipt, referenced by the disposals it weighs
Survey, Incident, DropOffLogForms: records, never a ticket’s field events
Photo, PhotoFilePhotograph metadata (its hash taken at capture); the files themselves live in object storage
ClockEntryTime-clock entries
Sync, SyncedRecord, QuarantinedRecord, HeldRecordWhat each sync sent and was answered; duplicates kept in full; records held for a person
RecordsWhat they are
CompletedLoad, CompletedHaulOutThe record concluded from a ticket’s field events. Its links to its field events are unique, so one load never bills twice
TransactionOne priced line, regenerated whenever its ticket changes
FlagA problem, with its code and the facts it was raised on
ReconciliationRun, ReconciliationDecision, ReconciliationJobEach run of the worker, what it decided, and the job queue

Marks: what people set, without changing the record

Section titled “Marks: what people set, without changing the record”

QcMark, InvoiceLock, InvoiceBatch, FlagAcceptance, TicketVoid, TicketUnvoid and DayApproval are records of their own, keyed to what they mark, written by the API. A reprocess never loses one, and the API never writes a derived record.

AuditRecord holds every insert and update on a tracked table: prior and new values, the fields that changed, the actor, the device, the source, the reason and the request. The database writes it by trigger and refuses a write with no actor; no role may change or remove one. SecurityEvent records every sign-in, failure, lockout, phone setup and use of the master passcode.

  • Any hard delete of operational data: records are archived, closed or voided.
  • Any update or delete of an AuditRecord.
  • A write with no actor.
  • A completed load, haul-out or transaction written by anyone but the worker’s login.
  • A transaction removed without its full row copied to the audit log first, or on a ticket locked as invoiced.
  • A second pay item with the same code on a project; two completed records on the same field event.
  • A read beyond what a viewer may see: row-level security, not only the screens.

Some sets are fixed in code because each value is a piece of behaviour: field event kinds, workflows (LOAD, HAUL_OUT, UNIT_RATE), statuses (PENDING, COMPLETED, MANUAL_REVIEW, VOID), QC statuses, billing units (CY, TN, EA, LB, HR, CREW_DAY, TBN), site facts, rule actions, user roles and flag codes. See Lists.