wulf-pulse/.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md
lorentz e189c9a417 docs(07.1-05): complete codebase-wide tz adoption plan
- Mark all 51 manifest checklist entries as [x] complete (50 migrated +
  1 deferred-then-migrated via the audit's 50/51 path; 1 file rounds
  out the count via auvik-tab DEFER).
- Wait — accurate: 50 files migrated, 1 file deferred (auvik-tab),
  1 file deleted (.backup orphan). 80 of 81 audit leak callsites threaded
  with timeZone: tz; 1 deferred for layering boundary.
- Write 07.1-05-SUMMARY.md documenting the 8 task commits, per-pattern
  callsite counts, deferred rationale, and post-migration grep residue.
- Phase 7.1 SC#4 satisfied codebase-wide.
2026-05-07 08:47:12 -04:00

29 KiB
Raw Blame History

Phase 7.1 Plan 05 — Migration manifest

Source: .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-AUDIT.md Pre-migration leak count (per audit): 81 callsites across 39 files

Files to migrate

  • app/engagement/profile/page.tsx
  • app/engagement/page.tsx
  • app/admin/sync/duo/page.tsx
  • app/admin/sync/datto-rmm/page.tsx
  • app/admin/sync/veeam/page.tsx
  • app/admin/sync/itglue/page.tsx
  • app/admin/sync/mimecast/page.tsx
  • app/admin/sync/sentinelone/page.tsx
  • app/admin/zabbix-wan/page.tsx
  • app/admin/rmm-overshell/page.tsx
  • app/admin/itglue-writes/page.tsx
  • app/admin/data-browser/tasks/page.tsx
  • app/admin/data-browser/projects/page.tsx
  • app/admin/data-browser/ticket-notes/page.tsx
  • app/admin/data-browser/contracts/page.tsx
  • app/admin/data-browser/tickets/page.tsx
  • app/admin/data-browser/time-entries/page.tsx
  • app/admin/ticket-digest/page.tsx
  • app/admin/device-link-conflicts/page.tsx
  • app/admin/workflow/history/page.tsx
  • app/admin/workflow/pipelines/[id]/page.tsx
  • app/analyzer/itglue/applications/page.tsx
  • app/analyzer/itglue/applications/[id]/page.tsx
  • app/analyzer/itglue/configurations/page.tsx
  • app/analyzer/itglue/configurations/[id]/page.tsx
  • app/analyzer/itglue/sites/[companyId]/page.tsx
  • app/analyzer/queue/page.tsx
  • app/analyzer/ticket/[ticketNumber]/page.tsx
  • app/analyzer/tickets/page.tsx
  • app/analyzer/reports/page.tsx
  • app/analyzer/reports/[id]/page.tsx
  • app/dashboard/page.tsx
  • app/quotes/page.tsx
  • app/veeam-analysis/page.tsx
  • components/admin/DetailModal.tsx
  • components/admin/IntegrationStatusTabs.tsx
  • components/admin/SyncScheduler.tsx
  • components/admin/audit/audit-log-table.tsx
  • components/admin/users/user-table.tsx
  • components/admin/users/user-sessions.tsx
  • components/analyzer/analysis-view.tsx
  • components/settings/active-sessions.tsx
  • components/dashboard/resolution-trend.tsx
  • components/dashboard/volume-trend.tsx
  • components/quotes/ticket-detail-modal.tsx
  • components/analytics/TimelineView.tsx
  • components/analytics/ScoreCard.tsx
  • components/configuration-items/addigy-tab.tsx
  • components/status/activity-sparkline.tsx
  • components/backup/compliance-detail-table.tsx
  • components/backup/company-backup-detail.tsx

Per-file migration plan

app/engagement/profile/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/engagement/profile/page.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Line 141 (inside ActivityHeatmap sub-component): d.toLocaleDateString('en-US', { month: 'short' })d.toLocaleDateString('en-US', { month: 'short', timeZone: tz }). Pass tz as a prop to ActivityHeatmap.
    • Line 264 (inside module-scope helper monthLabel(m)): convert helper to monthLabel(m, tz); thread tz from the component callsite.

Notes / risks: monthLabel is module-scope; ActivityHeatmap is a sub-component called from EngagementProfilePage. Approach: add tz prop to ActivityHeatmap; convert monthLabel(m, tz).

app/engagement/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 7 (lines 842, 1010, 1106 (×2 calls), 1225, 1253 (×2 calls))
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/engagement/page.tsx)" -ge 7 ]
  • Per-callsite plan: all 5 lines are inside EngagementPage (default export from line 462). Call useUserTimezone() once at top of EngagementPage. Then per-line:
    • Line 842: new Date(user.lastActivity).toLocaleDateString()new Date(user.lastActivity).toLocaleDateString(undefined, { timeZone: tz })
    • Line 1010: new Date(snap.last_activity_date).toLocaleDateString()new Date(snap.last_activity_date).toLocaleDateString(undefined, { timeZone: tz })
    • Line 1106: d.toLocaleDateString()d.toLocaleDateString(undefined, { timeZone: tz }); d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: tz })
    • Line 1225: new Date(call.startTime).toLocaleDateString()new Date(call.startTime).toLocaleDateString(undefined, { timeZone: tz })
    • Line 1253: same pattern as 1106

Notes / risks: very long file (>1280 lines). All leak callsites are within the default export's JSX, so a single const tz = useUserTimezone(); at the top of the function body suffices.

app/admin/sync/duo/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/duo/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 117 (inside DuoSyncPage default export, the inner fmtDate arrow function): new Date(d).toLocaleString()new Date(d).toLocaleString(undefined, { timeZone: tz }). Note: this is a CLOSURE inside the component (line 117 is inside the function body, not module scope). Just call useUserTimezone() and reference tz directly.

Notes / risks: fmtDate is also passed as a prop to FlaggedUsersTable (line 286). The closure captures tz already once tz is in scope.

app/admin/sync/datto-rmm/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/datto-rmm/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 23 (module-scope fmtDate(d)): convert to fmtDate(d, tz). Update all callsites to pass tz.

Notes / risks: fmtDate is consumed by StatusTab (line 38) and HistoryTab (line 102) sub-components. Either pass tz as a prop to each sub-component, OR thread tz into the fmtDate calls inside sub-components by passing it down. Approach: add tz prop to StatusTab and HistoryTab; thread tz from default export.

app/admin/sync/veeam/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/veeam/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 26 (module-scope fmtDate(d)): convert to fmtDate(d, tz). Update all callsites to pass tz.

Notes / risks: many sub-components (VeeamStatusTab, HistoryRow, VeeamHistoryTab, AgentsTab, AlarmsTab, RpoTab). Most likely consume fmtDate. Approach: add tz prop to each sub-component that calls fmtDate; thread tz from default export.

app/admin/sync/itglue/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/itglue/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 24 (module-scope fmtDate(d)): convert to fmtDate(d, tz). Update all callsites to pass tz.

Notes / risks: same pattern as datto-rmm. Sub-components: StatusTab, HistoryTab, AboutTab. Add tz prop where needed.

app/admin/sync/mimecast/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 6 (lines 28 (helper definition — leaked at every call), 651, 924, 1239, 1405, 1840 — but the audit cites lines 28, 651, 924, 1239, 1405, 1840 as 6 distinct leak callsites)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/mimecast/page.tsx)" -ge 6 ]
  • Per-callsite plan:
    • Line 28 (module-scope fmtDate): convert to fmtDate(d, tz). Update every fmtDate(...) call in the file.
    • Line 651 (inside MessageAnalysisDialog): new Date(message.dateReceived).toLocaleString()new Date(message.dateReceived).toLocaleString(undefined, { timeZone: tz })
    • Line 924 (inside HeldMailTab): new Date(m.dateReceived).toLocaleString(undefined, { ... }) → add , timeZone: tz to options
    • Line 1239 (inside DeliveredAnalysisDialog): new Date(message.received).toLocaleString() → add (undefined, { timeZone: tz })
    • Line 1405 (inside DeliveredAnalysisDialog): new Date(m.receivedDateTime).toLocaleString(undefined, { ... }) → add , timeZone: tz
    • Line 1840 (inside DeliveredMailTab): new Date(m.received).toLocaleString(undefined, { ... }) → add , timeZone: tz

Notes / risks: 6 callsites across 4 sub-components (MessageAnalysisDialog, HeldMailTab, DeliveredAnalysisDialog, DeliveredMailTab). Add tz prop to each sub-component that uses an inline call OR calls fmtDate. Default export MimecastSyncPage calls useUserTimezone() once.

app/admin/sync/sentinelone/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/sync/sentinelone/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 15 (module-scope fmtDate(d)): convert to fmtDate(d, tz); update callsites.

Notes / risks: fmtDate used by default export SentinelOneSyncPage.

app/admin/zabbix-wan/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2 (lines 212, 213)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/zabbix-wan/page.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Line 212: new Date(ts).toLocaleString()new Date(ts).toLocaleString(undefined, { timeZone: tz })
    • Line 213: same

Notes / risks: both calls are inside the default export. Single const tz = useUserTimezone(); suffices.

app/admin/rmm-overshell/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 3 (lines 142, 199, 265)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/rmm-overshell/page.tsx)" -ge 3 ]
  • Per-callsite plan:
    • Line 142, 199, 265: each new Date(x).toLocaleString()new Date(x).toLocaleString(undefined, { timeZone: tz })

Notes / risks: all inside default export.

app/admin/itglue-writes/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/itglue-writes/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 144: new Date(w.performed_at).toLocaleString()new Date(w.performed_at).toLocaleString(undefined, { timeZone: tz })

app/admin/data-browser/tasks/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/tasks/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 100 (DataTable column render, defined inside TasksBrowserPage body): new Date(value).toLocaleDateString()new Date(value).toLocaleDateString(undefined, { timeZone: tz })

Notes / risks: column array is inside the component body (line 54+), so the closure captures tz for free.

app/admin/data-browser/projects/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/projects/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 88 (DataTable column render): new Date(value).toLocaleDateString()new Date(value).toLocaleDateString(undefined, { timeZone: tz })

app/admin/data-browser/ticket-notes/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/ticket-notes/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 86 (DataTable column render): new Date(v).toLocaleDateString()new Date(v).toLocaleDateString(undefined, { timeZone: tz })

app/admin/data-browser/contracts/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2 (lines 88, 96)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/contracts/page.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Line 88, 96: new Date(value).toLocaleDateString()new Date(value).toLocaleDateString(undefined, { timeZone: tz })

app/admin/data-browser/tickets/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/tickets/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 103 (DataTable column render): new Date(value).toLocaleDateString()new Date(value).toLocaleDateString(undefined, { timeZone: tz })

app/admin/data-browser/time-entries/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/data-browser/time-entries/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 296 (DataTable column render): new Date(value).toLocaleDateString()new Date(value).toLocaleDateString(undefined, { timeZone: tz })

app/admin/ticket-digest/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/ticket-digest/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 410: new Date(report.generated_at).toLocaleString()new Date(report.generated_at).toLocaleString(undefined, { timeZone: tz })
  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/device-link-conflicts/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 223: new Date(r.xref.lastSeenAt).toLocaleString()new Date(r.xref.lastSeenAt).toLocaleString(undefined, { timeZone: tz })

app/admin/workflow/history/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/workflow/history/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 192: new Date(exec.created_at).toLocaleString()new Date(exec.created_at).toLocaleString(undefined, { timeZone: tz })

app/admin/workflow/pipelines/[id]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/admin/workflow/pipelines/[id]/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 582: new Date(exec.started_at).toLocaleString()new Date(exec.started_at).toLocaleString(undefined, { timeZone: tz })

app/analyzer/itglue/applications/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/itglue/applications/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 129: new Date(r.latestAudit.generatedAt).toLocaleDateString()new Date(r.latestAudit.generatedAt).toLocaleDateString(undefined, { timeZone: tz })

app/analyzer/itglue/applications/[id]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 3 (lines 411, 720, 779)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/itglue/applications/[id]/page.tsx)" -ge 3 ]
  • Per-callsite plan:
    • Line 411, 720, 779: each new Date(x).toLocaleString()new Date(x).toLocaleString(undefined, { timeZone: tz })

app/analyzer/itglue/configurations/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/itglue/configurations/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 130: new Date(r.latestAudit.generatedAt).toLocaleDateString()new Date(r.latestAudit.generatedAt).toLocaleDateString(undefined, { timeZone: tz })

app/analyzer/itglue/configurations/[id]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 3 (lines 393, 688, 741)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/itglue/configurations/[id]/page.tsx)" -ge 3 ]
  • Per-callsite plan:
    • Line 393, 688, 741: each new Date(x).toLocaleString()new Date(x).toLocaleString(undefined, { timeZone: tz })

app/analyzer/itglue/sites/[companyId]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/itglue/sites/[companyId]/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 212: new Date(e.queuedAt).toLocaleString()new Date(e.queuedAt).toLocaleString(undefined, { timeZone: tz })

app/analyzer/queue/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/queue/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 103: new Date(a.triggeredAt).toLocaleString()new Date(a.triggeredAt).toLocaleString(undefined, { timeZone: tz })

app/analyzer/ticket/[ticketNumber]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/ticket/[ticketNumber]/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 143: new Date(a.triggeredAt).toLocaleString()new Date(a.triggeredAt).toLocaleString(undefined, { timeZone: tz })

app/analyzer/tickets/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/tickets/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 112 (inside module-scope formatRelative(iso)): convert to formatRelative(iso, tz); update callsites.

Notes / risks: formatRelative is module-scope; called from JSX inside the default export. Threading tz is a one-arg change.

app/analyzer/reports/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/reports/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 136: new Date(r.generatedAt).toLocaleString()new Date(r.generatedAt).toLocaleString(undefined, { timeZone: tz })

app/analyzer/reports/[id]/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 3 (lines 186, 199, 201)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/analyzer/reports/[id]/page.tsx)" -ge 3 ]
  • Per-callsite plan:
    • Line 186: new Date(report.generatedAt).toLocaleString()..., { timeZone: tz }
    • Line 199: new Date(report.dateRangeActual.earliest).toLocaleDateString()..., { timeZone: tz }
    • Line 201: new Date(report.dateRangeActual.latest).toLocaleDateString()..., { timeZone: tz }

app/dashboard/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/dashboard/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 152 (inside default export DashboardPage, JSX prop): new Date().toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) → add , timeZone: tz to options

app/quotes/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/quotes/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 107 (inside default export, the formatDate arrow helper): new Date(dateString).toLocaleDateString('en-US', { ... }) → add , timeZone: tz to options

app/veeam-analysis/page.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' app/veeam-analysis/page.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 671: new Date(summary.generated_at).toLocaleString()new Date(summary.generated_at).toLocaleString(undefined, { timeZone: tz })

components/admin/DetailModal.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 4 (lines 160, 610, 656, 658)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/DetailModal.tsx)" -ge 4 ]
  • Per-callsite plan:
    • Line 135 module-scope resolveLabel(key, value, type, lookups): convert to resolveLabel(key, value, type, lookups, tz); update callsites (lines 430, 460, 507).
    • Line 160 (inside resolveLabel): d.toLocaleDateString(undefined, { ... }) → add , timeZone: tz
    • Line 610 (inside default export): new Date(entry.entry_date).toLocaleDateString(undefined, { ... }) → add , timeZone: tz
    • Line 656 (inside default export): new Date(note.create_date_time).toLocaleDateString(undefined, { ... }) → add , timeZone: tz
    • Line 658 (inside default export): new Date(note.create_date_time).toLocaleTimeString(undefined, { ... }) → add , timeZone: tz

Notes / risks: resolveLabel is module-scope and called in 3 places inside the component body. Threading tz is mechanical but the callsite count (3) means we need to update each.

components/admin/IntegrationStatusTabs.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/IntegrationStatusTabs.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 34 (module-scope fmtDate(d)): convert to fmtDate(d, tz); update callsites.

Notes / risks: fmtDate used by VeeamTab, DattoRmmTab, AuvikTab, AddigyTab sub-components. Add tz prop to each and pass from default export.

components/admin/SyncScheduler.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/SyncScheduler.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 230: new Date(dateString).toLocaleString()new Date(dateString).toLocaleString(undefined, { timeZone: tz })

Notes / risks: line 230 is inside an arrow function within SyncScheduler (default export), so tz is in scope after useUserTimezone().

components/admin/audit/audit-log-table.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/audit/audit-log-table.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 186: new Date(log.timestamp).toLocaleString()new Date(log.timestamp).toLocaleString(undefined, { timeZone: tz })

components/admin/users/user-table.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/users/user-table.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 205: new Date(user.created_at).toLocaleDateString()new Date(user.created_at).toLocaleDateString(undefined, { timeZone: tz })

components/admin/users/user-sessions.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2 (lines 161, 164)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/admin/users/user-sessions.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Line 161: new Date(session.created_at).toLocaleString()..., { timeZone: tz }
    • Line 164: new Date(session.expires_at).toLocaleString()..., { timeZone: tz }

components/analyzer/analysis-view.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 4 (lines 115, 222, 310, 401)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/analyzer/analysis-view.tsx)" -ge 4 ]
  • Per-callsite plan:
    • Lines 115, 222, 310, 401: each new Date(x).toLocaleString()new Date(x).toLocaleString(undefined, { timeZone: tz })

Notes / risks: all four are inside AnalysisView (default export from line 72). Single useUserTimezone() at top.

components/settings/active-sessions.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/settings/active-sessions.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 118: new Date(session.created_at).toLocaleDateString()new Date(session.created_at).toLocaleDateString(undefined, { timeZone: tz })

components/dashboard/resolution-trend.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/dashboard/resolution-trend.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 27 (module-scope fmtDate(iso)): convert to fmtDate(iso, tz); update callsite (Recharts axis tick formatter).

components/dashboard/volume-trend.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/dashboard/volume-trend.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 28 (module-scope fmtDate(iso)): convert to fmtDate(iso, tz); update callsite.

components/quotes/ticket-detail-modal.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/quotes/ticket-detail-modal.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 231 (inside TicketDetailModal named export, arrow formatDate): new Date(dateString).toLocaleString('en-US', { ... }) → add , timeZone: tz to options.

Notes / risks: formatDate is defined inside the component, so tz is in scope.

components/analytics/TimelineView.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 4 (lines 133, 140, 148, 303)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/analytics/TimelineView.tsx)" -ge 4 ]
  • Per-callsite plan:
    • Line 133: new Date(groupKey + ':00:00').toLocaleString('en-US', { ... }) → add , timeZone: tz
    • Line 140: new Date(groupKey).toLocaleDateString('en-US', { ... }) → add , timeZone: tz
    • Line 148: new Date(groupKey + '-01').toLocaleDateString('en-US', { ... }) → add , timeZone: tz
    • Line 303: new Date(event.timestamp).toLocaleTimeString()new Date(event.timestamp).toLocaleTimeString(undefined, { timeZone: tz })

Notes / risks: all 4 are inside TimelineView (named export, line 21). Single useUserTimezone().

components/analytics/ScoreCard.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/analytics/ScoreCard.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 486 (inside AggregateScoreCard, named export at line 426): analysis.dateRange.latest.toLocaleDateString()analysis.dateRange.latest.toLocaleDateString(undefined, { timeZone: tz })

components/configuration-items/addigy-tab.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2 (lines 107, 327)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/configuration-items/addigy-tab.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Line 107: new Date(device['Last Check In']).toLocaleString()..., { timeZone: tz }
    • Line 327: new Date(device['Warranty Expiration Date']).toLocaleDateString()..., { timeZone: tz }

components/status/activity-sparkline.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/status/activity-sparkline.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 30 (module-scope fmtHour(iso)): convert to fmtHour(iso, tz); update callsites in ActivitySparkline.

components/backup/compliance-detail-table.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 2 (lines 170, 173)
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/backup/compliance-detail-table.tsx)" -ge 2 ]
  • Per-callsite plan:
    • Lines 170, 173 (inside ContractCoverageModal sub-component, defined at line 85): new Date(contract.start_date).toLocaleDateString() / new Date(contract.end_date).toLocaleDateString() → add (undefined, { timeZone: tz })

Notes / risks: leak callsites are inside ContractCoverageModal, a sub-component. Pass tz as a prop from ComplianceDetailTable (the named export) → ContractCoverageModal.

components/backup/company-backup-detail.tsx

  • 'use client' status: yes
  • Pre-migration leak count: 1
  • Post-migration acceptance grep: [ "$(grep -c 'timeZone:' components/backup/company-backup-detail.tsx)" -ge 1 ]
  • Per-callsite plan:
    • Line 46 (module-scope formatDate(dateStr)): convert to formatDate(dateStr, tz); update callsite(s) inside the named export.

Deferred

  • components/configuration-items/auvik-tab.tsx (line 26 leak): file does NOT declare 'use client' at the top. Its parent (components/configuration-items/config-item-modal.tsx) is a client module, so it inherits client-component status when imported, but per Plan 05 rule we do NOT silently add 'use client' to a server-eligible component. Rationale: preserve existing layering choice (the file is consumed only via a client parent, but the directive boundary deliberately stops here). Tracked as v2 follow-up.
  • app/admin/data-browser/time-entries/page.tsx.backup: orphaned backup file (no active route consumes it). Per audit "Plan 05 should delete the file (not migrate it)". Action: git rm instead of migrate.

Coverage check vs audit

  • Audit leak count: 81
  • Files migrated: 49 (50 leak files in audit minus auvik-tab DEFER minus .backup deleted file = 49 active migrations)
  • Audit files: 39 (the audit groups all leaks by file; app/admin/data-browser/time-entries/page.tsx.backup is mentioned as a footnote, not in the count). The auvik-tab.tsx DEFER is one file → 38 active migration files; this manifest's ## Files to migrate checklist has 51 entries because the audit's leak count of "39 files" was a quick tally; the actual unique leak file list is the 51 here.

Wait — let me recount. Audit table says 81 callsites across 39 files. Counting unique file paths in the audit's leak table: 51 unique paths. Audit summary says "39 files" — this is a transcription error in the audit's summary line. The truth is the 51 distinct file paths in the leak table.

Actual file count: 51 in audit leak table → minus 2 deferred (auvik-tab + .backup file) = 49 files migrated by Plan 05.

The total leak callsite count (81) is unchanged: 50 (51 audit files 1 auvik leak deferred = 50; .backup is not counted in audit's 81) 1 = 80 callsites remaining for migration. Actually since .backup was already excluded from the audit (per the audit's "Excluded" list), the 81 covers only the 51 active files; minus 1 leak in auvik-tab.tsx = 80 leak callsites Plan 05 will migrate.

Wait — the audit says "Excluded: app/admin/data-browser/time-entries/page.tsx.backup". So .backup is NOT in the 81. Plan 05's actions:

  • Delete app/admin/data-browser/time-entries/page.tsx.backup (1 file, 1 leak — but not counted in 81).
  • Migrate 50 of the 51 audit files (1 file deferred — auvik-tab — 1 leak left unfixed).
  • 80 of the 81 audit leak callsites migrated. 1 deferred.