back to job discovery pipeline
every save said ok
july 2026 · a dashboard where every save showed success and then reverted on refresh, and the two small bugs behind it.
the dashboard for my job discovery pipeline lets me mark a posting applied, dismissed or saved. every click showed a green success toast. every refresh put the old status back. i spent about six hours on it.
what i thought it was
first the database. supabase was up and answering fine. then the scraper, which runs every 30 minutes and writes new postings: maybe it was overwriting the status column. its upsert was on conflict do nothing, so it never touched a row that already existed. the database was fine, the api looked fine, and the scraper was innocent.
what it was
i stopped trusting the browser and hit the endpoint with curl:
$ curl -s -o /dev/null -w "%{http_code} %{redirect_url}" \
-X PATCH .../api/jobs/123/status \
-d '{"status":"applied"}'
307 .../loginthe api never ran. the dashboard is password protected, and the auth middleware exempted /api/auth but not the rest of /api. every write got a 307 to the login page, the browser followed it, the login page answered 200 with html, and fetch read that 200 as success. the toast was telling the truth about the wrong request. the fix was one line:
- if (pathname.startsWith('/login') || pathname.startsWith('/api/auth'))
+ if (pathname.startsWith('/login') || pathname.startsWith('/api/'))the bug under it
saves worked after that, but the page still showed 7 applied jobs when the table had 10. the page was force-dynamic, but the supabase client's own fetch calls were still landing in next.js's data cache. i replaced the client call with a raw fetch and cache: 'no-store', and the page went live.
what i took from it
test the api without the ui. the browser was following the redirect and hiding the failure, and one curl showed it. when an abstraction behaves strangely, drop a layer: a raw fetch with explicit options is unambiguous. and two small mistakes compounding can look like three different bugs at once.
the same shape came back at seatsnipe's launch: a stale banner session redirected to a login page that answered 200. that one gets a re-login and a retry now.