Project 09 / 09

Time Tracker

AutoCAD and SOLIDWORKS add-ins that measure the time a designer actually spends on each die design and post it to the Design Desk API on the company's War Room server, where it is compared against the design's estimate.

  • C# (.NET 8 / .NET 10)
  • WPF
  • AutoCAD .NET API (2025–2027)
  • SOLIDWORKS API (COM)
  • MSAL / Microsoft Entra ID
  • ClosedXML
  • Inno Setup
  • PowerShell
7,201
lines of code
4
CAD hosts: AutoCAD 2025-27 + SOLIDWORKS
1 s
sampling, foreground time only
64
contract test assertions

At a glance

Hand-written code 7,201 lines in 35 files
Hosts AutoCAD 2025, 2026 and 2027 (three builds) and SOLIDWORKS 2024
Sign-in Microsoft Entra single sign-on; the server maps the user to their Plex designer
Sampling Once a second; counts only foreground, active, non-idle time on the mapped drawing
Delivery Durable on-disk outbox with exactly-once acknowledgement and an audit log
Contract tests 64 assertions against simulated server responses
Installers Machine-wide Inno Setup installers for both hosts

Lines of code

Language Lines Files Role
C# 5,609 24 Add-in hosts, sampler, sync, sign-in, workbook, contract tests
XAML 724 3 WPF tracker, log and debug windows
Inno Setup 480 2 AutoCAD and SOLIDWORKS installers
PowerShell 207 3 Installer builds, isolated-server test script
MSBuild 181 3 Per-version AutoCAD targeting
Total 7,201 35

The problem

Die designs are quoted with an estimated number of design hours, but nobody knew the real number. Time was kept by hand in a shared Excel workbook, if at all. The War Room server already holds every design job from the Plex ERP and its estimate. The missing piece was an honest actual: time measured inside the CAD tool, tied to the right job, that can't be inflated by a drawing left open over lunch.

 AutoCAD / SOLIDWORKS ──► 1 s foreground sampler ──► ~60 s intervals ──► on-disk outbox ──► War Room server
   docked tracker palette   active · focused · not idle   per mapped drawing   UUID + exact payload   Design Desk API
        │                                                                                         (actual vs. estimate)
        └── Microsoft sign-in (Entra token) ─────────────────────────────────────────────────────────┘

What I built

1. One tracker, two CAD hosts

  • A WPF tracker UI that runs as a dockable palette in AutoCAD and a task-pane tab in SOLIDWORKS, behind a small IDesignHost interface for active-document, focus and shutdown events.
  • AutoCAD: one codebase builds three version-specific bundles (.NET 8 for 2025/2026, .NET 10 for 2027) and a TIMETRACKER command.
  • SOLIDWORKS: a registered 64-bit COM add-in with a DPI-aware icon set.
  • Shared sign-in, local storage, workbook sync, server contract, outbox and audit log across both hosts.

2. Honest time measurement

  • Foreground sampler: a one-second sampler counts time only when the CAD app is in front, the mapped drawing is the active one, and keyboard or mouse input happened within the idle threshold. Reading a drawing without touching it past the threshold doesn't count.
  • Drawing switches: time on another drawing is never billed to the selected job, and capture resumes automatically when the mapped drawing comes back.
  • No inferred time: a blocked callback, sleep or clock rollback longer than 2.5 seconds adds nothing.
  • Crash recovery: a heartbeat lets the next launch recover the end time after a crash or forced kill, without counting the time CAD was closed. At worst the current unclosed window (under 60 seconds) is lost.

3. Choosing the job

  • The design picker searches the War Room catalog by project, part, quote, customer or design ID, with multi-keyword search and a live result count.
  • Recently used designs float to the top, but nothing is ever auto-selected. Saved drawing-to-design mappings must be confirmed on each start, including offline starts.
  • The selected design names the time entry, so there's no free-text project field to mistype.

4. Reliable delivery to the War Room server

  • Disk before network: each closed interval gets a UUID, and its exact serialized payload is flushed to disk before the first POST. Retries reuse both across restarts.
  • Exactly-once: an entry leaves the outbox only on HTTP 200/201 with a matching UUID back. Duplicate acknowledgements are recorded, not double-counted.
  • Error handling: network failures, timeouts, 401, 403 and 5xx back off and retry; 400, 404 and 409 stop and show up under Review design uploads with the server's Problem Details message.
  • Audit log: a JSONL file records the exact payload before every POST and every acknowledgement or rejection.
  • Isolation: separate outboxes per server endpoint, a local lock so only one CAD process owns a store, and corrupt outboxes surfaced rather than overwritten.

5. Microsoft single sign-on

  • Client: MSAL sign-in against Entra ID, with the token cache encrypted for the Windows user. The add-in sends a bearer token for the War Room API scope and asks the server "who am I?" instead of showing a name picker.
  • Server spec: I wrote the server-side change the add-in depends on: token validation for v1 and v2 issuers, mapping the caller to their Plex designer by object ID and then by UPN or email, and a feature flag to retire the old anonymous LAN endpoint once every workstation is upgraded.
  • No Plex credentials or API keys ever live on the client.

6. Legacy workbook and install

  • The original Excel time log (ClosedXML) still works and syncs to a shared OneDrive workbook, with an offline indicator and startup aggregation.
  • Installers put the AutoCAD bundles in Autodesk's trusted machine-wide plug-in folder and register the SOLIDWORKS add-in. Setup offers to close a running CAD session. The build checks that every bundle has a sign-in client ID and that the server's catalog endpoint answers.

Testing

  • Contract harness: 64 deterministic assertions with no CAD and no server. It covers disk-before-send, interval math, UTC and whole-second serialization, lost-response retries, restart recovery, every error class, overlap rejection, idle and foreground sampling, suspend and clock rollback, lock ownership and corrupt-outbox handling.
  • Isolated-server script: runs against a loopback-only test instance of the War Room API. It posts one synthetic interval and checks duplicate handling, totals, 400/404/409 errors and estimate versioning.
  • Builds: all three AutoCAD versions compile with zero errors.

Status

  • Built: the AutoCAD and SOLIDWORKS add-ins, sampler, outbox, SSO client, installers and contract tests. Read-only calls against the production catalog return the expected jobs and designers.
  • Pending: the server-side SSO change, a run of the isolated-server script against a live test instance, and hands-on acceptance in AutoCAD (drawing switches, idle, shutdown and restart).
  • History: began in July 2025 as a standalone WPF + Excel time log; rebuilt as CAD add-ins with server integration in 2026.