You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit fecb556
Browse filesBrowse the repository at this point in the historyBrowse files
fix(training): defer completion email and share canonical training IDs (#3529)
* fix(training): defer completion email and share canonical training IDs
The portal's complete-training route awaited the completion-certificate
email before responding. That API call resolves the member, renders a PDF
and calls the email provider, so every final-video completion made the
employee wait seconds for work whose outcome they never see — and Node's
fetch has no default request timeout, so an unreachable API could stall
the response for minutes even though the completion was already durable.
Defer it with `after` so it runs once the response is sent, and bound the
request with an AbortSignal timeout so a hung API can't pin the
invocation open. The email path performs no DB or storage writes, only an
in-memory PDF render and a send, so nothing the UI reads afterwards
depends on it having finished.
The route also restated the valid-video-ID list and the HIPAA eligibility
rule that apps/api owns, a fifth copy of constants already duplicated
across both apps and two API modules. Move them to @trycompai/company —
the existing shared-definitions package for api/app/portal — so the two
completion paths cannot disagree about which videos exist or which orgs
may complete HIPAA training.
The two apps' training data files link to the canonical IDs by type only.
They are imported by client components and by a Trigger.dev task, and
@trycompai/company requires @trycompai/db at runtime, so a value
re-export would have pulled Prisma into those bundles. The type-level tie
still fails the build on drift, in both directions: an unknown ID in a
rendered list, or a canonical ID that no longer matches.
Also fixes the pre-existing training-hipaa spec, whose @db mock was never
given frameworkInstance when the HIPAA gate was added, and adds coverage
for the gate's rejection path.
* fix(training): make the canonical/rendered video lists exhaustive both ways
`satisfies readonly CanonicalTrainingVideo[]` only proved that every
rendered video is canonical. The reverse — a canonical ID with no
rendered video — still compiled, and that is the dangerous direction:
completion requires a row for every canonical ID, so adding one without
a matching video would leave employees permanently unable to finish
training.
Key the data by the canonical union instead. `Record<GeneralTrainingVideoId,
...>` is exhaustive by construction, so both drifts now fail the build:
a missing key (TS2741) and an unknown key (TS2353). Verified by
introducing each drift and compiling.
The `Exclude<GeneralTrainingVideoId, (typeof trainingVideos)[number]['id']>`
form would not have worked here — the `readonly TrainingVideo[]`
annotation widens `id` to `string`, so the Exclude resolves to `never`
and the guard passes vacuously.
0 commit comments