Skip to content

Maintenance finalSnapshot behavior (locked)

Purpose

finalSnapshot is an immutable JSON column on maintenance_requests that captures a consistent, point-in-time view of a request when it becomes closed (terminal).

It exists so that:

  • UI can render closed tasks from a stable structure even if users are later renamed, deleted, or cache is cold.
  • Analytics and support can trust “what the ticket looked like at close” without recomputing from live joins.

Compliance / retention / erasure processes are out of scope for v1; may extend this column or externalize copies later.


When it is written

Created only when status first becomes a terminal value:

  • completed
  • cancelled
  • declined

Rules:

  1. Write once — never updated or recomputed after insert.
  2. Same transaction as the terminal status (and related timestamp/notes columns for that transition).
  3. If the transaction fails, neither terminal status nor snapshot should persist partially (implementation must enforce atomicity).

Closed tasks — UI data sources

Closed = status ∈ { completed, cancelled, declined } (see README).

DataSource
Structure: title, priority, category, location, department, relatedUsersfinalSnapshot (preferred)
Notes: cancellationNotes, declinedNotes, completion notes / hours (if present)Row columns
Timestamps: completedAt, cancelledAt, declinedAt, etc.Row columns

archivedAt does not change whether a task is closed.


Snapshot JSON shape (versioned)

Top-level v allows future migrations of the shape.

json
{
  "v": 1,
  "status": "cancelled",
  "takenAt": "2026-03-28T12:00:00.000Z",
  "relatedUsers": [
    {
      "id": "user-id",
      "name": "Jane Doe",
      "role": "employee",
      "type": "submittedBy",
      "profilePic": "https://…",
      "canViewProfile": true
    }
  ],
  "department": {
    "id": "dept-id",
    "name": "Engineering"
  },
  "title": "Fix HVAC",
  "priority": "high",
  "category": "hvac",
  "location": "Building A"
}

Required fields (v: 1)

FieldDescription
vSchema version (1).
statusTerminal status at write time.
takenAtISO timestamp when the snapshot was taken (same moment as terminal transition commit).
relatedUsersArray per Missing users; no email.
department{ id, name }department is part of the snapshot (frozen at terminal time).
title, priority, category, locationCopy of display fields at terminal time.

Notes (cancellationNotes, declinedNotes, completion bodies) are not duplicated inside v: 1 by default; they live on the row (see README).


Missing users (structured fallback)

If a referenced user cannot be resolved at snapshot write time, include a placeholder entry:

json
{
  "id": "original-user-id",
  "name": null,
  "role": "employee",
  "type": "submittedBy",
  "profilePic": null,
  "canViewProfile": false,
  "isMissing": true,
  "missingReason": "USER_DELETED"
}

Live relatedUsers (non-closed) uses the same shape when a user is missing (see ../cache/user.md).


Cache interaction (read path)

Task staterelatedUsers source
Open (pending, in_progress)Built from live user cache + row IDs
ClosedrelatedUsers inside finalSnapshot only (do not rebuild from live cache for display authority)

Active tasks: resolve names/avatars via central user cache; DB stores IDs only on the maintenance row.


List vs detail (takenAt)

EndpointfinalSnapshottakenAt field
ListDo not embed full snapshotSee below
DetailInclude full finalSnapshot for closed tasksN/A as list field

takenAt on list items

Row statetakenAt
Closed (completed, cancelled, declined)finalSnapshot.takenAt (must exist)
Not closed (pending, in_progress)null

Do not infer a synthetic takenAt for open tasks from updatedAt in v1 (keeps semantics explicit).


Purge and snapshot

Hard delete removes the row; finalSnapshot is lost unless copied elsewhere. Audit / maintenance logs should record purge metadata (see product rules). Implementation detail: log structured meta on purge for traceability.