feat(board): daily board linked to shots

A /board page that replaces the shared doc used as the day-to-day tracker.
One card per active/on-hold project with a status line, dated milestones
and to-do lines typed or pasted in the doc's own format:

  DH2_VFX_027_090 finalise (CHRIS)
  DH2_VFX_005_010 gfx update @michelle wait: client GFX ADH_GFX_005_020

Shot codes link to the shot (live status + latest version), (NAME)/@name
assigns, wait: marks a blocker, headings group lines. Codes that match no
shot are flagged, with a relink when there is an obvious near miss.

Board lines are their own model, not Tasks: tasks drive shot status and
notifications, and a note like "finalise" must not touch either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
twotalesanimation
2026-10-07 17:30:40 +02:00
parent 27d9618995
commit 34af26dfbf
8 changed files with 1331 additions and 0 deletions
+61
View File
@@ -262,6 +262,7 @@ model User {
createdShootDays ShootDay[] @relation("ShootDayCreator")
createdTakes Take[] @relation("TakeCreator")
uploadedTakeAttachments TakeAttachment[] @relation("TakeAttachmentUploader")
assignedBoardItems BoardItem[] @relation("BoardItemAssignee")
@@map("users")
}
@@ -382,6 +383,14 @@ model Project {
deliveryPackages DeliveryPackage[]
deliveryRequests DeliveryRequest[]
/// The one-line "where are we" on the daily board ("Official bid sent",
/// "Awaiting feedback on pick-ups"). Free text on purpose: it is what the
/// producer would have typed at the top of the project's section in the doc.
boardStatus String? @db.Text
boardStatusAt DateTime?
boardItems BoardItem[]
milestones ProjectMilestone[]
@@map("projects")
}
@@ -487,6 +496,7 @@ model Shot {
loggedTakes Take[] @relation("TakeToShot")
exports Export[]
deliveryRequestLines DeliveryRequestLine[]
boardItems BoardItem[]
@@unique([projectId, shotCode])
@@map("shots")
@@ -1255,6 +1265,57 @@ model DeliveryRequestLine {
@@map("delivery_request_lines")
}
/// A line on the daily board — the day-to-day to-do the team used to keep in
/// a shared doc ("DH2_VFX_027_090 finalise (CHRIS)"). Deliberately not a Task:
/// tasks are the pipeline's one-per-shot work items whose state drives shot
/// status, and a note like "finalise" or "awaiting gfx" must not move a shot
/// back to IN_PROGRESS or notify anyone.
///
/// `code` is the shot code as typed. When it matches a shot, `shotId` links it
/// and the board shows the shot's live status; when it does not, the line is a
/// flag ("not on our tracker?") until the shot exists or the code is fixed.
model BoardItem {
id String @id @default(cuid())
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
shotId String?
shot Shot? @relation(fields: [shotId], references: [id], onDelete: SetNull)
code String?
text String @db.Text
/// Heading the line sits under on the board ("WATER DROPS"); "" = none
group String @default("")
assigneeId String?
assignee User? @relation("BoardItemAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
/// What the line is blocked on ("client GFX ADH_GFX_013_010"); null = not blocked
waitingOn String?
sortOrder Int @default(0)
doneAt DateTime?
doneById String?
createdById String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([projectId, doneAt])
@@index([shotId])
@@map("board_items")
}
/// A dated project milestone — batch deliveries, picture locks, shoot start,
/// colour & mix review. Episode due dates stay in EpisodeDueDate because the
/// shot-status board keys off them; these are the dates around the work.
model ProjectMilestone {
id String @id @default(cuid())
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
label String
date DateTime
doneAt DateTime?
createdAt DateTime @default(now())
@@index([projectId, date])
@@map("project_milestones")
}
model SketchTemplate {
id String @id @default(cuid())
name String