Session 17: Audit response — checkout 401 fix, hero prop 404 fix, Slate parsing fix, ALL tab cascade isolation, cookie/nav/footer/autocomplete polish (1438 tests)

This commit is contained in:
Kev
2026-06-11 21:22:59 -04:00
parent 73b65a0248
commit beaf8b2a61
14 changed files with 681 additions and 25 deletions
+70 -7
View File
@@ -1,5 +1,28 @@
const { getSupabaseServiceClient } = require('../utils/supabase');
/**
* Session 17 — `requireAuth` was 401'ing legitimate users whose Supabase
* auth account had never had a matching row inserted into the
* `public.users` table. Signup writes to `auth.users` automatically;
* the corresponding row in `public.users` was supposed to land via a
* trigger or a post-signup handler, but for SSO callbacks and any
* legacy account that pre-dated the trigger the row was simply
* missing. The audit found this: checkout 401'd as "User profile not
* found" for valid sessions.
*
* The fix is an on-demand upsert. When the select misses, we insert a
* default row (tier='free') keyed by the Supabase auth user's id +
* email, then re-select. This is idempotent — concurrent requests
* land on the upsert's existing-row branch and re-read the same row.
*
* If the insert ITSELF fails (genuine DB issue, not a missing row),
* we 401 with a distinct message ('User profile creation failed') so
* the operator can distinguish missing-row recovery from real DB
* outages in logs.
*/
const PROFILE_COLUMNS = 'id, email, tier, scan_count, scan_reset_date, founder_status, grace_period_until, stripe_customer_id';
async function requireAuth(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
@@ -14,17 +37,57 @@ async function requireAuth(req, res, next) {
return res.status(401).json({ error: 'Invalid or expired token' });
}
// Fetch user profile from our users table. Session 9 added
// `grace_period_until` + `stripe_customer_id` to the select so the
// grace-period middleware can read them off `req.user` without a
// second round-trip. Both fields default to null when absent so
// pre-Stripe users behave identically to before.
const { data: profile, error: profileError } = await supabase
// First read. PostgREST returns `error.code === 'PGRST116'` when
// `.single()` gets zero rows — that's the signal we use to trigger
// the on-demand upsert below. Other errors (network, permission)
// bubble up as a real 401.
let { data: profile, error: profileError } = await supabase
.from('users')
.select('id, email, tier, scan_count, scan_reset_date, founder_status, grace_period_until, stripe_customer_id')
.select(PROFILE_COLUMNS)
.eq('id', user.id)
.single();
// Session 17 — if no row exists, create one on the fly. The
// `auth.users` row already exists (we just resolved a token against
// it), so we're not creating an identity — we're filling in the
// app-side row that should have been created at signup time but
// wasn't (SSO callbacks, legacy accounts pre-trigger, etc.).
// Detect PostgREST's "single requested, zero rows returned" via
// either the canonical error code (preferred) or the message
// pattern Supabase emits when the code field is stripped by an
// older client. Canonical message:
// "JSON object requested, multiple (or no) rows returned"
const isMissingRow = profileError && (
profileError.code === 'PGRST116'
|| /\(or no\) rows/i.test(profileError.message || '')
|| /^no rows$/i.test(profileError.message || '')
);
if (!profile && isMissingRow) {
const defaultRow = {
id: user.id,
email: user.email || null,
tier: 'free',
scan_count: 0,
scan_reset_date: new Date().toISOString().slice(0, 10),
founder_status: false,
};
const { error: upsertErr } = await supabase
.from('users')
.upsert(defaultRow, { onConflict: 'id' });
if (upsertErr) {
console.warn('[requireAuth] users-row upsert failed:', upsertErr.message);
return res.status(401).json({ error: 'User profile creation failed' });
}
// Re-select. Use the same .single() shape so test mocks keep working.
const reread = await supabase
.from('users')
.select(PROFILE_COLUMNS)
.eq('id', user.id)
.single();
profile = reread.data;
profileError = reread.error;
}
if (profileError || !profile) {
return res.status(401).json({ error: 'User profile not found' });
}