Skip to content

feat: add import run notifications - #120

Merged
HarryRandall merged 2 commits into
mainfrom
feat/import-run-notifications
Sep 22, 2026
Merged

HarryRandall merged 2 commits into
mainfrom
feat/import-run-notifications

Conversation

@HarryRandall

Copy link
Copy Markdown
Owner

Summary

This is stack 5 of 16. It contains the focused commits between feat/year-picker-select and feat/import-run-notifications and targets the branch immediately below it.

Verification

  • GitHub Quality gate
  • GitHub Route gate
  • GitHub Database gate
  • GitHub Browser gate

Deployment notes

Do not deploy this branch independently. Merge the stack from the bottom upwards. The one-time hosted database rebuild remains a separate approved operation after the complete stack reaches main.

@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
coursemap Ready Ready Preview Sep 22, 2026 1:03pm UTC

A run could take twenty minutes and the only way to learn how it ended
was to sit on the imports page and watch. This adds an own-row inbox and
hangs the first producer off the one write every ending shares.

Four paths end a run, two of them SQL with no application code to hook,
so the producer is a trigger on the run row rather than a call in the
worker: private.refresh_catalogue_import_run() is the sole writer of
catalogue_import_runs.status, so a trigger there catches the worker
finishing, a cancellation, a released target and the stale-lease sweep
without each caller having to remember. The dedupe key means a run that
leaves and re-enters a terminal status is still reported once.

The table is gated on identity, not on a permission. The catalogue write
hole came from a helper that accepted a read permission every sign-up
holds, so there is no permission to get wrong here: authenticated gets
select and nothing else, the only reader of a row is the user named on
it, and both the producer and the read marker are definer routines no
client role can call or aim at somebody else.
The notifications menu shipped with a hard-coded sampleNotifications
array, so the badge was decoration and reading a row did nothing. It now
reads the signed-in user's rows, marks them read through the database
function that scopes the update to the caller, and says so when it
cannot.

An empty inbox is what most people have most of the time, so it gets the
finished treatment rather than the broken one: no retry, no warning
colour and nothing for the reader to do. The failure state is the only
one that offers another attempt.

Rows group by age, not by read state, because grouping on read state
would make a row jump to another heading the instant it was read and
lose the reader's place. Marking read is optimistic and a failed write
is corrected by the next read rather than by an error the reader can do
nothing about.

Reading goes through getAuthViewer(), so a signed-out visitor and a
deployment with no Supabase configured both get an empty inbox rather
than a thrown configuration error: the bell sits in the shell on every
page and has to stay quiet where there is nobody to notify.
@HarryRandall
HarryRandall force-pushed the feat/year-picker-select branch from 063733d to 4d53aa8 Compare September 22, 2026 12:25
@HarryRandall
HarryRandall force-pushed the feat/import-run-notifications branch from 07f0f16 to 218ec37 Compare September 22, 2026 12:25
Base automatically changed from feat/year-picker-select to main September 22, 2026 12:38
@HarryRandall
HarryRandall merged commit 218ec37 into main Sep 22, 2026
4 of 6 checks passed
@HarryRandall
HarryRandall deleted the feat/import-run-notifications branch September 22, 2026 12:39

This branch was successfully deployed

1 active deployment
Preview 218ec37f Deployed Sep 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant