// Response shapes returned by the API. Dates are ISO 8601 strings. import type { actionKinds, actionStatuses, AreaKind, IncidentStatus, IncidentType, rcaMethods, Role, rootCauseCategories, Severity, } from './enums.ts' export type ActionKind = (typeof actionKinds)[number] export type ActionStatus = (typeof actionStatuses)[number] export type RcaMethod = (typeof rcaMethods)[number] export type RootCauseCategory = (typeof rootCauseCategories)[number] export interface UserRef { id: string name: string } export interface User { id: string email: string name: string role: Role active: boolean lastLoginAt: string | null createdAt: string } export interface Organization { id: string name: string } export interface Area { id: string siteId: string parentId: string | null name: string kind: AreaKind archivedAt: string | null } export interface Site { id: string name: string address: string | null timezone: string archivedAt: string | null areas: Area[] } export interface Incident { id: string number: number reference: string title: string type: IncidentType severity: Severity status: IncidentStatus occurredAt: string reportedAt: string updatedAt: string closedAt: string | null site: { id: string; name: string } area: { id: string; name: string } | null locationDetail: string | null description: string | null immediateAction: string | null anonymous: boolean reporter: UserRef | null /** Name given by someone reporting without an account. */ reporterName: string | null /** How the report arrived; `kiosk` covers kiosk tablets and QR codes on reporting links. */ channel: 'web' | 'kiosk' kiosk: { id: string; name: string } | null } export interface Kiosk { id: string name: string token: string site: { id: string; name: string } | null lastUsedAt: string | null revokedAt: string | null createdAt: string } /** What a reporting link may see: just enough to fill in the report form. */ export interface KioskConfig { organization: { name: string } kiosk: { name: string } sites: Site[] } export interface Investigation { id: string lead: UserRef | null method: RcaMethod summary: string | null startedAt: string completedAt: string | null } export interface RootCause { id: string category: RootCauseCategory description: string whys: string[] } export interface CorrectiveAction { id: string incident: { number: number; reference: string; title: string } rootCauseId: string | null kind: ActionKind title: string description: string | null assignee: UserRef | null dueDate: string | null status: ActionStatus overdue: boolean completedAt: string | null verifiedBy: UserRef | null verifiedAt: string | null createdAt: string } export interface Attachment { id: string fileName: string contentType: string sizeBytes: number uploadedBy: UserRef | null createdAt: string url: string } export interface TransitionOption { to: IncidentStatus label: string /** Why the transition can't happen yet; absent when it is allowed. */ blockedReason?: string } export interface IncidentDetail extends Incident { investigation: Investigation | null rootCauses: RootCause[] actions: CorrectiveAction[] attachments: Attachment[] transitions: TransitionOption[] /** What the signed-in user may do on this incident. */ can: { edit: boolean; manageInvestigation: boolean; manageActions: boolean } } export interface Comment { id: string author: UserRef | null body: string createdAt: string } export interface TimelineEntry { id: number at: string actor: UserRef | null action: string changes: Record | null } export interface Paginated { items: T[] page: number pageSize: number total: number } export interface OverviewStats { openIncidents: number reportedLast7Days: number actionsDueThisWeek: number overdueActions: number /** Average days from report to close for incidents closed in the last 90 days. */ averageCloseDays: number | null byStatus: Record actionProgress: { completed: number; total: number } /** Incidents per week for the last 12 weeks, oldest first. */ weeklyTrend: { weekStart: string; count: number }[] bySite: { siteId: string; name: string; count: number }[] } export interface AnalyticsStats { periodDays: number total: number byType: { type: IncidentType; count: number }[] bySeverity: { severity: Severity; count: number }[] topRootCause: { category: RootCauseCategory; count: number; share: number } | null /** Share of completed actions finished on or before their due date. */ onTimeActionRate: number | null monthlyCompletedActions: { month: string; onTime: number; late: number }[] }